/..

#CONTENT

#TOP

gef.py
PYTHON
    1 
 
2
 
3
 
4
 
5
 
6
 
7
 
8
 
9
 
10
 
11
 
12
 
13
 
14
 
15
 
16
 
17
 
18
 
19
 
20
 
21
 
22
 
23
 
24
 
25
 
26
 
27
 
28
 
29
 
30
 
31
 
32
 
33
 
34
 
35
 
36
 
37
 
38
 
39
 
40
 
41
 
42
 
43
 
44
 
45
 
46
 
47
 
48
 
49
 
50
 
51
 
52
 
53
 
54
 
55
 
56
 
57
 
58
 
59
 
60
 
61
 
62
 
63
 
64
 
65
 
66
 
67
 
68
 
69
 
70
 
71
 
72
 
73
 
74
 
75
 
76
 
77
 
78
 
79
 
80
 
81
 
82
 
83
 
84
 
85
 
86
 
87
 
88
 
89
 
90
 
91
 
92
 
93
 
94
 
95
 
96
 
97
 
98
 
99
 
100
 
101
 
102
 
103
 
104
 
105
 
106
 
107
 
108
 
109
 
110
 
111
 
112
 
113
 
114
 
115
 
116
 
117
 
118
 
119
 
120
 
121
 
122
 
123
 
124
 
125
 
126
 
127
 
128
 
129
 
130
 
131
 
132
 
133
 
134
 
135
 
136
 
137
 
138
 
139
 
140
 
141
 
142
 
143
 
144
 
145
 
146
 
147
 
148
 
149
 
150
 
151
 
152
 
153
 
154
 
155
 
156
 
157
 
158
 
159
 
160
 
161
 
162
 
163
 
164
 
165
 
166
 
167
 
168
 
169
 
170
 
171
 
172
 
173
 
174
 
175
 
176
 
177
 
178
 
179
 
180
 
181
 
182
 
183
 
184
 
185
 
186
 
187
 
188
 
189
 
190
 
191
 
192
 
193
 
194
 
195
 
196
 
197
 
198
 
199
 
200
 
201
 
202
 
203
 
204
 
205
 
206
 
207
 
208
 
209
 
210
 
211
 
212
 
213
 
214
 
215
 
216
 
217
 
218
 
219
 
220
 
221
 
222
 
223
 
224
 
225
 
226
 
227
 
228
 
229
 
230
 
231
 
232
 
233
 
234
 
235
 
236
 
237
 
238
 
239
 
240
 
241
 
242
 
243
 
244
 
245
 
246
 
247
 
248
 
249
 
250
 
251
 
252
 
253
 
254
 
255
 
256
 
257
 
258
 
259
 
260
 
261
 
262
 
263
 
264
 
265
 
266
 
267
 
268
 
269
 
270
 
271
 
272
 
273
 
274
 
275
 
276
 
277
 
278
 
279
 
280
 
281
 
282
 
283
 
284
 
285
 
286
 
287
 
288
 
289
 
290
 
291
 
292
 
293
 
294
 
295
 
296
 
297
 
298
 
299
 
300
 
301
 
302
 
303
 
304
 
305
 
306
 
307
 
308
 
309
 
310
 
311
 
312
 
313
 
314
 
315
 
316
 
317
 
318
 
319
 
320
 
321
 
322
 
323
 
324
 
325
 
326
 
327
 
328
 
329
 
330
 
331
 
332
 
333
 
334
 
335
 
336
 
337
 
338
 
339
 
340
 
341
 
342
 
343
 
344
 
345
 
346
 
347
 
348
 
349
 
350
 
351
 
352
 
353
 
354
 
355
 
356
 
357
 
358
 
359
 
360
 
361
 
362
 
363
 
364
 
365
 
366
 
367
 
368
 
369
 
370
 
371
 
372
 
373
 
374
 
375
 
376
 
377
 
378
 
379
 
380
 
381
 
382
 
383
 
384
 
385
 
386
 
387
 
388
 
389
 
390
 
391
 
392
 
393
 
394
 
395
 
396
 
397
 
398
 
399
 
400
 
401
 
402
 
403
 
404
 
405
 
406
 
407
 
408
 
409
 
410
 
411
 
412
 
413
 
414
 
415
 
416
 
417
 
418
 
419
 
420
 
421
 
422
 
423
 
424
 
425
 
426
 
427
 
428
 
429
 
430
 
431
 
432
 
433
 
434
 
435
 
436
 
437
 
438
 
439
 
440
 
441
 
442
 
443
 
444
 
445
 
446
 
447
 
448
 
449
 
450
 
451
 
452
 
453
 
454
 
455
 
456
 
457
 
458
 
459
 
460
 
461
 
462
 
463
 
464
 
465
 
466
 
467
 
468
 
469
 
470
 
471
 
472
 
473
 
474
 
475
 
476
 
477
 
478
 
479
 
480
 
481
 
482
 
483
 
484
 
485
 
486
 
487
 
488
 
489
 
490
 
491
 
492
 
493
 
494
 
495
 
496
 
497
 
498
 
499
 
500
 
501
 
502
 
503
 
504
 
505
 
506
 
507
 
508
 
509
 
510
 
511
 
512
 
513
 
514
 
515
 
516
 
517
 
518
 
519
 
520
 
521
 
522
 
523
 
524
 
525
 
526
 
527
 
528
 
529
 
530
 
531
 
532
 
533
 
534
 
535
 
536
 
537
 
538
 
539
 
540
 
541
 
542
 
543
 
544
 
545
 
546
 
547
 
548
 
549
 
550
 
551
 
552
 
553
 
554
 
555
 
556
 
557
 
558
 
559
 
560
 
561
 
562
 
563
 
564
 
565
 
566
 
567
 
568
 
569
 
570
 
571
 
572
 
573
 
574
 
575
 
576
 
577
 
578
 
579
 
580
 
581
 
582
 
583
 
584
 
585
 
586
 
587
 
588
 
589
 
590
 
591
 
592
 
593
 
594
 
595
 
596
 
597
 
598
 
599
 
600
 
601
 
602
 
603
 
604
 
605
 
606
 
607
 
608
 
609
 
610
 
611
 
612
 
613
 
614
 
615
 
616
 
617
 
618
 
619
 
620
 
621
 
622
 
623
 
624
 
625
 
626
 
627
 
628
 
629
 
630
 
631
 
632
 
633
 
634
 
635
 
636
 
637
 
638
 
639
 
640
 
641
 
642
 
643
 
644
 
645
 
646
 
647
 
648
 
649
 
650
 
651
 
652
 
653
 
654
 
655
 
656
 
657
 
658
 
659
 
660
 
661
 
662
 
663
 
664
 
665
 
666
 
667
 
668
 
669
 
670
 
671
 
672
 
673
 
674
 
675
 
676
 
677
 
678
 
679
 
680
 
681
 
682
 
683
 
684
 
685
 
686
 
687
 
688
 
689
 
690
 
691
 
692
 
693
 
694
 
695
 
696
 
697
 
698
 
699
 
700
 
701
 
702
 
703
 
704
 
705
 
706
 
707
 
708
 
709
 
710
 
711
 
712
 
713
 
714
 
715
 
716
 
717
 
718
 
719
 
720
 
721
 
722
 
723
 
724
 
725
 
726
 
727
 
728
 
729
 
730
 
731
 
732
 
733
 
734
 
735
 
736
 
737
 
738
 
739
 
740
 
741
 
742
 
743
 
744
 
745
 
746
 
747
 
748
 
749
 
750
 
751
 
752
 
753
 
754
 
755
 
756
 
757
 
758
 
759
 
760
 
761
 
762
 
763
 
764
 
765
 
766
 
767
 
768
 
769
 
770
 
771
 
772
 
773
 
774
 
775
 
776
 
777
 
778
 
779
 
780
 
781
 
782
 
783
 
784
 
785
 
786
 
787
 
788
 
789
 
790
 
791
 
792
 
793
 
794
 
795
 
796
 
797
 
798
 
799
 
800
 
801
 
802
 
803
 
804
 
805
 
806
 
807
 
808
 
809
 
810
 
811
 
812
 
813
 
814
 
815
 
816
 
817
 
818
 
819
 
820
 
821
 
822
 
823
 
824
 
825
 
826
 
827
 
828
 
829
 
830
 
831
 
832
 
833
 
834
 
835
 
836
 
837
 
838
 
839
 
840
 
841
 
842
 
843
 
844
 
845
 
846
 
847
 
848
 
849
 
850
 
851
 
852
 
853
 
854
 
855
 
856
 
857
 
858
 
859
 
860
 
861
 
862
 
863
 
864
 
865
 
866
 
867
 
868
 
869
 
870
 
871
 
872
 
873
 
874
 
875
 
876
 
877
 
878
 
879
 
880
 
881
 
882
 
883
 
884
 
885
 
886
 
887
 
888
 
889
 
890
 
891
 
892
 
893
 
894
 
895
 
896
 
897
 
898
 
899
 
900
 
901
 
902
 
903
 
904
 
905
 
906
 
907
 
908
 
909
 
910
 
911
 
912
 
913
 
914
 
915
 
916
 
917
 
918
 
919
 
920
 
921
 
922
 
923
 
924
 
925
 
926
 
927
 
928
 
929
 
930
 
931
 
932
 
933
 
934
 
935
 
936
 
937
 
938
 
939
 
940
 
941
 
942
 
943
 
944
 
945
 
946
 
947
 
948
 
949
 
950
 
951
 
952
 
953
 
954
 
955
 
956
 
957
 
958
 
959
 
960
 
961
 
962
 
963
 
964
 
965
 
966
 
967
 
968
 
969
 
970
 
971
 
972
 
973
 
974
 
975
 
976
 
977
 
978
 
979
 
980
 
981
 
982
 
983
 
984
 
985
 
986
 
987
 
988
 
989
 
990
 
991
 
992
 
993
 
994
 
995
 
996
 
997
 
998
 
999
 
1000
 
1001
 
1002
 
1003
 
1004
 
1005
 
1006
 
1007
 
1008
 
1009
 
1010
 
1011
 
1012
 
1013
 
1014
 
1015
 
1016
 
1017
 
1018
 
1019
 
1020
 
1021
 
1022
 
1023
 
1024
 
1025
 
1026
 
1027
 
1028
 
1029
 
1030
 
1031
 
1032
 
1033
 
1034
 
1035
 
1036
 
1037
 
1038
 
1039
 
1040
 
1041
 
1042
 
1043
 
1044
 
1045
 
1046
 
1047
 
1048
 
1049
 
1050
 
1051
 
1052
 
1053
 
1054
 
1055
 
1056
 
1057
 
1058
 
1059
 
1060
 
1061
 
1062
 
1063
 
1064
 
1065
 
1066
 
1067
 
1068
 
1069
 
1070
 
1071
 
1072
 
1073
 
1074
 
1075
 
1076
 
1077
 
1078
 
1079
 
1080
 
1081
 
1082
 
1083
 
1084
 
1085
 
1086
 
1087
 
1088
 
1089
 
1090
 
1091
 
1092
 
1093
 
1094
 
1095
 
1096
 
1097
 
1098
 
1099
 
1100
 
1101
 
1102
 
1103
 
1104
 
1105
 
1106
 
1107
 
1108
 
1109
 
1110
 
1111
 
1112
 
1113
 
1114
 
1115
 
1116
 
1117
 
1118
 
1119
 
1120
 
1121
 
1122
 
1123
 
1124
 
1125
 
1126
 
1127
 
1128
 
1129
 
1130
 
1131
 
1132
 
1133
 
1134
 
1135
 
1136
 
1137
 
1138
 
1139
 
1140
 
1141
 
1142
 
1143
 
1144
 
1145
 
1146
 
1147
 
1148
 
1149
 
1150
 
1151
 
1152
 
1153
 
1154
 
1155
 
1156
 
1157
 
1158
 
1159
 
1160
 
1161
 
1162
 
1163
 
1164
 
1165
 
1166
 
1167
 
1168
 
1169
 
1170
 
1171
 
1172
 
1173
 
1174
 
1175
 
1176
 
1177
 
1178
 
1179
 
1180
 
1181
 
1182
 
1183
 
1184
 
1185
 
1186
 
1187
 
1188
 
1189
 
1190
 
1191
 
1192
 
1193
 
1194
 
1195
 
1196
 
1197
 
1198
 
1199
 
1200
 
1201
 
1202
 
1203
 
1204
 
1205
 
1206
 
1207
 
1208
 
1209
 
1210
 
1211
 
1212
 
1213
 
1214
 
1215
 
1216
 
1217
 
1218
 
1219
 
1220
 
1221
 
1222
 
1223
 
1224
 
1225
 
1226
 
1227
 
1228
 
1229
 
1230
 
1231
 
1232
 
1233
 
1234
 
1235
 
1236
 
1237
 
1238
 
1239
 
1240
 
1241
 
1242
 
1243
 
1244
 
1245
 
1246
 
1247
 
1248
 
1249
 
1250
 
1251
 
1252
 
1253
 
1254
 
1255
 
1256
 
1257
 
1258
 
1259
 
1260
 
1261
 
1262
 
1263
 
1264
 
1265
 
1266
 
1267
 
1268
 
1269
 
1270
 
1271
 
1272
 
1273
 
1274
 
1275
 
1276
 
1277
 
1278
 
1279
 
1280
 
1281
 
1282
 
1283
 
1284
 
1285
 
1286
 
1287
 
1288
 
1289
 
1290
 
1291
 
1292
 
1293
 
1294
 
1295
 
1296
 
1297
 
1298
 
1299
 
1300
 
1301
 
1302
 
1303
 
1304
 
1305
 
1306
 
1307
 
1308
 
1309
 
1310
 
1311
 
1312
 
1313
 
1314
 
1315
 
1316
 
1317
 
1318
 
1319
 
1320
 
1321
 
1322
 
1323
 
1324
 
1325
 
1326
 
1327
 
1328
 
1329
 
1330
 
1331
 
1332
 
1333
 
1334
 
1335
 
1336
 
1337
 
1338
 
1339
 
1340
 
1341
 
1342
 
1343
 
1344
 
1345
 
1346
 
1347
 
1348
 
1349
 
1350
 
1351
 
1352
 
1353
 
1354
 
1355
 
1356
 
1357
 
1358
 
1359
 
1360
 
1361
 
1362
 
1363
 
1364
 
1365
 
1366
 
1367
 
1368
 
1369
 
1370
 
1371
 
1372
 
1373
 
1374
 
1375
 
1376
 
1377
 
1378
 
1379
 
1380
 
1381
 
1382
 
1383
 
1384
 
1385
 
1386
 
1387
 
1388
 
1389
 
1390
 
1391
 
1392
 
1393
 
1394
 
1395
 
1396
 
1397
 
1398
 
1399
 
1400
 
1401
 
1402
 
1403
 
1404
 
1405
 
1406
 
1407
 
1408
 
1409
 
1410
 
1411
 
1412
 
1413
 
1414
 
1415
 
1416
 
1417
 
1418
 
1419
 
1420
 
1421
 
1422
 
1423
 
1424
 
1425
 
1426
 
1427
 
1428
 
1429
 
1430
 
1431
 
1432
 
1433
 
1434
 
1435
 
1436
 
1437
 
1438
 
1439
 
1440
 
1441
 
1442
 
1443
 
1444
 
1445
 
1446
 
1447
 
1448
 
1449
 
1450
 
1451
 
1452
 
1453
 
1454
 
1455
 
1456
 
1457
 
1458
 
1459
 
1460
 
1461
 
1462
 
1463
 
1464
 
1465
 
1466
 
1467
 
1468
 
1469
 
1470
 
1471
 
1472
 
1473
 
1474
 
1475
 
1476
 
1477
 
1478
 
1479
 
1480
 
1481
 
1482
 
1483
 
1484
 
1485
 
1486
 
1487
 
1488
 
1489
 
1490
 
1491
 
1492
 
1493
 
1494
 
1495
 
1496
 
1497
 
1498
 
1499
 
1500
 
1501
 
1502
 
1503
 
1504
 
1505
 
1506
 
1507
 
1508
 
1509
 
1510
 
1511
 
1512
 
1513
 
1514
 
1515
 
1516
 
1517
 
1518
 
1519
 
1520
 
1521
 
1522
 
1523
 
1524
 
1525
 
1526
 
1527
 
1528
 
1529
 
1530
 
1531
 
1532
 
1533
 
1534
 
1535
 
1536
 
1537
 
1538
 
1539
 
1540
 
1541
 
1542
 
1543
 
1544
 
1545
 
1546
 
1547
 
1548
 
1549
 
1550
 
1551
 
1552
 
1553
 
1554
 
1555
 
1556
 
1557
 
1558
 
1559
 
1560
 
1561
 
1562
 
1563
 
1564
 
1565
 
1566
 
1567
 
1568
 
1569
 
1570
 
1571
 
1572
 
1573
 
1574
 
1575
 
1576
 
1577
 
1578
 
1579
 
1580
 
1581
 
1582
 
1583
 
1584
 
1585
 
1586
 
1587
 
1588
 
1589
 
1590
 
1591
 
1592
 
1593
 
1594
 
1595
 
1596
 
1597
 
1598
 
1599
 
1600
 
1601
 
1602
 
1603
 
1604
 
1605
 
1606
 
1607
 
1608
 
1609
 
1610
 
1611
 
1612
 
1613
 
1614
 
1615
 
1616
 
1617
 
1618
 
1619
 
1620
 
1621
 
1622
 
1623
 
1624
 
1625
 
1626
 
1627
 
1628
 
1629
 
1630
 
1631
 
1632
 
1633
 
1634
 
1635
 
1636
 
1637
 
1638
 
1639
 
1640
 
1641
 
1642
 
1643
 
1644
 
1645
 
1646
 
1647
 
1648
 
1649
 
1650
 
1651
 
1652
 
1653
 
1654
 
1655
 
1656
 
1657
 
1658
 
1659
 
1660
 
1661
 
1662
 
1663
 
1664
 
1665
 
1666
 
1667
 
1668
 
1669
 
1670
 
1671
 
1672
 
1673
 
1674
 
1675
 
1676
 
1677
 
1678
 
1679
 
1680
 
1681
 
1682
 
1683
 
1684
 
1685
 
1686
 
1687
 
1688
 
1689
 
1690
 
1691
 
1692
 
1693
 
1694
 
1695
 
1696
 
1697
 
1698
 
1699
 
1700
 
1701
 
1702
 
1703
 
1704
 
1705
 
1706
 
1707
 
1708
 
1709
 
1710
 
1711
 
1712
 
1713
 
1714
 
1715
 
1716
 
1717
 
1718
 
1719
 
1720
 
1721
 
1722
 
1723
 
1724
 
1725
 
1726
 
1727
 
1728
 
1729
 
1730
 
1731
 
1732
 
1733
 
1734
 
1735
 
1736
 
1737
 
1738
 
1739
 
1740
 
1741
 
1742
 
1743
 
1744
 
1745
 
1746
 
1747
 
1748
 
1749
 
1750
 
1751
 
1752
 
1753
 
1754
 
1755
 
1756
 
1757
 
1758
 
1759
 
1760
 
1761
 
1762
 
1763
 
1764
 
1765
 
1766
 
1767
 
1768
 
1769
 
1770
 
1771
 
1772
 
1773
 
1774
 
1775
 
1776
 
1777
 
1778
 
1779
 
1780
 
1781
 
1782
 
1783
 
1784
 
1785
 
1786
 
1787
 
1788
 
1789
 
1790
 
1791
 
1792
 
1793
 
1794
 
1795
 
1796
 
1797
 
1798
 
1799
 
1800
 
1801
 
1802
 
1803
 
1804
 
1805
 
1806
 
1807
 
1808
 
1809
 
1810
 
1811
 
1812
 
1813
 
1814
 
1815
 
1816
 
1817
 
1818
 
1819
 
1820
 
1821
 
1822
 
1823
 
1824
 
1825
 
1826
 
1827
 
1828
 
1829
 
1830
 
1831
 
1832
 
1833
 
1834
 
1835
 
1836
 
1837
 
1838
 
1839
 
1840
 
1841
 
1842
 
1843
 
1844
 
1845
 
1846
 
1847
 
1848
 
1849
 
1850
 
1851
 
1852
 
1853
 
1854
 
1855
 
1856
 
1857
 
1858
 
1859
 
1860
 
1861
 
1862
 
1863
 
1864
 
1865
 
1866
 
1867
 
1868
 
1869
 
1870
 
1871
 
1872
 
1873
 
1874
 
1875
 
1876
 
1877
 
1878
 
1879
 
1880
 
1881
 
1882
 
1883
 
1884
 
1885
 
1886
 
1887
 
1888
 
1889
 
1890
 
1891
 
1892
 
1893
 
1894
 
1895
 
1896
 
1897
 
1898
 
1899
 
1900
 
1901
 
1902
 
1903
 
1904
 
1905
 
1906
 
1907
 
1908
 
1909
 
1910
 
1911
 
1912
 
1913
 
1914
 
1915
 
1916
 
1917
 
1918
 
1919
 
1920
 
1921
 
1922
 
1923
 
1924
 
1925
 
1926
 
1927
 
1928
 
1929
 
1930
 
1931
 
1932
 
1933
 
1934
 
1935
 
1936
 
1937
 
1938
 
1939
 
1940
 
1941
 
1942
 
1943
 
1944
 
1945
 
1946
 
1947
 
1948
 
1949
 
1950
 
1951
 
1952
 
1953
 
1954
 
1955
 
1956
 
1957
 
1958
 
1959
 
1960
 
1961
 
1962
 
1963
 
1964
 
1965
 
1966
 
1967
 
1968
 
1969
 
1970
 
1971
 
1972
 
1973
 
1974
 
1975
 
1976
 
1977
 
1978
 
1979
 
1980
 
1981
 
1982
 
1983
 
1984
 
1985
 
1986
 
1987
 
1988
 
1989
 
1990
 
1991
 
1992
 
1993
 
1994
 
1995
 
1996
 
1997
 
1998
 
1999
 
2000
 
2001
 
2002
 
2003
 
2004
 
2005
 
2006
 
2007
 
2008
 
2009
 
2010
 
2011
 
2012
 
2013
 
2014
 
2015
 
2016
 
2017
 
2018
 
2019
 
2020
 
2021
 
2022
 
2023
 
2024
 
2025
 
2026
 
2027
 
2028
 
2029
 
2030
 
2031
 
2032
 
2033
 
2034
 
2035
 
2036
 
2037
 
2038
 
2039
 
2040
 
2041
 
2042
 
2043
 
2044
 
2045
 
2046
 
2047
 
2048
 
2049
 
2050
 
2051
 
2052
 
2053
 
2054
 
2055
 
2056
 
2057
 
2058
 
2059
 
2060
 
2061
 
2062
 
2063
 
2064
 
2065
 
2066
 
2067
 
2068
 
2069
 
2070
 
2071
 
2072
 
2073
 
2074
 
2075
 
2076
 
2077
 
2078
 
2079
 
2080
 
2081
 
2082
 
2083
 
2084
 
2085
 
2086
 
2087
 
2088
 
2089
 
2090
 
2091
 
2092
 
2093
 
2094
 
2095
 
2096
 
2097
 
2098
 
2099
 
2100
 
2101
 
2102
 
2103
 
2104
 
2105
 
2106
 
2107
 
2108
 
2109
 
2110
 
2111
 
2112
 
2113
 
2114
 
2115
 
2116
 
2117
 
2118
 
2119
 
2120
 
2121
 
2122
 
2123
 
2124
 
2125
 
2126
 
2127
 
2128
 
2129
 
2130
 
2131
 
2132
 
2133
 
2134
 
2135
 
2136
 
2137
 
2138
 
2139
 
2140
 
2141
 
2142
 
2143
 
2144
 
2145
 
2146
 
2147
 
2148
 
2149
 
2150
 
2151
 
2152
 
2153
 
2154
 
2155
 
2156
 
2157
 
2158
 
2159
 
2160
 
2161
 
2162
 
2163
 
2164
 
2165
 
2166
 
2167
 
2168
 
2169
 
2170
 
2171
 
2172
 
2173
 
2174
 
2175
 
2176
 
2177
 
2178
 
2179
 
2180
 
2181
 
2182
 
2183
 
2184
 
2185
 
2186
 
2187
 
2188
 
2189
 
2190
 
2191
 
2192
 
2193
 
2194
 
2195
 
2196
 
2197
 
2198
 
2199
 
2200
 
2201
 
2202
 
2203
 
2204
 
2205
 
2206
 
2207
 
2208
 
2209
 
2210
 
2211
 
2212
 
2213
 
2214
 
2215
 
2216
 
2217
 
2218
 
2219
 
2220
 
2221
 
2222
 
2223
 
2224
 
2225
 
2226
 
2227
 
2228
 
2229
 
2230
 
2231
 
2232
 
2233
 
2234
 
2235
 
2236
 
2237
 
2238
 
2239
 
2240
 
2241
 
2242
 
2243
 
2244
 
2245
 
2246
 
2247
 
2248
 
2249
 
2250
 
2251
 
2252
 
2253
 
2254
 
2255
 
2256
 
2257
 
2258
 
2259
 
2260
 
2261
 
2262
 
2263
 
2264
 
2265
 
2266
 
2267
 
2268
 
2269
 
2270
 
2271
 
2272
 
2273
 
2274
 
2275
 
2276
 
2277
 
2278
 
2279
 
2280
 
2281
 
2282
 
2283
 
2284
 
2285
 
2286
 
2287
 
2288
 
2289
 
2290
 
2291
 
2292
 
2293
 
2294
 
2295
 
2296
 
2297
 
2298
 
2299
 
2300
 
2301
 
2302
 
2303
 
2304
 
2305
 
2306
 
2307
 
2308
 
2309
 
2310
 
2311
 
2312
 
2313
 
2314
 
2315
 
2316
 
2317
 
2318
 
2319
 
2320
 
2321
 
2322
 
2323
 
2324
 
2325
 
2326
 
2327
 
2328
 
2329
 
2330
 
2331
 
2332
 
2333
 
2334
 
2335
 
2336
 
2337
 
2338
 
2339
 
2340
 
2341
 
2342
 
2343
 
2344
 
2345
 
2346
 
2347
 
2348
 
2349
 
2350
 
2351
 
2352
 
2353
 
2354
 
2355
 
2356
 
2357
 
2358
 
2359
 
2360
 
2361
 
2362
 
2363
 
2364
 
2365
 
2366
 
2367
 
2368
 
2369
 
2370
 
2371
 
2372
 
2373
 
2374
 
2375
 
2376
 
2377
 
2378
 
2379
 
2380
 
2381
 
2382
 
2383
 
2384
 
2385
 
2386
 
2387
 
2388
 
2389
 
2390
 
2391
 
2392
 
2393
 
2394
 
2395
 
2396
 
2397
 
2398
 
2399
 
2400
 
2401
 
2402
 
2403
 
2404
 
2405
 
2406
 
2407
 
2408
 
2409
 
2410
 
2411
 
2412
 
2413
 
2414
 
2415
 
2416
 
2417
 
2418
 
2419
 
2420
 
2421
 
2422
 
2423
 
2424
 
2425
 
2426
 
2427
 
2428
 
2429
 
2430
 
2431
 
2432
 
2433
 
2434
 
2435
 
2436
 
2437
 
2438
 
2439
 
2440
 
2441
 
2442
 
2443
 
2444
 
2445
 
2446
 
2447
 
2448
 
2449
 
2450
 
2451
 
2452
 
2453
 
2454
 
2455
 
2456
 
2457
 
2458
 
2459
 
2460
 
2461
 
2462
 
2463
 
2464
 
2465
 
2466
 
2467
 
2468
 
2469
 
2470
 
2471
 
2472
 
2473
 
2474
 
2475
 
2476
 
2477
 
2478
 
2479
 
2480
 
2481
 
2482
 
2483
 
2484
 
2485
 
2486
 
2487
 
2488
 
2489
 
2490
 
2491
 
2492
 
2493
 
2494
 
2495
 
2496
 
2497
 
2498
 
2499
 
2500
 
2501
 
2502
 
2503
 
2504
 
2505
 
2506
 
2507
 
2508
 
2509
 
2510
 
2511
 
2512
 
2513
 
2514
 
2515
 
2516
 
2517
 
2518
 
2519
 
2520
 
2521
 
2522
 
2523
 
2524
 
2525
 
2526
 
2527
 
2528
 
2529
 
2530
 
2531
 
2532
 
2533
 
2534
 
2535
 
2536
 
2537
 
2538
 
2539
 
2540
 
2541
 
2542
 
2543
 
2544
 
2545
 
2546
 
2547
 
2548
 
2549
 
2550
 
2551
 
2552
 
2553
 
2554
 
2555
 
2556
 
2557
 
2558
 
2559
 
2560
 
2561
 
2562
 
2563
 
2564
 
2565
 
2566
 
2567
 
2568
 
2569
 
2570
 
2571
 
2572
 
2573
 
2574
 
2575
 
2576
 
2577
 
2578
 
2579
 
2580
 
2581
 
2582
 
2583
 
2584
 
2585
 
2586
 
2587
 
2588
 
2589
 
2590
 
2591
 
2592
 
2593
 
2594
 
2595
 
2596
 
2597
 
2598
 
2599
 
2600
 
2601
 
2602
 
2603
 
2604
 
2605
 
2606
 
2607
 
2608
 
2609
 
2610
 
2611
 
2612
 
2613
 
2614
 
2615
 
2616
 
2617
 
2618
 
2619
 
2620
 
2621
 
2622
 
2623
 
2624
 
2625
 
2626
 
2627
 
2628
 
2629
 
2630
 
2631
 
2632
 
2633
 
2634
 
2635
 
2636
 
2637
 
2638
 
2639
 
2640
 
2641
 
2642
 
2643
 
2644
 
2645
 
2646
 
2647
 
2648
 
2649
 
2650
 
2651
 
2652
 
2653
 
2654
 
2655
 
2656
 
2657
 
2658
 
2659
 
2660
 
2661
 
2662
 
2663
 
2664
 
2665
 
2666
 
2667
 
2668
 
2669
 
2670
 
2671
 
2672
 
2673
 
2674
 
2675
 
2676
 
2677
 
2678
 
2679
 
2680
 
2681
 
2682
 
2683
 
2684
 
2685
 
2686
 
2687
 
2688
 
2689
 
2690
 
2691
 
2692
 
2693
 
2694
 
2695
 
2696
 
2697
 
2698
 
2699
 
2700
 
2701
 
2702
 
2703
 
2704
 
2705
 
2706
 
2707
 
2708
 
2709
 
2710
 
2711
 
2712
 
2713
 
2714
 
2715
 
2716
 
2717
 
2718
 
2719
 
2720
 
2721
 
2722
 
2723
 
2724
 
2725
 
2726
 
2727
 
2728
 
2729
 
2730
 
2731
 
2732
 
2733
 
2734
 
2735
 
2736
 
2737
 
2738
 
2739
 
2740
 
2741
 
2742
 
2743
 
2744
 
2745
 
2746
 
2747
 
2748
 
2749
 
2750
 
2751
 
2752
 
2753
 
2754
 
2755
 
2756
 
2757
 
2758
 
2759
 
2760
 
2761
 
2762
 
2763
 
2764
 
2765
 
2766
 
2767
 
2768
 
2769
 
2770
 
2771
 
2772
 
2773
 
2774
 
2775
 
2776
 
2777
 
2778
 
2779
 
2780
 
2781
 
2782
 
2783
 
2784
 
2785
 
2786
 
2787
 
2788
 
2789
 
2790
 
2791
 
2792
 
2793
 
2794
 
2795
 
2796
 
2797
 
2798
 
2799
 
2800
 
2801
 
2802
 
2803
 
2804
 
2805
 
2806
 
2807
 
2808
 
2809
 
2810
 
2811
 
2812
 
2813
 
2814
 
2815
 
2816
 
2817
 
2818
 
2819
 
2820
 
2821
 
2822
 
2823
 
2824
 
2825
 
2826
 
2827
 
2828
 
2829
 
2830
 
2831
 
2832
 
2833
 
2834
 
2835
 
2836
 
2837
 
2838
 
2839
 
2840
 
2841
 
2842
 
2843
 
2844
 
2845
 
2846
 
2847
 
2848
 
2849
 
2850
 
2851
 
2852
 
2853
 
2854
 
2855
 
2856
 
2857
 
2858
 
2859
 
2860
 
2861
 
2862
 
2863
 
2864
 
2865
 
2866
 
2867
 
2868
 
2869
 
2870
 
2871
 
2872
 
2873
 
2874
 
2875
 
2876
 
2877
 
2878
 
2879
 
2880
 
2881
 
2882
 
2883
 
2884
 
2885
 
2886
 
2887
 
2888
 
2889
 
2890
 
2891
 
2892
 
2893
 
2894
 
2895
 
2896
 
2897
 
2898
 
2899
 
2900
 
2901
 
2902
 
2903
 
2904
 
2905
 
2906
 
2907
 
2908
 
2909
 
2910
 
2911
 
2912
 
2913
 
2914
 
2915
 
2916
 
2917
 
2918
 
2919
 
2920
 
2921
 
2922
 
2923
 
2924
 
2925
 
2926
 
2927
 
2928
 
2929
 
2930
 
2931
 
2932
 
2933
 
2934
 
2935
 
2936
 
2937
 
2938
 
2939
 
2940
 
2941
 
2942
 
2943
 
2944
 
2945
 
2946
 
2947
 
2948
 
2949
 
2950
 
2951
 
2952
 
2953
 
2954
 
2955
 
2956
 
2957
 
2958
 
2959
 
2960
 
2961
 
2962
 
2963
 
2964
 
2965
 
2966
 
2967
 
2968
 
2969
 
2970
 
2971
 
2972
 
2973
 
2974
 
2975
 
2976
 
2977
 
2978
 
2979
 
2980
 
2981
 
2982
 
2983
 
2984
 
2985
 
2986
 
2987
 
2988
 
2989
 
2990
 
2991
 
2992
 
2993
 
2994
 
2995
 
2996
 
2997
 
2998
 
2999
 
3000
 
3001
 
3002
 
3003
 
3004
 
3005
 
3006
 
3007
 
3008
 
3009
 
3010
 
3011
 
3012
 
3013
 
3014
 
3015
 
3016
 
3017
 
3018
 
3019
 
3020
 
3021
 
3022
 
3023
 
3024
 
3025
 
3026
 
3027
 
3028
 
3029
 
3030
 
3031
 
3032
 
3033
 
3034
 
3035
 
3036
 
3037
 
3038
 
3039
 
3040
 
3041
 
3042
 
3043
 
3044
 
3045
 
3046
 
3047
 
3048
 
3049
 
3050
 
3051
 
3052
 
3053
 
3054
 
3055
 
3056
 
3057
 
3058
 
3059
 
3060
 
3061
 
3062
 
3063
 
3064
 
3065
 
3066
 
3067
 
3068
 
3069
 
3070
 
3071
 
3072
 
3073
 
3074
 
3075
 
3076
 
3077
 
3078
 
3079
 
3080
 
3081
 
3082
 
3083
 
3084
 
3085
 
3086
 
3087
 
3088
 
3089
 
3090
 
3091
 
3092
 
3093
 
3094
 
3095
 
3096
 
3097
 
3098
 
3099
 
3100
 
3101
 
3102
 
3103
 
3104
 
3105
 
3106
 
3107
 
3108
 
3109
 
3110
 
3111
 
3112
 
3113
 
3114
 
3115
 
3116
 
3117
 
3118
 
3119
 
3120
 
3121
 
3122
 
3123
 
3124
 
3125
 
3126
 
3127
 
3128
 
3129
 
3130
 
3131
 
3132
 
3133
 
3134
 
3135
 
3136
 
3137
 
3138
 
3139
 
3140
 
3141
 
3142
 
3143
 
3144
 
3145
 
3146
 
3147
 
3148
 
3149
 
3150
 
3151
 
3152
 
3153
 
3154
 
3155
 
3156
 
3157
 
3158
 
3159
 
3160
 
3161
 
3162
 
3163
 
3164
 
3165
 
3166
 
3167
 
3168
 
3169
 
3170
 
3171
 
3172
 
3173
 
3174
 
3175
 
3176
 
3177
 
3178
 
3179
 
3180
 
3181
 
3182
 
3183
 
3184
 
3185
 
3186
 
3187
 
3188
 
3189
 
3190
 
3191
 
3192
 
3193
 
3194
 
3195
 
3196
 
3197
 
3198
 
3199
 
3200
 
3201
 
3202
 
3203
 
3204
 
3205
 
3206
 
3207
 
3208
 
3209
 
3210
 
3211
 
3212
 
3213
 
3214
 
3215
 
3216
 
3217
 
3218
 
3219
 
3220
 
3221
 
3222
 
3223
 
3224
 
3225
 
3226
 
3227
 
3228
 
3229
 
3230
 
3231
 
3232
 
3233
 
3234
 
3235
 
3236
 
3237
 
3238
 
3239
 
3240
 
3241
 
3242
 
3243
 
3244
 
3245
 
3246
 
3247
 
3248
 
3249
 
3250
 
3251
 
3252
 
3253
 
3254
 
3255
 
3256
 
3257
 
3258
 
3259
 
3260
 
3261
 
3262
 
3263
 
3264
 
3265
 
3266
 
3267
 
3268
 
3269
 
3270
 
3271
 
3272
 
3273
 
3274
 
3275
 
3276
 
3277
 
3278
 
3279
 
3280
 
3281
 
3282
 
3283
 
3284
 
3285
 
3286
 
3287
 
3288
 
3289
 
3290
 
3291
 
3292
 
3293
 
3294
 
3295
 
3296
 
3297
 
3298
 
3299
 
3300
 
3301
 
3302
 
3303
 
3304
 
3305
 
3306
 
3307
 
3308
 
3309
 
3310
 
3311
 
3312
 
3313
 
3314
 
3315
 
3316
 
3317
 
3318
 
3319
 
3320
 
3321
 
3322
 
3323
 
3324
 
3325
 
3326
 
3327
 
3328
 
3329
 
3330
 
3331
 
3332
 
3333
 
3334
 
3335
 
3336
 
3337
 
3338
 
3339
 
3340
 
3341
 
3342
 
3343
 
3344
 
3345
 
3346
 
3347
 
3348
 
3349
 
3350
 
3351
 
3352
 
3353
 
3354
 
3355
 
3356
 
3357
 
3358
 
3359
 
3360
 
3361
 
3362
 
3363
 
3364
 
3365
 
3366
 
3367
 
3368
 
3369
 
3370
 
3371
 
3372
 
3373
 
3374
 
3375
 
3376
 
3377
 
3378
 
3379
 
3380
 
3381
 
3382
 
3383
 
3384
 
3385
 
3386
 
3387
 
3388
 
3389
 
3390
 
3391
 
3392
 
3393
 
3394
 
3395
 
3396
 
3397
 
3398
 
3399
 
3400
 
3401
 
3402
 
3403
 
3404
 
3405
 
3406
 
3407
 
3408
 
3409
 
3410
 
3411
 
3412
 
3413
 
3414
 
3415
 
3416
 
3417
 
3418
 
3419
 
3420
 
3421
 
3422
 
3423
 
3424
 
3425
 
3426
 
3427
 
3428
 
3429
 
3430
 
3431
 
3432
 
3433
 
3434
 
3435
 
3436
 
3437
 
3438
 
3439
 
3440
 
3441
 
3442
 
3443
 
3444
 
3445
 
3446
 
3447
 
3448
 
3449
 
3450
 
3451
 
3452
 
3453
 
3454
 
3455
 
3456
 
3457
 
3458
 
3459
 
3460
 
3461
 
3462
 
3463
 
3464
 
3465
 
3466
 
3467
 
3468
 
3469
 
3470
 
3471
 
3472
 
3473
 
3474
 
3475
 
3476
 
3477
 
3478
 
3479
 
3480
 
3481
 
3482
 
3483
 
3484
 
3485
 
3486
 
3487
 
3488
 
3489
 
3490
 
3491
 
3492
 
3493
 
3494
 
3495
 
3496
 
3497
 
3498
 
3499
 
3500
 
3501
 
3502
 
3503
 
3504
 
3505
 
3506
 
3507
 
3508
 
3509
 
3510
 
3511
 
3512
 
3513
 
3514
 
3515
 
3516
 
3517
 
3518
 
3519
 
3520
 
3521
 
3522
 
3523
 
3524
 
3525
 
3526
 
3527
 
3528
 
3529
 
3530
 
3531
 
3532
 
3533
 
3534
 
3535
 
3536
 
3537
 
3538
 
3539
 
3540
 
3541
 
3542
 
3543
 
3544
 
3545
 
3546
 
3547
 
3548
 
3549
 
3550
 
3551
 
3552
 
3553
 
3554
 
3555
 
3556
 
3557
 
3558
 
3559
 
3560
 
3561
 
3562
 
3563
 
3564
 
3565
 
3566
 
3567
 
3568
 
3569
 
3570
 
3571
 
3572
 
3573
 
3574
 
3575
 
3576
 
3577
 
3578
 
3579
 
3580
 
3581
 
3582
 
3583
 
3584
 
3585
 
3586
 
3587
 
3588
 
3589
 
3590
 
3591
 
3592
 
3593
 
3594
 
3595
 
3596
 
3597
 
3598
 
3599
 
3600
 
3601
 
3602
 
3603
 
3604
 
3605
 
3606
 
3607
 
3608
 
3609
 
3610
 
3611
 
3612
 
3613
 
3614
 
3615
 
3616
 
3617
 
3618
 
3619
 
3620
 
3621
 
3622
 
3623
 
3624
 
3625
 
3626
 
3627
 
3628
 
3629
 
3630
 
3631
 
3632
 
3633
 
3634
 
3635
 
3636
 
3637
 
3638
 
3639
 
3640
 
3641
 
3642
 
3643
 
3644
 
3645
 
3646
 
3647
 
3648
 
3649
 
3650
 
3651
 
3652
 
3653
 
3654
 
3655
 
3656
 
3657
 
3658
 
3659
 
3660
 
3661
 
3662
 
3663
 
3664
 
3665
 
3666
 
3667
 
3668
 
3669
 
3670
 
3671
 
3672
 
3673
 
3674
 
3675
 
3676
 
3677
 
3678
 
3679
 
3680
 
3681
 
3682
 
3683
 
3684
 
3685
 
3686
 
3687
 
3688
 
3689
 
3690
 
3691
 
3692
 
3693
 
3694
 
3695
 
3696
 
3697
 
3698
 
3699
 
3700
 
3701
 
3702
 
3703
 
3704
 
3705
 
3706
 
3707
 
3708
 
3709
 
3710
 
3711
 
3712
 
3713
 
3714
 
3715
 
3716
 
3717
 
3718
 
3719
 
3720
 
3721
 
3722
 
3723
 
3724
 
3725
 
3726
 
3727
 
3728
 
3729
 
3730
 
3731
 
3732
 
3733
 
3734
 
3735
 
3736
 
3737
 
3738
 
3739
 
3740
 
3741
 
3742
 
3743
 
3744
 
3745
 
3746
 
3747
 
3748
 
3749
 
3750
 
3751
 
3752
 
3753
 
3754
 
3755
 
3756
 
3757
 
3758
 
3759
 
3760
 
3761
 
3762
 
3763
 
3764
 
3765
 
3766
 
3767
 
3768
 
3769
 
3770
 
3771
 
3772
 
3773
 
3774
 
3775
 
3776
 
3777
 
3778
 
3779
 
3780
 
3781
 
3782
 
3783
 
3784
 
3785
 
3786
 
3787
 
3788
 
3789
 
3790
 
3791
 
3792
 
3793
 
3794
 
3795
 
3796
 
3797
 
3798
 
3799
 
3800
 
3801
 
3802
 
3803
 
3804
 
3805
 
3806
 
3807
 
3808
 
3809
 
3810
 
3811
 
3812
 
3813
 
3814
 
3815
 
3816
 
3817
 
3818
 
3819
 
3820
 
3821
 
3822
 
3823
 
3824
 
3825
 
3826
 
3827
 
3828
 
3829
 
3830
 
3831
 
3832
 
3833
 
3834
 
3835
 
3836
 
3837
 
3838
 
3839
 
3840
 
3841
 
3842
 
3843
 
3844
 
3845
 
3846
 
3847
 
3848
 
3849
 
3850
 
3851
 
3852
 
3853
 
3854
 
3855
 
3856
 
3857
 
3858
 
3859
 
3860
 
3861
 
3862
 
3863
 
3864
 
3865
 
3866
 
3867
 
3868
 
3869
 
3870
 
3871
 
3872
 
3873
 
3874
 
3875
 
3876
 
3877
 
3878
 
3879
 
3880
 
3881
 
3882
 
3883
 
3884
 
3885
 
3886
 
3887
 
3888
 
3889
 
3890
 
3891
 
3892
 
3893
 
3894
 
3895
 
3896
 
3897
 
3898
 
3899
 
3900
 
3901
 
3902
 
3903
 
3904
 
3905
 
3906
 
3907
 
3908
 
3909
 
3910
 
3911
 
3912
 
3913
 
3914
 
3915
 
3916
 
3917
 
3918
 
3919
 
3920
 
3921
 
3922
 
3923
 
3924
 
3925
 
3926
 
3927
 
3928
 
3929
 
3930
 
3931
 
3932
 
3933
 
3934
 
3935
 
3936
 
3937
 
3938
 
3939
 
3940
 
3941
 
3942
 
3943
 
3944
 
3945
 
3946
 
3947
 
3948
 
3949
 
3950
 
3951
 
3952
 
3953
 
3954
 
3955
 
3956
 
3957
 
3958
 
3959
 
3960
 
3961
 
3962
 
3963
 
3964
 
3965
 
3966
 
3967
 
3968
 
3969
 
3970
 
3971
 
3972
 
3973
 
3974
 
3975
 
3976
 
3977
 
3978
 
3979
 
3980
 
3981
 
3982
 
3983
 
3984
 
3985
 
3986
 
3987
 
3988
 
3989
 
3990
 
3991
 
3992
 
3993
 
3994
 
3995
 
3996
 
3997
 
3998
 
3999
 
4000
 
4001
 
4002
 
4003
 
4004
 
4005
 
4006
 
4007
 
4008
 
4009
 
4010
 
4011
 
4012
 
4013
 
4014
 
4015
 
4016
 
4017
 
4018
 
4019
 
4020
 
4021
 
4022
 
4023
 
4024
 
4025
 
4026
 
4027
 
4028
 
4029
 
4030
 
4031
 
4032
 
4033
 
4034
 
4035
 
4036
 
4037
 
4038
 
4039
 
4040
 
4041
 
4042
 
4043
 
4044
 
4045
 
4046
 
4047
 
4048
 
4049
 
4050
 
4051
 
4052
 
4053
 
4054
 
4055
 
4056
 
4057
 
4058
 
4059
 
4060
 
4061
 
4062
 
4063
 
4064
 
4065
 
4066
 
4067
 
4068
 
4069
 
4070
 
4071
 
4072
 
4073
 
4074
 
4075
 
4076
 
4077
 
4078
 
4079
 
4080
 
4081
 
4082
 
4083
 
4084
 
4085
 
4086
 
4087
 
4088
 
4089
 
4090
 
4091
 
4092
 
4093
 
4094
 
4095
 
4096
 
4097
 
4098
 
4099
 
4100
 
4101
 
4102
 
4103
 
4104
 
4105
 
4106
 
4107
 
4108
 
4109
 
4110
 
4111
 
4112
 
4113
 
4114
 
4115
 
4116
 
4117
 
4118
 
4119
 
4120
 
4121
 
4122
 
4123
 
4124
 
4125
 
4126
 
4127
 
4128
 
4129
 
4130
 
4131
 
4132
 
4133
 
4134
 
4135
 
4136
 
4137
 
4138
 
4139
 
4140
 
4141
 
4142
 
4143
 
4144
 
4145
 
4146
 
4147
 
4148
 
4149
 
4150
 
4151
 
4152
 
4153
 
4154
 
4155
 
4156
 
4157
 
4158
 
4159
 
4160
 
4161
 
4162
 
4163
 
4164
 
4165
 
4166
 
4167
 
4168
 
4169
 
4170
 
4171
 
4172
 
4173
 
4174
 
4175
 
4176
 
4177
 
4178
 
4179
 
4180
 
4181
 
4182
 
4183
 
4184
 
4185
 
4186
 
4187
 
4188
 
4189
 
4190
 
4191
 
4192
 
4193
 
4194
 
4195
 
4196
 
4197
 
4198
 
4199
 
4200
 
4201
 
4202
 
4203
 
4204
 
4205
 
4206
 
4207
 
4208
 
4209
 
4210
 
4211
 
4212
 
4213
 
4214
 
4215
 
4216
 
4217
 
4218
 
4219
 
4220
 
4221
 
4222
 
4223
 
4224
 
4225
 
4226
 
4227
 
4228
 
4229
 
4230
 
4231
 
4232
 
4233
 
4234
 
4235
 
4236
 
4237
 
4238
 
4239
 
4240
 
4241
 
4242
 
4243
 
4244
 
4245
 
4246
 
4247
 
4248
 
4249
 
4250
 
4251
 
4252
 
4253
 
4254
 
4255
 
4256
 
4257
 
4258
 
4259
 
4260
 
4261
 
4262
 
4263
 
4264
 
4265
 
4266
 
4267
 
4268
 
4269
 
4270
 
4271
 
4272
 
4273
 
4274
 
4275
 
4276
 
4277
 
4278
 
4279
 
4280
 
4281
 
4282
 
4283
 
4284
 
4285
 
4286
 
4287
 
4288
 
4289
 
4290
 
4291
 
4292
 
4293
 
4294
 
4295
 
4296
 
4297
 
4298
 
4299
 
4300
 
4301
 
4302
 
4303
 
4304
 
4305
 
4306
 
4307
 
4308
 
4309
 
4310
 
4311
 
4312
 
4313
 
4314
 
4315
 
4316
 
4317
 
4318
 
4319
 
4320
 
4321
 
4322
 
4323
 
4324
 
4325
 
4326
 
4327
 
4328
 
4329
 
4330
 
4331
 
4332
 
4333
 
4334
 
4335
 
4336
 
4337
 
4338
 
4339
 
4340
 
4341
 
4342
 
4343
 
4344
 
4345
 
4346
 
4347
 
4348
 
4349
 
4350
 
4351
 
4352
 
4353
 
4354
 
4355
 
4356
 
4357
 
4358
 
4359
 
4360
 
4361
 
4362
 
4363
 
4364
 
4365
 
4366
 
4367
 
4368
 
4369
 
4370
 
4371
 
4372
 
4373
 
4374
 
4375
 
4376
 
4377
 
4378
 
4379
 
4380
 
4381
 
4382
 
4383
 
4384
 
4385
 
4386
 
4387
 
4388
 
4389
 
4390
 
4391
 
4392
 
4393
 
4394
 
4395
 
4396
 
4397
 
4398
 
4399
 
4400
 
4401
 
4402
 
4403
 
4404
 
4405
 
4406
 
4407
 
4408
 
4409
 
4410
 
4411
 
4412
 
4413
 
4414
 
4415
 
4416
 
4417
 
4418
 
4419
 
4420
 
4421
 
4422
 
4423
 
4424
 
4425
 
4426
 
4427
 
4428
 
4429
 
4430
 
4431
 
4432
 
4433
 
4434
 
4435
 
4436
 
4437
 
4438
 
4439
 
4440
 
4441
 
4442
 
4443
 
4444
 
4445
 
4446
 
4447
 
4448
 
4449
 
4450
 
4451
 
4452
 
4453
 
4454
 
4455
 
4456
 
4457
 
4458
 
4459
 
4460
 
4461
 
4462
 
4463
 
4464
 
4465
 
4466
 
4467
 
4468
 
4469
 
4470
 
4471
 
4472
 
4473
 
4474
 
4475
 
4476
 
4477
 
4478
 
4479
 
4480
 
4481
 
4482
 
4483
 
4484
 
4485
 
4486
 
4487
 
4488
 
4489
 
4490
 
4491
 
4492
 
4493
 
4494
 
4495
 
4496
 
4497
 
4498
 
4499
 
4500
 
4501
 
4502
 
4503
 
4504
 
4505
 
4506
 
4507
 
4508
 
4509
 
4510
 
4511
 
4512
 
4513
 
4514
 
4515
 
4516
 
4517
 
4518
 
4519
 
4520
 
4521
 
4522
 
4523
 
4524
 
4525
 
4526
 
4527
 
4528
 
4529
 
4530
 
4531
 
4532
 
4533
 
4534
 
4535
 
4536
 
4537
 
4538
 
4539
 
4540
 
4541
 
4542
 
4543
 
4544
 
4545
 
4546
 
4547
 
4548
 
4549
 
4550
 
4551
 
4552
 
4553
 
4554
 
4555
 
4556
 
4557
 
4558
 
4559
 
4560
 
4561
 
4562
 
4563
 
4564
 
4565
 
4566
 
4567
 
4568
 
4569
 
4570
 
4571
 
4572
 
4573
 
4574
 
4575
 
4576
 
4577
 
4578
 
4579
 
4580
 
4581
 
4582
 
4583
 
4584
 
4585
 
4586
 
4587
 
4588
 
4589
 
4590
 
4591
 
4592
 
4593
 
4594
 
4595
 
4596
 
4597
 
4598
 
4599
 
4600
 
4601
 
4602
 
4603
 
4604
 
4605
 
4606
 
4607
 
4608
 
4609
 
4610
 
4611
 
4612
 
4613
 
4614
 
4615
 
4616
 
4617
 
4618
 
4619
 
4620
 
4621
 
4622
 
4623
 
4624
 
4625
 
4626
 
4627
 
4628
 
4629
 
4630
 
4631
 
4632
 
4633
 
4634
 
4635
 
4636
 
4637
 
4638
 
4639
 
4640
 
4641
 
4642
 
4643
 
4644
 
4645
 
4646
 
4647
 
4648
 
4649
 
4650
 
4651
 
4652
 
4653
 
4654
 
4655
 
4656
 
4657
 
4658
 
4659
 
4660
 
4661
 
4662
 
4663
 
4664
 
4665
 
4666
 
4667
 
4668
 
4669
 
4670
 
4671
 
4672
 
4673
 
4674
 
4675
 
4676
 
4677
 
4678
 
4679
 
4680
 
4681
 
4682
 
4683
 
4684
 
4685
 
4686
 
4687
 
4688
 
4689
 
4690
 
4691
 
4692
 
4693
 
4694
 
4695
 
4696
 
4697
 
4698
 
4699
 
4700
 
4701
 
4702
 
4703
 
4704
 
4705
 
4706
 
4707
 
4708
 
4709
 
4710
 
4711
 
4712
 
4713
 
4714
 
4715
 
4716
 
4717
 
4718
 
4719
 
4720
 
4721
 
4722
 
4723
 
4724
 
4725
 
4726
 
4727
 
4728
 
4729
 
4730
 
4731
 
4732
 
4733
 
4734
 
4735
 
4736
 
4737
 
4738
 
4739
 
4740
 
4741
 
4742
 
4743
 
4744
 
4745
 
4746
 
4747
 
4748
 
4749
 
4750
 
4751
 
4752
 
4753
 
4754
 
4755
 
4756
 
4757
 
4758
 
4759
 
4760
 
4761
 
4762
 
4763
 
4764
 
4765
 
4766
 
4767
 
4768
 
4769
 
4770
 
4771
 
4772
 
4773
 
4774
 
4775
 
4776
 
4777
 
4778
 
4779
 
4780
 
4781
 
4782
 
4783
 
4784
 
4785
 
4786
 
4787
 
4788
 
4789
 
4790
 
4791
 
4792
 
4793
 
4794
 
4795
 
4796
 
4797
 
4798
 
4799
 
4800
 
4801
 
4802
 
4803
 
4804
 
4805
 
4806
 
4807
 
4808
 
4809
 
4810
 
4811
 
4812
 
4813
 
4814
 
4815
 
4816
 
4817
 
4818
 
4819
 
4820
 
4821
 
4822
 
4823
 
4824
 
4825
 
4826
 
4827
 
4828
 
4829
 
4830
 
4831
 
4832
 
4833
 
4834
 
4835
 
4836
 
4837
 
4838
 
4839
 
4840
 
4841
 
4842
 
4843
 
4844
 
4845
 
4846
 
4847
 
4848
 
4849
 
4850
 
4851
 
4852
 
4853
 
4854
 
4855
 
4856
 
4857
 
4858
 
4859
 
4860
 
4861
 
4862
 
4863
 
4864
 
4865
 
4866
 
4867
 
4868
 
4869
 
4870
 
4871
 
4872
 
4873
 
4874
 
4875
 
4876
 
4877
 
4878
 
4879
 
4880
 
4881
 
4882
 
4883
 
4884
 
4885
 
4886
 
4887
 
4888
 
4889
 
4890
 
4891
 
4892
 
4893
 
4894
 
4895
 
4896
 
4897
 
4898
 
4899
 
4900
 
4901
 
4902
 
4903
 
4904
 
4905
 
4906
 
4907
 
4908
 
4909
 
4910
 
4911
 
4912
 
4913
 
4914
 
4915
 
4916
 
4917
 
4918
 
4919
 
4920
 
4921
 
4922
 
4923
 
4924
 
4925
 
4926
 
4927
 
4928
 
4929
 
4930
 
4931
 
4932
 
4933
 
4934
 
4935
 
4936
 
4937
 
4938
 
4939
 
4940
 
4941
 
4942
 
4943
 
4944
 
4945
 
4946
 
4947
 
4948
 
4949
 
4950
 
4951
 
4952
 
4953
 
4954
 
4955
 
4956
 
4957
 
4958
 
4959
 
4960
 
4961
 
4962
 
4963
 
4964
 
4965
 
4966
 
4967
 
4968
 
4969
 
4970
 
4971
 
4972
 
4973
 
4974
 
4975
 
4976
 
4977
 
4978
 
4979
 
4980
 
4981
 
4982
 
4983
 
4984
 
4985
 
4986
 
4987
 
4988
 
4989
 
4990
 
4991
 
4992
 
4993
 
4994
 
4995
 
4996
 
4997
 
4998
 
4999
 
5000
 
5001
 
5002
 
5003
 
5004
 
5005
 
5006
 
5007
 
5008
 
5009
 
5010
 
5011
 
5012
 
5013
 
5014
 
5015
 
5016
 
5017
 
5018
 
5019
 
5020
 
5021
 
5022
 
5023
 
5024
 
5025
 
5026
 
5027
 
5028
 
5029
 
5030
 
5031
 
5032
 
5033
 
5034
 
5035
 
5036
 
5037
 
5038
 
5039
 
5040
 
5041
 
5042
 
5043
 
5044
 
5045
 
5046
 
5047
 
5048
 
5049
 
5050
 
5051
 
5052
 
5053
 
5054
 
5055
 
5056
 
5057
 
5058
 
5059
 
5060
 
5061
 
5062
 
5063
 
5064
 
5065
 
5066
 
5067
 
5068
 
5069
 
5070
 
5071
 
5072
 
5073
 
5074
 
5075
 
5076
 
5077
 
5078
 
5079
 
5080
 
5081
 
5082
 
5083
 
5084
 
5085
 
5086
 
5087
 
5088
 
5089
 
5090
 
5091
 
5092
 
5093
 
5094
 
5095
 
5096
 
5097
 
5098
 
5099
 
5100
 
5101
 
5102
 
5103
 
5104
 
5105
 
5106
 
5107
 
5108
 
5109
 
5110
 
5111
 
5112
 
5113
 
5114
 
5115
 
5116
 
5117
 
5118
 
5119
 
5120
 
5121
 
5122
 
5123
 
5124
 
5125
 
5126
 
5127
 
5128
 
5129
 
5130
 
5131
 
5132
 
5133
 
5134
 
5135
 
5136
 
5137
 
5138
 
5139
 
5140
 
5141
 
5142
 
5143
 
5144
 
5145
 
5146
 
5147
 
5148
 
5149
 
5150
 
5151
 
5152
 
5153
 
5154
 
5155
 
5156
 
5157
 
5158
 
5159
 
5160
 
5161
 
5162
 
5163
 
5164
 
5165
 
5166
 
5167
 
5168
 
5169
 
5170
 
5171
 
5172
 
5173
 
5174
 
5175
 
5176
 
5177
 
5178
 
5179
 
5180
 
5181
 
5182
 
5183
 
5184
 
5185
 
5186
 
5187
 
5188
 
5189
 
5190
 
5191
 
5192
 
5193
 
5194
 
5195
 
5196
 
5197
 
5198
 
5199
 
5200
 
5201
 
5202
 
5203
 
5204
 
5205
 
5206
 
5207
 
5208
 
5209
 
5210
 
5211
 
5212
 
5213
 
5214
 
5215
 
5216
 
5217
 
5218
 
5219
 
5220
 
5221
 
5222
 
5223
 
5224
 
5225
 
5226
 
5227
 
5228
 
5229
 
5230
 
5231
 
5232
 
5233
 
5234
 
5235
 
5236
 
5237
 
5238
 
5239
 
5240
 
5241
 
5242
 
5243
 
5244
 
5245
 
5246
 
5247
 
5248
 
5249
 
5250
 
5251
 
5252
 
5253
 
5254
 
5255
 
5256
 
5257
 
5258
 
5259
 
5260
 
5261
 
5262
 
5263
 
5264
 
5265
 
5266
 
5267
 
5268
 
5269
 
5270
 
5271
 
5272
 
5273
 
5274
 
5275
 
5276
 
5277
 
5278
 
5279
 
5280
 
5281
 
5282
 
5283
 
5284
 
5285
 
5286
 
5287
 
5288
 
5289
 
5290
 
5291
 
5292
 
5293
 
5294
 
5295
 
5296
 
5297
 
5298
 
5299
 
5300
 
5301
 
5302
 
5303
 
5304
 
5305
 
5306
 
5307
 
5308
 
5309
 
5310
 
5311
 
5312
 
5313
 
5314
 
5315
 
5316
 
5317
 
5318
 
5319
 
5320
 
5321
 
5322
 
5323
 
5324
 
5325
 
5326
 
5327
 
5328
 
5329
 
5330
 
5331
 
5332
 
5333
 
5334
 
5335
 
5336
 
5337
 
5338
 
5339
 
5340
 
5341
 
5342
 
5343
 
5344
 
5345
 
5346
 
5347
 
5348
 
5349
 
5350
 
5351
 
5352
 
5353
 
5354
 
5355
 
5356
 
5357
 
5358
 
5359
 
5360
 
5361
 
5362
 
5363
 
5364
 
5365
 
5366
 
5367
 
5368
 
5369
 
5370
 
5371
 
5372
 
5373
 
5374
 
5375
 
5376
 
5377
 
5378
 
5379
 
5380
 
5381
 
5382
 
5383
 
5384
 
5385
 
5386
 
5387
 
5388
 
5389
 
5390
 
5391
 
5392
 
5393
 
5394
 
5395
 
5396
 
5397
 
5398
 
5399
 
5400
 
5401
 
5402
 
5403
 
5404
 
5405
 
5406
 
5407
 
5408
 
5409
 
5410
 
5411
 
5412
 
5413
 
5414
 
5415
 
5416
 
5417
 
5418
 
5419
 
5420
 
5421
 
5422
 
5423
 
5424
 
5425
 
5426
 
5427
 
5428
 
5429
 
5430
 
5431
 
5432
 
5433
 
5434
 
5435
 
5436
 
5437
 
5438
 
5439
 
5440
 
5441
 
5442
 
5443
 
5444
 
5445
 
5446
 
5447
 
5448
 
5449
 
5450
 
5451
 
5452
 
5453
 
5454
 
5455
 
5456
 
5457
 
5458
 
5459
 
5460
 
5461
 
5462
 
5463
 
5464
 
5465
 
5466
 
5467
 
5468
 
5469
 
5470
 
5471
 
5472
 
5473
 
5474
 
5475
 
5476
 
5477
 
5478
 
5479
 
5480
 
5481
 
5482
 
5483
 
5484
 
5485
 
5486
 
5487
 
5488
 
5489
 
5490
 
5491
 
5492
 
5493
 
5494
 
5495
 
5496
 
5497
 
5498
 
5499
 
5500
 
5501
 
5502
 
5503
 
5504
 
5505
 
5506
 
5507
 
5508
 
5509
 
5510
 
5511
 
5512
 
5513
 
5514
 
5515
 
5516
 
5517
 
5518
 
5519
 
5520
 
5521
 
5522
 
5523
 
5524
 
5525
 
5526
 
5527
 
5528
 
5529
 
5530
 
5531
 
5532
 
5533
 
5534
 
5535
 
5536
 
5537
 
5538
 
5539
 
5540
 
5541
 
5542
 
5543
 
5544
 
5545
 
5546
 
5547
 
5548
 
5549
 
5550
 
5551
 
5552
 
5553
 
5554
 
5555
 
5556
 
5557
 
5558
 
5559
 
5560
 
5561
 
5562
 
5563
 
5564
 
5565
 
5566
 
5567
 
5568
 
5569
 
5570
 
5571
 
5572
 
5573
 
5574
 
5575
 
5576
 
5577
 
5578
 
5579
 
5580
 
5581
 
5582
 
5583
 
5584
 
5585
 
5586
 
5587
 
5588
 
5589
 
5590
 
5591
 
5592
 
5593
 
5594
 
5595
 
5596
 
5597
 
5598
 
5599
 
5600
 
5601
 
5602
 
5603
 
5604
 
5605
 
5606
 
5607
 
5608
 
5609
 
5610
 
5611
 
5612
 
5613
 
5614
 
5615
 
5616
 
5617
 
5618
 
5619
 
5620
 
5621
 
5622
 
5623
 
5624
 
5625
 
5626
 
5627
 
5628
 
5629
 
5630
 
5631
 
5632
 
5633
 
5634
 
5635
 
5636
 
5637
 
5638
 
5639
 
5640
 
5641
 
5642
 
5643
 
5644
 
5645
 
5646
 
5647
 
5648
 
5649
 
5650
 
5651
 
5652
 
5653
 
5654
 
5655
 
5656
 
5657
 
5658
 
5659
 
5660
 
5661
 
5662
 
5663
 
5664
 
5665
 
5666
 
5667
 
5668
 
5669
 
5670
 
5671
 
5672
 
5673
 
5674
 
5675
 
5676
 
5677
 
5678
 
5679
 
5680
 
5681
 
5682
 
5683
 
5684
 
5685
 
5686
 
5687
 
5688
 
5689
 
5690
 
5691
 
5692
 
5693
 
5694
 
5695
 
5696
 
5697
 
5698
 
5699
 
5700
 
5701
 
5702
 
5703
 
5704
 
5705
 
5706
 
5707
 
5708
 
5709
 
5710
 
5711
 
5712
 
5713
 
5714
 
5715
 
5716
 
5717
 
5718
 
5719
 
5720
 
5721
 
5722
 
5723
 
5724
 
5725
 
5726
 
5727
 
5728
 
5729
 
5730
 
5731
 
5732
 
5733
 
5734
 
5735
 
5736
 
5737
 
5738
 
5739
 
5740
 
5741
 
5742
 
5743
 
5744
 
5745
 
5746
 
5747
 
5748
 
5749
 
5750
 
5751
 
5752
 
5753
 
5754
 
5755
 
5756
 
5757
 
5758
 
5759
 
5760
 
5761
 
5762
 
5763
 
5764
 
5765
 
5766
 
5767
 
5768
 
5769
 
5770
 
5771
 
5772
 
5773
 
5774
 
5775
 
5776
 
5777
 
5778
 
5779
 
5780
 
5781
 
5782
 
5783
 
5784
 
5785
 
5786
 
5787
 
5788
 
5789
 
5790
 
5791
 
5792
 
5793
 
5794
 
5795
 
5796
 
5797
 
5798
 
5799
 
5800
 
5801
 
5802
 
5803
 
5804
 
5805
 
5806
 
5807
 
5808
 
5809
 
5810
 
5811
 
5812
 
5813
 
5814
 
5815
 
5816
 
5817
 
5818
 
5819
 
5820
 
5821
 
5822
 
5823
 
5824
 
5825
 
5826
 
5827
 
5828
 
5829
 
5830
 
5831
 
5832
 
5833
 
5834
 
5835
 
5836
 
5837
 
5838
 
5839
 
5840
 
5841
 
5842
 
5843
 
5844
 
5845
 
5846
 
5847
 
5848
 
5849
 
5850
 
5851
 
5852
 
5853
 
5854
 
5855
 
5856
 
5857
 
5858
 
5859
 
5860
 
5861
 
5862
 
5863
 
5864
 
5865
 
5866
 
5867
 
5868
 
5869
 
5870
 
5871
 
5872
 
5873
 
5874
 
5875
 
5876
 
5877
 
5878
 
5879
 
5880
 
5881
 
5882
 
5883
 
5884
 
5885
 
5886
 
5887
 
5888
 
5889
 
5890
 
5891
 
5892
 
5893
 
5894
 
5895
 
5896
 
5897
 
5898
 
5899
 
5900
 
5901
 
5902
 
5903
 
5904
 
5905
 
5906
 
5907
 
5908
 
5909
 
5910
 
5911
 
5912
 
5913
 
5914
 
5915
 
5916
 
5917
 
5918
 
5919
 
5920
 
5921
 
5922
 
5923
 
5924
 
5925
 
5926
 
5927
 
5928
 
5929
 
5930
 
5931
 
5932
 
5933
 
5934
 
5935
 
5936
 
5937
 
5938
 
5939
 
5940
 
5941
 
5942
 
5943
 
5944
 
5945
 
5946
 
5947
 
5948
 
5949
 
5950
 
5951
 
5952
 
5953
 
5954
 
5955
 
5956
 
5957
 
5958
 
5959
 
5960
 
5961
 
5962
 
5963
 
5964
 
5965
 
5966
 
5967
 
5968
 
5969
 
5970
 
5971
 
5972
 
5973
 
5974
 
5975
 
5976
 
5977
 
5978
 
5979
 
5980
 
5981
 
5982
 
5983
 
5984
 
5985
 
5986
 
5987
 
5988
 
5989
 
5990
 
5991
 
5992
 
5993
 
5994
 
5995
 
5996
 
5997
 
5998
 
5999
 
6000
 
6001
 
6002
 
6003
 
6004
 
6005
 
6006
 
6007
 
6008
 
6009
 
6010
 
6011
 
6012
 
6013
 
6014
 
6015
 
6016
 
6017
 
6018
 
6019
 
6020
 
6021
 
6022
 
6023
 
6024
 
6025
 
6026
 
6027
 
6028
 
6029
 
6030
 
6031
 
6032
 
6033
 
6034
 
6035
 
6036
 
6037
 
6038
 
6039
 
6040
 
6041
 
6042
 
6043
 
6044
 
6045
 
6046
 
6047
 
6048
 
6049
 
6050
 
6051
 
6052
 
6053
 
6054
 
6055
 
6056
 
6057
 
6058
 
6059
 
6060
 
6061
 
6062
 
6063
 
6064
 
6065
 
6066
 
6067
 
6068
 
6069
 
6070
 
6071
 
6072
 
6073
 
6074
 
6075
 
6076
 
6077
 
6078
 
6079
 
6080
 
6081
 
6082
 
6083
 
6084
 
6085
 
6086
 
6087
 
6088
 
6089
 
6090
 
6091
 
6092
 
6093
 
6094
 
6095
 
6096
 
6097
 
6098
 
6099
 
6100
 
6101
 
6102
 
6103
 
6104
 
6105
 
6106
 
6107
 
6108
 
6109
 
6110
 
6111
 
6112
 
6113
 
6114
 
6115
 
6116
 
6117
 
6118
 
6119
 
6120
 
6121
 
6122
 
6123
 
6124
 
6125
 
6126
 
6127
 
6128
 
6129
 
6130
 
6131
 
6132
 
6133
 
6134
 
6135
 
6136
 
6137
 
6138
 
6139
 
6140
 
6141
 
6142
 
6143
 
6144
 
6145
 
6146
 
6147
 
6148
 
6149
 
6150
 
6151
 
6152
 
6153
 
6154
 
6155
 
6156
 
6157
 
6158
 
6159
 
6160
 
6161
 
6162
 
6163
 
6164
 
6165
 
6166
 
6167
 
6168
 
6169
 
6170
 
6171
 
6172
 
6173
 
6174
 
6175
 
6176
 
6177
 
6178
 
6179
 
6180
 
6181
 
6182
 
6183
 
6184
 
6185
 
6186
 
6187
 
6188
 
6189
 
6190
 
6191
 
6192
 
6193
 
6194
 
6195
 
6196
 
6197
 
6198
 
6199
 
6200
 
6201
 
6202
 
6203
 
6204
 
6205
 
6206
 
6207
 
6208
 
6209
 
6210
 
6211
 
6212
 
6213
 
6214
 
6215
 
6216
 
6217
 
6218
 
6219
 
6220
 
6221
 
6222
 
6223
 
6224
 
6225
 
6226
 
6227
 
6228
 
6229
 
6230
 
6231
 
6232
 
6233
 
6234
 
6235
 
6236
 
6237
 
6238
 
6239
 
6240
 
6241
 
6242
 
6243
 
6244
 
6245
 
6246
 
6247
 
6248
 
6249
 
6250
 
6251
 
6252
 
6253
 
6254
 
6255
 
6256
 
6257
 
6258
 
6259
 
6260
 
6261
 
6262
 
6263
 
6264
 
6265
 
6266
 
6267
 
6268
 
6269
 
6270
 
6271
 
6272
 
6273
 
6274
 
6275
 
6276
 
6277
 
6278
 
6279
 
6280
 
6281
 
6282
 
6283
 
6284
 
6285
 
6286
 
6287
 
6288
 
6289
 
6290
 
6291
 
6292
 
6293
 
6294
 
6295
 
6296
 
6297
 
6298
 
6299
 
6300
 
6301
 
6302
 
6303
 
6304
 
6305
 
6306
 
6307
 
6308
 
6309
 
6310
 
6311
 
6312
 
6313
 
6314
 
6315
 
6316
 
6317
 
6318
 
6319
 
6320
 
6321
 
6322
 
6323
 
6324
 
6325
 
6326
 
6327
 
6328
 
6329
 
6330
 
6331
 
6332
 
6333
 
6334
 
6335
 
6336
 
6337
 
6338
 
6339
 
6340
 
6341
 
6342
 
6343
 
6344
 
6345
 
6346
 
6347
 
6348
 
6349
 
6350
 
6351
 
6352
 
6353
 
6354
 
6355
 
6356
 
6357
 
6358
 
6359
 
6360
 
6361
 
6362
 
6363
 
6364
 
6365
 
6366
 
6367
 
6368
 
6369
 
6370
 
6371
 
6372
 
6373
 
6374
 
6375
 
6376
 
6377
 
6378
 
6379
 
6380
 
6381
 
6382
 
6383
 
6384
 
6385
 
6386
 
6387
 
6388
 
6389
 
6390
 
6391
 
6392
 
6393
 
6394
 
6395
 
6396
 
6397
 
6398
 
6399
 
6400
 
6401
 
6402
 
6403
 
6404
 
6405
 
6406
 
6407
 
6408
 
6409
 
6410
 
6411
 
6412
 
6413
 
6414
 
6415
 
6416
 
6417
 
6418
 
6419
 
6420
 
6421
 
6422
 
6423
 
6424
 
6425
 
6426
 
6427
 
6428
 
6429
 
6430
 
6431
 
6432
 
6433
 
6434
 
6435
 
6436
 
6437
 
6438
 
6439
 
6440
 
6441
 
6442
 
6443
 
6444
 
6445
 
6446
 
6447
 
6448
 
6449
 
6450
 
6451
 
6452
 
6453
 
6454
 
6455
 
6456
 
6457
 
6458
 
6459
 
6460
 
6461
 
6462
 
6463
 
6464
 
6465
 
6466
 
6467
 
6468
 
6469
 
6470
 
6471
 
6472
 
6473
 
6474
 
6475
 
6476
 
6477
 
6478
 
6479
 
6480
 
6481
 
6482
 
6483
 
6484
 
6485
 
6486
 
6487
 
6488
 
6489
 
6490
 
6491
 
6492
 
6493
 
6494
 
6495
 
6496
 
6497
 
6498
 
6499
 
6500
 
6501
 
6502
 
6503
 
6504
 
6505
 
6506
 
6507
 
6508
 
6509
 
6510
 
6511
 
6512
 
6513
 
6514
 
6515
 
6516
 
6517
 
6518
 
6519
 
6520
 
6521
 
6522
 
6523
 
6524
 
6525
 
6526
 
6527
 
6528
 
6529
 
6530
 
6531
 
6532
 
6533
 
6534
 
6535
 
6536
 
6537
 
6538
 
6539
 
6540
 
6541
 
6542
 
6543
 
6544
 
6545
 
6546
 
6547
 
6548
 
6549
 
6550
 
6551
 
6552
 
6553
 
6554
 
6555
 
6556
 
6557
 
6558
 
6559
 
6560
 
6561
 
6562
 
6563
 
6564
 
6565
 
6566
 
6567
 
6568
 
6569
 
6570
 
6571
 
6572
 
6573
 
6574
 
6575
 
6576
 
6577
 
6578
 
6579
 
6580
 
6581
 
6582
 
6583
 
6584
 
6585
 
6586
 
6587
 
6588
 
6589
 
6590
 
6591
 
6592
 
6593
 
6594
 
6595
 
6596
 
6597
 
6598
 
6599
 
6600
 
6601
 
6602
 
6603
 
6604
 
6605
 
6606
 
6607
 
6608
 
6609
 
6610
 
6611
 
6612
 
6613
 
6614
 
6615
 
6616
 
6617
 
6618
 
6619
 
6620
 
6621
 
6622
 
6623
 
6624
 
6625
 
6626
 
6627
 
6628
 
6629
 
6630
 
6631
 
6632
 
6633
 
6634
 
6635
 
6636
 
6637
 
6638
 
6639
 
6640
 
6641
 
6642
 
6643
 
6644
 
6645
 
6646
 
6647
 
6648
 
6649
 
6650
 
6651
 
6652
 
6653
 
6654
 
6655
 
6656
 
6657
 
6658
 
6659
 
6660
 
6661
 
6662
 
6663
 
6664
 
6665
 
6666
 
6667
 
6668
 
6669
 
6670
 
6671
 
6672
 
6673
 
6674
 
6675
 
6676
 
6677
 
6678
 
6679
 
6680
 
6681
 
6682
 
6683
 
6684
 
6685
 
6686
 
6687
 
6688
 
6689
 
6690
 
6691
 
6692
 
6693
 
6694
 
6695
 
6696
 
6697
 
6698
 
6699
 
6700
 
6701
 
6702
 
6703
 
6704
 
6705
 
6706
 
6707
 
6708
 
6709
 
6710
 
6711
 
6712
 
6713
 
6714
 
6715
 
6716
 
6717
 
6718
 
6719
 
6720
 
6721
 
6722
 
6723
 
6724
 
6725
 
6726
 
6727
 
6728
 
6729
 
6730
 
6731
 
6732
 
6733
 
6734
 
6735
 
6736
 
6737
 
6738
 
6739
 
6740
 
6741
 
6742
 
6743
 
6744
 
6745
 
6746
 
6747
 
6748
 
6749
 
6750
 
6751
 
6752
 
6753
 
6754
 
6755
 
6756
 
6757
 
6758
 
6759
 
6760
 
6761
 
6762
 
6763
 
6764
 
6765
 
6766
 
6767
 
6768
 
6769
 
6770
 
6771
 
6772
 
6773
 
6774
 
6775
 
6776
 
6777
 
6778
 
6779
 
6780
 
6781
 
6782
 
6783
 
6784
 
6785
 
6786
 
6787
 
6788
 
6789
 
6790
 
6791
 
6792
 
6793
 
6794
 
6795
 
6796
 
6797
 
6798
 
6799
 
6800
 
6801
 
6802
 
6803
 
6804
 
6805
 
6806
 
6807
 
6808
 
6809
 
6810
 
6811
 
6812
 
6813
 
6814
 
6815
 
6816
 
6817
 
6818
 
6819
 
6820
 
6821
 
6822
 
6823
 
6824
 
6825
 
6826
 
6827
 
6828
 
6829
 
6830
 
6831
 
6832
 
6833
 
6834
 
6835
 
6836
 
6837
 
6838
 
6839
 
6840
 
6841
 
6842
 
6843
 
6844
 
6845
 
6846
 
6847
 
6848
 
6849
 
6850
 
6851
 
6852
 
6853
 
6854
 
6855
 
6856
 
6857
 
6858
 
6859
 
6860
 
6861
 
6862
 
6863
 
6864
 
6865
 
6866
 
6867
 
6868
 
6869
 
6870
 
6871
 
6872
 
6873
 
6874
 
6875
 
6876
 
6877
 
6878
 
6879
 
6880
 
6881
 
6882
 
6883
 
6884
 
6885
 
6886
 
6887
 
6888
 
6889
 
6890
 
6891
 
6892
 
6893
 
6894
 
6895
 
6896
 
6897
 
6898
 
6899
 
6900
 
6901
 
6902
 
6903
 
6904
 
6905
 
6906
 
6907
 
6908
 
6909
 
6910
 
6911
 
6912
 
6913
 
6914
 
6915
 
6916
 
6917
 
6918
 
6919
 
6920
 
6921
 
6922
 
6923
 
6924
 
6925
 
6926
 
6927
 
6928
 
6929
 
6930
 
6931
 
6932
 
6933
 
6934
 
6935
 
6936
 
6937
 
6938
 
6939
 
6940
 
6941
 
6942
 
6943
 
6944
 
6945
 
6946
 
6947
 
6948
 
6949
 
6950
 
6951
 
6952
 
6953
 
6954
 
6955
 
6956
 
6957
 
6958
 
6959
 
6960
 
6961
 
6962
 
6963
 
6964
 
6965
 
6966
 
6967
 
6968
 
6969
 
6970
 
6971
 
6972
 
6973
 
6974
 
6975
 
6976
 
6977
 
6978
 
6979
 
6980
 
6981
 
6982
 
6983
 
6984
 
6985
 
6986
 
6987
 
6988
 
6989
 
6990
 
6991
 
6992
 
6993
 
6994
 
6995
 
6996
 
6997
 
6998
 
6999
 
7000
 
7001
 
7002
 
7003
 
7004
 
7005
 
7006
 
7007
 
7008
 
7009
 
7010
 
7011
 
7012
 
7013
 
7014
 
7015
 
7016
 
7017
 
7018
 
7019
 
7020
 
7021
 
7022
 
7023
 
7024
 
7025
 
7026
 
7027
 
7028
 
7029
 
7030
 
7031
 
7032
 
7033
 
7034
 
7035
 
7036
 
7037
 
7038
 
7039
 
7040
 
7041
 
7042
 
7043
 
7044
 
7045
 
7046
 
7047
 
7048
 
7049
 
7050
 
7051
 
7052
 
7053
 
7054
 
7055
 
7056
 
7057
 
7058
 
7059
 
7060
 
7061
 
7062
 
7063
 
7064
 
7065
 
7066
 
7067
 
7068
 
7069
 
7070
 
7071
 
7072
 
7073
 
7074
 
7075
 
7076
 
7077
 
7078
 
7079
 
7080
 
7081
 
7082
 
7083
 
7084
 
7085
 
7086
 
7087
 
7088
 
7089
 
7090
 
7091
 
7092
 
7093
 
7094
 
7095
 
7096
 
7097
 
7098
 
7099
 
7100
 
7101
 
7102
 
7103
 
7104
 
7105
 
7106
 
7107
 
7108
 
7109
 
7110
 
7111
 
7112
 
7113
 
7114
 
7115
 
7116
 
7117
 
7118
 
7119
 
7120
 
7121
 
7122
 
7123
 
7124
 
7125
 
7126
 
7127
 
7128
 
7129
 
7130
 
7131
 
7132
 
7133
 
7134
 
7135
 
7136
 
7137
 
7138
 
7139
 
7140
 
7141
 
7142
 
7143
 
7144
 
7145
 
7146
 
7147
 
7148
 
7149
 
7150
 
7151
 
7152
 
7153
 
7154
 
7155
 
7156
 
7157
 
7158
 
7159
 
7160
 
7161
 
7162
 
7163
 
7164
 
7165
 
7166
 
7167
 
7168
 
7169
 
7170
 
7171
 
7172
 
7173
 
7174
 
7175
 
7176
 
7177
 
7178
 
7179
 
7180
 
7181
 
7182
 
7183
 
7184
 
7185
 
7186
 
7187
 
7188
 
7189
 
7190
 
7191
 
7192
 
7193
 
7194
 
7195
 
7196
 
7197
 
7198
 
7199
 
7200
 
7201
 
7202
 
7203
 
7204
 
7205
 
7206
 
7207
 
7208
 
7209
 
7210
 
7211
 
7212
 
7213
 
7214
 
7215
 
7216
 
7217
 
7218
 
7219
 
7220
 
7221
 
7222
 
7223
 
7224
 
7225
 
7226
 
7227
 
7228
 
7229
 
7230
 
7231
 
7232
 
7233
 
7234
 
7235
 
7236
 
7237
 
7238
 
7239
 
7240
 
7241
 
7242
 
7243
 
7244
 
7245
 
7246
 
7247
 
7248
 
7249
 
7250
 
7251
 
7252
 
7253
 
7254
 
7255
 
7256
 
7257
 
7258
 
7259
 
7260
 
7261
 
7262
 
7263
 
7264
 
7265
 
7266
 
7267
 
7268
 
7269
 
7270
 
7271
 
7272
 
7273
 
7274
 
7275
 
7276
 
7277
 
7278
 
7279
 
7280
 
7281
 
7282
 
7283
 
7284
 
7285
 
7286
 
7287
 
7288
 
7289
 
7290
 
7291
 
7292
 
7293
 
7294
 
7295
 
7296
 
7297
 
7298
 
7299
 
7300
 
7301
 
7302
 
7303
 
7304
 
7305
 
7306
 
7307
 
7308
 
7309
 
7310
 
7311
 
7312
 
7313
 
7314
 
7315
 
7316
 
7317
 
7318
 
7319
 
7320
 
7321
 
7322
 
7323
 
7324
 
7325
 
7326
 
7327
 
7328
 
7329
 
7330
 
7331
 
7332
 
7333
 
7334
 
7335
 
7336
 
7337
 
7338
 
7339
 
7340
 
7341
 
7342
 
7343
 
7344
 
7345
 
7346
 
7347
 
7348
 
7349
 
7350
 
7351
 
7352
 
7353
 
7354
 
7355
 
7356
 
7357
 
7358
 
7359
 
7360
 
7361
 
7362
 
7363
 
7364
 
7365
 
7366
 
7367
 
7368
 
7369
 
7370
 
7371
 
7372
 
7373
 
7374
 
7375
 
7376
 
7377
 
7378
 
7379
 
7380
 
7381
 
7382
 
7383
 
7384
 
7385
 
7386
 
7387
 
7388
 
7389
 
7390
 
7391
 
7392
 
7393
 
7394
 
7395
 
7396
 
7397
 
7398
 
7399
 
7400
 
7401
 
7402
 
7403
 
7404
 
7405
 
7406
 
7407
 
7408
 
7409
 
7410
 
7411
 
7412
 
7413
 
7414
 
7415
 
7416
 
7417
 
7418
 
7419
 
7420
 
7421
 
7422
 
7423
 
7424
 
7425
 
7426
 
7427
 
7428
 
7429
 
7430
 
7431
 
7432
 
7433
 
7434
 
7435
 
7436
 
7437
 
7438
 
7439
 
7440
 
7441
 
7442
 
7443
 
7444
 
7445
 
7446
 
7447
 
7448
 
7449
 
7450
 
7451
 
7452
 
7453
 
7454
 
7455
 
7456
 
7457
 
7458
 
7459
 
7460
 
7461
 
7462
 
7463
 
7464
 
7465
 
7466
 
7467
 
7468
 
7469
 
7470
 
7471
 
7472
 
7473
 
7474
 
7475
 
7476
 
7477
 
7478
 
7479
 
7480
 
7481
 
7482
 
7483
 
7484
 
7485
 
7486
 
7487
 
7488
 
7489
 
7490
 
7491
 
7492
 
7493
 
7494
 
7495
 
7496
 
7497
 
7498
 
7499
 
7500
 
7501
 
7502
 
7503
 
7504
 
7505
 
7506
 
7507
 
7508
 
7509
 
7510
 
7511
 
7512
 
7513
 
7514
 
7515
 
7516
 
7517
 
7518
 
7519
 
7520
 
7521
 
7522
 
7523
 
7524
 
7525
 
7526
 
7527
 
7528
 
7529
 
7530
 
7531
 
7532
 
7533
 
7534
 
7535
 
7536
 
7537
 
7538
 
7539
 
7540
 
7541
 
7542
 
7543
 
7544
 
7545
 
7546
 
7547
 
7548
 
7549
 
7550
 
7551
 
7552
 
7553
 
7554
 
7555
 
7556
 
7557
 
7558
 
7559
 
7560
 
7561
 
7562
 
7563
 
7564
 
7565
 
7566
 
7567
 
7568
 
7569
 
7570
 
7571
 
7572
 
7573
 
7574
 
7575
 
7576
 
7577
 
7578
 
7579
 
7580
 
7581
 
7582
 
7583
 
7584
 
7585
 
7586
 
7587
 
7588
 
7589
 
7590
 
7591
 
7592
 
7593
 
7594
 
7595
 
7596
 
7597
 
7598
 
7599
 
7600
 
7601
 
7602
 
7603
 
7604
 
7605
 
7606
 
7607
 
7608
 
7609
 
7610
 
7611
 
7612
 
7613
 
7614
 
7615
 
7616
 
7617
 
7618
 
7619
 
7620
 
7621
 
7622
 
7623
 
7624
 
7625
 
7626
 
7627
 
7628
 
7629
 
7630
 
7631
 
7632
 
7633
 
7634
 
7635
 
7636
 
7637
 
7638
 
7639
 
7640
 
7641
 
7642
 
7643
 
7644
 
7645
 
7646
 
7647
 
7648
 
7649
 
7650
 
7651
 
7652
 
7653
 
7654
 
7655
 
7656
 
7657
 
7658
 
7659
 
7660
 
7661
 
7662
 
7663
 
7664
 
7665
 
7666
 
7667
 
7668
 
7669
 
7670
 
7671
 
7672
 
7673
 
7674
 
7675
 
7676
 
7677
 
7678
 
7679
 
7680
 
7681
 
7682
 
7683
 
7684
 
7685
 
7686
 
7687
 
7688
 
7689
 
7690
 
7691
 
7692
 
7693
 
7694
 
7695
 
7696
 
7697
 
7698
 
7699
 
7700
 
7701
 
7702
 
7703
 
7704
 
7705
 
7706
 
7707
 
7708
 
7709
 
7710
 
7711
 
7712
 
7713
 
7714
 
7715
 
7716
 
7717
 
7718
 
7719
 
7720
 
7721
 
7722
 
7723
 
7724
 
7725
 
7726
 
7727
 
7728
 
7729
 
7730
 
7731
 
7732
 
7733
 
7734
 
7735
 
7736
 
7737
 
7738
 
7739
 
7740
 
7741
 
7742
 
7743
 
7744
 
7745
 
7746
 
7747
 
7748
 
7749
 
7750
 
7751
 
7752
 
7753
 
7754
 
7755
 
7756
 
7757
 
7758
 
7759
 
7760
 
7761
 
7762
 
7763
 
7764
 
7765
 
7766
 
7767
 
7768
 
7769
 
7770
 
7771
 
7772
 
7773
 
7774
 
7775
 
7776
 
7777
 
7778
 
7779
 
7780
 
7781
 
7782
 
7783
 
7784
 
7785
 
7786
 
7787
 
7788
 
7789
 
7790
 
7791
 
7792
 
7793
 
7794
 
7795
 
7796
 
7797
 
7798
 
7799
 
7800
 
7801
 
7802
 
7803
 
7804
 
7805
 
7806
 
7807
 
7808
 
7809
 
7810
 
7811
 
7812
 
7813
 
7814
 
7815
 
7816
 
7817
 
7818
 
7819
 
7820
 
7821
 
7822
 
7823
 
7824
 
7825
 
7826
 
7827
 
7828
 
7829
 
7830
 
7831
 
7832
 
7833
 
7834
 
7835
 
7836
 
7837
 
7838
 
7839
 
7840
 
7841
 
7842
 
7843
 
7844
 
7845
 
7846
 
7847
 
7848
 
7849
 
7850
 
7851
 
7852
 
7853
 
7854
 
7855
 
7856
 
7857
 
7858
 
7859
 
7860
 
7861
 
7862
 
7863
 
7864
 
7865
 
7866
 
7867
 
7868
 
7869
 
7870
 
7871
 
7872
 
7873
 
7874
 
7875
 
7876
 
7877
 
7878
 
7879
 
7880
 
7881
 
7882
 
7883
 
7884
 
7885
 
7886
 
7887
 
7888
 
7889
 
7890
 
7891
 
7892
 
7893
 
7894
 
7895
 
7896
 
7897
 
7898
 
7899
 
7900
 
7901
 
7902
 
7903
 
7904
 
7905
 
7906
 
7907
 
7908
 
7909
 
7910
 
7911
 
7912
 
7913
 
7914
 
7915
 
7916
 
7917
 
7918
 
7919
 
7920
 
7921
 
7922
 
7923
 
7924
 
7925
 
7926
 
7927
 
7928
 
7929
 
7930
 
7931
 
7932
 
7933
 
7934
 
7935
 
7936
 
7937
 
7938
 
7939
 
7940
 
7941
 
7942
 
7943
 
7944
 
7945
 
7946
 
7947
 
7948
 
7949
 
7950
 
7951
 
7952
 
7953
 
7954
 
7955
 
7956
 
7957
 
7958
 
7959
 
7960
 
7961
 
7962
 
7963
 
7964
 
7965
 
7966
 
7967
 
7968
 
7969
 
7970
 
7971
 
7972
 
7973
 
7974
 
7975
 
7976
 
7977
 
7978
 
7979
 
7980
 
7981
 
7982
 
7983
 
7984
 
7985
 
7986
 
7987
 
7988
 
7989
 
7990
 
7991
 
7992
 
7993
 
7994
 
7995
 
7996
 
7997
 
7998
 
7999
 
8000
 
8001
 
8002
 
8003
 
8004
 
8005
 
8006
 
8007
 
8008
 
8009
 
8010
 
8011
 
8012
 
8013
 
8014
 
8015
 
8016
 
8017
 
8018
 
8019
 
8020
 
8021
 
8022
 
8023
 
8024
 
8025
 
8026
 
8027
 
8028
 
8029
 
8030
 
8031
 
8032
 
8033
 
8034
 
8035
 
8036
 
8037
 
8038
 
8039
 
8040
 
8041
 
8042
 
8043
 
8044
 
8045
 
8046
 
8047
 
8048
 
8049
 
8050
 
8051
 
8052
 
8053
 
8054
 
8055
 
8056
 
8057
 
8058
 
8059
 
8060
 
8061
 
8062
 
8063
 
8064
 
8065
 
8066
 
8067
 
8068
 
8069
 
8070
 
8071
 
8072
 
8073
 
8074
 
8075
 
8076
 
8077
 
8078
 
8079
 
8080
 
8081
 
8082
 
8083
 
8084
 
8085
 
8086
 
8087
 
8088
 
8089
 
8090
 
8091
 
8092
 
8093
 
8094
 
8095
 
8096
 
8097
 
8098
 
8099
 
8100
 
8101
 
8102
 
8103
 
8104
 
8105
 
8106
 
8107
 
8108
 
8109
 
8110
 
8111
 
8112
 
8113
 
8114
 
8115
 
8116
 
8117
 
8118
 
8119
 
8120
 
8121
 
8122
 
8123
 
8124
 
8125
 
8126
 
8127
 
8128
 
8129
 
8130
 
8131
 
8132
 
8133
 
8134
 
8135
 
8136
 
8137
 
8138
 
8139
 
8140
 
8141
 
8142
 
8143
 
8144
 
8145
 
8146
 
8147
 
8148
 
8149
 
8150
 
8151
 
8152
 
8153
 
8154
 
8155
 
8156
 
8157
 
8158
 
8159
 
8160
 
8161
 
8162
 
8163
 
8164
 
8165
 
8166
 
8167
 
8168
 
8169
 
8170
 
8171
 
8172
 
8173
 
8174
 
8175
 
8176
 
8177
 
8178
 
8179
 
8180
 
8181
 
8182
 
8183
 
8184
 
8185
 
8186
 
8187
 
8188
 
8189
 
8190
 
8191
 
8192
 
8193
 
8194
 
8195
 
8196
 
8197
 
8198
 
8199
 
8200
 
8201
 
8202
 
8203
 
8204
 
8205
 
8206
 
8207
 
8208
 
8209
 
8210
 
8211
 
8212
 
8213
 
8214
 
8215
 
8216
 
8217
 
8218
 
8219
 
8220
 
8221
 
8222
 
8223
 
8224
 
8225
 
8226
 
8227
 
8228
 
8229
 
8230
 
8231
 
8232
 
8233
 
8234
 
8235
 
8236
 
8237
 
8238
 
8239
 
8240
 
8241
 
8242
 
8243
 
8244
 
8245
 
8246
 
8247
 
8248
 
8249
 
8250
 
8251
 
8252
 
8253
 
8254
 
8255
 
8256
 
8257
 
8258
 
8259
 
8260
 
8261
 
8262
 
8263
 
8264
 
8265
 
8266
 
8267
 
8268
 
8269
 
8270
 
8271
 
8272
 
8273
 
8274
 
8275
 
8276
 
8277
 
8278
 
8279
 
8280
 
8281
 
8282
 
8283
 
8284
 
8285
 
8286
 
8287
 
8288
 
8289
 
8290
 
8291
 
8292
 
8293
 
8294
 
8295
 
8296
 
8297
 
8298
 
8299
 
8300
 
8301
 
8302
 
8303
 
8304
 
8305
 
8306
 
8307
 
8308
 
8309
 
8310
 
8311
 
8312
 
8313
 
8314
 
8315
 
8316
 
8317
 
8318
 
8319
 
8320
 
8321
 
8322
 
8323
 
8324
 
8325
 
8326
 
8327
 
8328
 
8329
 
8330
 
8331
 
8332
 
8333
 
8334
 
8335
 
8336
 
8337
 
8338
 
8339
 
8340
 
8341
 
8342
 
8343
 
8344
 
8345
 
8346
 
8347
 
8348
 
8349
 
8350
 
8351
 
8352
 
8353
 
8354
 
8355
 
8356
 
8357
 
8358
 
8359
 
8360
 
8361
 
8362
 
8363
 
8364
 
8365
 
8366
 
8367
 
8368
 
8369
 
8370
 
8371
 
8372
 
8373
 
8374
 
8375
 
8376
 
8377
 
8378
 
8379
 
8380
 
8381
 
8382
 
8383
 
8384
 
8385
 
8386
 
8387
 
8388
 
8389
 
8390
 
8391
 
8392
 
8393
 
8394
 
8395
 
8396
 
8397
 
8398
 
8399
 
8400
 
8401
 
8402
 
8403
 
8404
 
8405
 
8406
 
8407
 
8408
 
8409
 
8410
 
8411
 
8412
 
8413
 
8414
 
8415
 
8416
 
8417
 
8418
 
8419
 
8420
 
8421
 
8422
 
8423
 
8424
 
8425
 
8426
 
8427
 
8428
 
8429
 
8430
 
8431
 
8432
 
8433
 
8434
 
8435
 
8436
 
8437
 
8438
 
8439
 
8440
 
8441
 
8442
 
8443
 
8444
 
8445
 
8446
 
8447
 
8448
 
8449
 
8450
 
8451
 
8452
 
8453
 
8454
 
8455
 
8456
 
8457
 
8458
 
8459
 
8460
 
8461
 
8462
 
8463
 
8464
 
8465
 
8466
 
8467
 
8468
 
8469
 
8470
 
8471
 
8472
 
8473
 
8474
 
8475
 
8476
 
8477
 
8478
 
8479
 
8480
 
8481
 
8482
 
8483
 
8484
 
8485
 
8486
 
8487
 
8488
 
8489
 
8490
 
8491
 
8492
 
8493
 
8494
 
8495
 
8496
 
8497
 
8498
 
8499
 
8500
 
8501
 
8502
 
8503
 
8504
 
8505
 
8506
 
8507
 
8508
 
8509
 
8510
 
8511
 
8512
 
8513
 
8514
 
8515
 
8516
 
8517
 
8518
 
8519
 
8520
 
8521
 
8522
 
8523
 
8524
 
8525
 
8526
 
8527
 
8528
 
8529
 
8530
 
8531
 
8532
 
8533
 
8534
 
8535
 
8536
 
8537
 
8538
 
8539
 
8540
 
8541
 
8542
 
8543
 
8544
 
8545
 
8546
 
8547
 
8548
 
8549
 
8550
 
8551
 
8552
 
8553
 
8554
 
8555
 
8556
 
8557
 
8558
 
8559
 
8560
 
8561
 
8562
 
8563
 
8564
 
8565
 
8566
 
8567
 
8568
 
8569
 
8570
 
8571
 
8572
 
8573
 
8574
 
8575
 
8576
 
8577
 
8578
 
8579
 
8580
 
8581
 
8582
 
8583
 
8584
 
8585
 
8586
 
8587
 
8588
 
8589
 
8590
 
8591
 
8592
 
8593
 
8594
 
8595
 
8596
 
8597
 
8598
 
8599
 
8600
 
8601
 
8602
 
8603
 
8604
 
8605
 
8606
 
8607
 
8608
 
8609
 
8610
 
8611
 
8612
 
8613
 
8614
 
8615
 
8616
 
8617
 
8618
 
8619
 
8620
 
8621
 
8622
 
8623
 
8624
 
8625
 
8626
 
8627
 
8628
 
8629
 
8630
 
8631
 
8632
 
8633
 
8634
 
8635
 
8636
 
8637
 
8638
 
8639
 
8640
 
8641
 
8642
 
8643
 
8644
 
8645
 
8646
 
8647
 
8648
 
8649
 
8650
 
8651
 
8652
 
8653
 
8654
 
8655
 
8656
 
8657
 
8658
 
8659
 
8660
 
8661
 
8662
 
8663
 
8664
 
8665
 
8666
 
8667
 
8668
 
8669
 
8670
 
8671
 
8672
 
8673
 
8674
 
8675
 
8676
 
8677
 
8678
 
8679
 
8680
 
8681
 
8682
 
8683
 
8684
 
8685
 
8686
 
8687
 
8688
 
8689
 
8690
 
8691
 
8692
 
8693
 
8694
 
8695
 
8696
 
8697
 
8698
 
8699
 
8700
 
8701
 
8702
 
8703
 
8704
 
8705
 
8706
 
8707
 
8708
 
8709
 
8710
 
8711
 
8712
 
8713
 
8714
 
8715
 
8716
 
8717
 
8718
 
8719
 
8720
 
8721
 
8722
 
8723
 
8724
 
8725
 
8726
 
8727
 
8728
 
8729
 
8730
 
8731
 
8732
 
8733
 
8734
 
8735
 
8736
 
8737
 
8738
 
8739
 
8740
 
8741
 
8742
 
8743
 
8744
 
8745
 
8746
 
8747
 
8748
 
8749
 
8750
 
8751
 
8752
 
8753
 
8754
 
8755
 
8756
 
8757
 
8758
 
8759
 
8760
 
8761
 
8762
 
8763
 
8764
 
8765
 
8766
 
8767
 
8768
 
8769
 
8770
 
8771
 
8772
 
8773
 
8774
 
8775
 
8776
 
8777
 
8778
 
8779
 
8780
 
8781
 
8782
 
8783
 
8784
 
8785
 
8786
 
8787
 
8788
 
8789
 
8790
 
8791
 
8792
 
8793
 
8794
 
8795
 
8796
 
8797
 
8798
 
8799
 
8800
 
8801
 
8802
 
8803
 
8804
 
8805
 
8806
 
8807
 
8808
 
8809
 
8810
 
8811
 
8812
 
8813
 
8814
 
8815
 
8816
 
8817
 
8818
 
8819
 
8820
 
8821
 
8822
 
8823
 
8824
 
8825
 
8826
 
8827
 
8828
 
8829
 
8830
 
8831
 
8832
 
8833
 
8834
 
8835
 
8836
 
8837
 
8838
 
8839
 
8840
 
8841
 
8842
 
8843
 
8844
 
8845
 
8846
 
8847
 
8848
 
8849
 
8850
 
8851
 
8852
 
8853
 
8854
 
8855
 
8856
 
8857
 
8858
 
8859
 
8860
 
8861
 
8862
 
8863
 
8864
 
8865
 
8866
 
8867
 
8868
 
8869
 
8870
 
8871
 
8872
 
8873
 
8874
 
8875
 
8876
 
8877
 
8878
 
8879
 
8880
 
8881
 
8882
 
8883
 
8884
 
8885
 
8886
 
8887
 
8888
 
8889
 
8890
 
8891
 
8892
 
8893
 
8894
 
8895
 
8896
 
8897
 
8898
 
8899
 
8900
 
8901
 
8902
 
8903
 
8904
 
8905
 
8906
 
8907
 
8908
 
8909
 
8910
 
8911
 
8912
 
8913
 
8914
 
8915
 
8916
 
8917
 
8918
 
8919
 
8920
 
8921
 
8922
 
8923
 
8924
 
8925
 
8926
 
8927
 
8928
 
8929
 
8930
 
8931
 
8932
 
8933
 
8934
 
8935
 
8936
 
8937
 
8938
 
8939
 
8940
 
8941
 
8942
 
8943
 
8944
 
8945
 
8946
 
8947
 
8948
 
8949
 
8950
 
8951
 
8952
 
8953
 
8954
 
8955
 
8956
 
8957
 
8958
 
8959
 
8960
 
8961
 
8962
 
8963
 
8964
 
8965
 
8966
 
8967
 
8968
 
8969
 
8970
 
8971
 
8972
 
8973
 
8974
 
8975
 
8976
 
8977
 
8978
 
8979
 
8980
 
8981
 
8982
 
8983
 
8984
 
8985
 
8986
 
8987
 
8988
 
8989
 
8990
 
8991
 
8992
 
8993
 
8994
 
8995
 
8996
 
8997
 
8998
 
8999
 
9000
 
9001
 
9002
 
9003
 
9004
 
9005
 
9006
 
9007
 
9008
 
9009
 
9010
 
9011
 
9012
 
9013
 
9014
 
9015
 
9016
 
9017
 
9018
 
9019
 
9020
 
9021
 
9022
 
9023
 
9024
 
9025
 
9026
 
9027
 
9028
 
9029
 
9030
 
9031
 
9032
 
9033
 
9034
 
9035
 
9036
 
9037
 
9038
 
9039
 
9040
 
9041
 
9042
 
9043
 
9044
 
9045
 
9046
 
9047
 
9048
 
9049
 
9050
 
9051
 
9052
 
9053
 
9054
 
9055
 
9056
 
9057
 
9058
 
9059
 
9060
 
9061
 
9062
 
9063
 
9064
 
9065
 
9066
 
9067
 
9068
 
9069
 
9070
 
9071
 
9072
 
9073
 
9074
 
9075
 
9076
 
9077
 
9078
 
9079
 
9080
 
9081
 
9082
 
9083
 
9084
 
9085
 
9086
 
9087
 
9088
 
9089
 
9090
 
9091
 
9092
 
9093
 
9094
 
9095
 
9096
 
9097
 
9098
 
9099
 
9100
 
9101
 
9102
 
9103
 
9104
 
9105
 
9106
 
9107
 
9108
 
9109
 
9110
 
9111
 
9112
 
9113
 
9114
 
9115
 
9116
 
9117
 
9118
 
9119
 
9120
 
9121
 
9122
 
9123
 
9124
 
9125
 
9126
 
9127
 
9128
 
9129
 
9130
 
9131
 
9132
 
9133
 
9134
 
9135
 
9136
 
9137
 
9138
 
9139
 
9140
 
9141
 
9142
 
9143
 
9144
 
9145
 
9146
 
9147
 
9148
 
9149
 
9150
 
9151
 
9152
 
9153
 
9154
 
9155
 
9156
 
9157
 
9158
 
9159
 
9160
 
9161
 
9162
 
9163
 
9164
 
9165
 
9166
 
9167
 
9168
 
9169
 
9170
 
9171
 
9172
 
9173
 
9174
 
9175
 
9176
 
9177
 
9178
 
9179
 
9180
 
9181
 
9182
 
9183
 
9184
 
9185
 
9186
 
9187
 
9188
 
9189
 
9190
 
9191
 
9192
 
9193
 
9194
 
9195
 
9196
 
9197
 
9198
 
9199
 
9200
 
9201
 
9202
 
9203
 
9204
 
9205
 
9206
 
9207
 
9208
 
9209
 
9210
 
9211
 
9212
 
9213
 
9214
 
9215
 
9216
 
9217
 
9218
 
9219
 
9220
 
9221
 
9222
 
9223
 
9224
 
9225
 
9226
 
9227
 
9228
 
9229
 
9230
 
9231
 
9232
 
9233
 
9234
 
9235
 
9236
 
9237
 
9238
 
9239
 
9240
 
9241
 
9242
 
9243
 
9244
 
9245
 
9246
 
9247
 
9248
 
9249
 
9250
 
9251
 
9252
 
9253
 
9254
 
9255
 
9256
 
9257
 
9258
 
9259
 
9260
 
9261
 
9262
 
9263
 
9264
 
9265
 
9266
 
9267
 
9268
 
9269
 
9270
 
9271
 
9272
 
9273
 
9274
 
9275
 
9276
 
9277
 
9278
 
9279
 
9280
 
9281
 
9282
 
9283
 
9284
 
9285
 
9286
 
9287
 
9288
 
9289
 
9290
 
9291
 
9292
 
9293
 
9294
 
9295
 
9296
 
9297
 
9298
 
9299
 
9300
 
9301
 
9302
 
9303
 
9304
 
9305
 
9306
 
9307
 
9308
 
9309
 
9310
 
9311
 
9312
 
9313
 
9314
 
9315
 
9316
 
9317
 
9318
 
9319
 
9320
 
9321
 
9322
 
9323
 
9324
 
9325
 
9326
 
9327
 
9328
 
9329
 
9330
 
9331
 
9332
 
9333
 
9334
 
9335
 
9336
 
9337
 
9338
 
9339
 
9340
 
9341
 
9342
 
9343
 
9344
 
9345
 
9346
 
9347
 
9348
 
9349
 
9350
 
9351
 
9352
 
9353
 
9354
 
9355
 
9356
 
9357
 
9358
 
9359
 
9360
 
9361
 
9362
 
9363
 
9364
 
9365
 
9366
 
9367
 
9368
 
9369
 
9370
 
9371
 
9372
 
9373
 
9374
 
9375
 
9376
 
9377
 
9378
 
9379
 
9380
 
9381
 
9382
 
9383
 
9384
 
9385
 
9386
 
9387
 
9388
 
9389
 
9390
 
9391
 
9392
 
9393
 
9394
 
9395
 
9396
 
9397
 
9398
 
9399
 
9400
 
9401
 
9402
 
9403
 
9404
 
9405
 
9406
 
9407
 
9408
 
9409
 
9410
 
9411
 
9412
 
9413
 
9414
 
9415
 
9416
 
9417
 
9418
 
9419
 
9420
 
9421
 
9422
 
9423
 
9424
 
9425
 
9426
 
9427
 
9428
 
9429
 
9430
 
9431
 
9432
 
9433
 
9434
 
9435
 
9436
 
9437
 
9438
 
9439
 
9440
 
9441
 
9442
 
9443
 
9444
 
9445
 
9446
 
9447
 
9448
 
9449
 
9450
 
9451
 
9452
 
9453
 
9454
 
9455
 
9456
 
9457
 
9458
 
9459
 
9460
 
9461
 
9462
 
9463
 
9464
 
9465
 
9466
 
9467
 
9468
 
9469
 
9470
 
9471
 
9472
 
9473
 
9474
 
9475
 
9476
 
9477
 
9478
 
9479
 
9480
 
9481
 
9482
 
9483
 
9484
 
9485
 
9486
 
9487
 
9488
 
9489
 
9490
 
9491
 
9492
 
9493
 
9494
 
9495
 
9496
 
9497
 
9498
 
9499
 
9500
 
9501
 
9502
 
9503
 
9504
 
9505
 
9506
 
9507
 
9508
 
9509
 
9510
 
9511
 
9512
 
9513
 
9514
 
9515
 
9516
 
9517
 
9518
 
9519
 
9520
 
9521
 
9522
 
9523
 
9524
 
9525
 
9526
 
9527
 
9528
 
9529
 
9530
 
9531
 
9532
 
9533
 
9534
 
9535
 
9536
 
9537
 
9538
 
9539
 
9540
 
9541
 
9542
 
9543
 
9544
 
9545
 
9546
 
9547
 
9548
 
9549
 
9550
 
9551
 
9552
 
9553
 
9554
 
9555
 
9556
 
9557
 
9558
 
9559
 
9560
 
9561
 
9562
 
9563
 
9564
 
9565
 
9566
 
9567
 
9568
 
9569
 
9570
 
9571
 
9572
 
9573
 
9574
 
9575
 
9576
 
9577
 
9578
 
9579
 
9580
 
9581
 
9582
 
9583
 
9584
 
9585
 
9586
 
9587
 
9588
 
9589
 
9590
 
9591
 
9592
 
9593
 
9594
 
9595
 
9596
 
9597
 
9598
 
9599
 
9600
 
9601
 
9602
 
9603
 
9604
 
9605
 
9606
 
9607
 
9608
 
9609
 
9610
 
9611
 
9612
 
9613
 
9614
 
9615
 
9616
 
9617
 
9618
 
9619
 
9620
 
9621
 
9622
 
9623
 
9624
 
9625
 
9626
 
9627
 
9628
 
9629
 
9630
 
9631
 
9632
 
9633
 
9634
 
9635
 
9636
 
9637
 
9638
 
9639
 
9640
 
9641
 
9642
 
9643
 
9644
 
9645
 
9646
 
9647
 
9648
 
9649
 
9650
 
9651
 
9652
 
9653
 
9654
 
9655
 
9656
 
9657
 
9658
 
9659
 
9660
 
9661
 
9662
 
9663
 
9664
 
9665
 
9666
 
9667
 
9668
 
9669
 
9670
 
9671
 
9672
 
9673
 
9674
 
9675
 
9676
 
9677
 
9678
 
9679
 
9680
 
9681
 
9682
 
9683
 
9684
 
9685
 
9686
 
9687
 
9688
 
9689
 
9690
 
9691
 
9692
 
9693
 
9694
 
9695
 
9696
 
9697
 
9698
 
9699
 
9700
 
9701
 
9702
 
9703
 
9704
 
9705
 
9706
 
9707
 
9708
 
9709
 
9710
 
9711
 
9712
 
9713
 
9714
 
9715
 
9716
 
9717
 
9718
 
9719
 
9720
 
9721
 
9722
 
9723
 
9724
 
9725
 
9726
 
9727
 
9728
 
9729
 
9730
 
9731
 
9732
 
9733
 
9734
 
9735
 
9736
 
9737
 
9738
 
9739
 
9740
 
9741
 
9742
 
9743
 
9744
 
9745
 
9746
 
9747
 
9748
 
9749
 
9750
 
9751
 
9752
 
9753
 
9754
 
9755
 
9756
 
9757
 
9758
 
9759
 
9760
 
9761
 
9762
 
9763
 
9764
 
9765
 
9766
 
9767
 
9768
 
9769
 
9770
 
9771
 
9772
 
9773
 
9774
 
9775
 
9776
 
9777
 
9778
 
9779
 
9780
 
9781
 
9782
 
9783
 
9784
 
9785
 
9786
 
9787
 
9788
 
9789
 
9790
 
9791
 
9792
 
9793
 
9794
 
9795
 
9796
 
9797
 
9798
 
9799
 
9800
 
9801
 
9802
 
9803
 
9804
 
9805
 
9806
 
9807
 
9808
 
9809
 
9810
 
9811
 
9812
 
9813
 
9814
 
9815
 
9816
 
9817
 
9818
 
9819
 
9820
 
9821
 
9822
 
9823
 
9824
 
9825
 
9826
 
9827
 
9828
 
9829
 
9830
 
9831
 
9832
 
9833
 
9834
 
9835
 
9836
 
9837
 
9838
 
9839
 
9840
 
9841
 
9842
 
9843
 
9844
 
9845
 
9846
 
9847
 
9848
 
9849
 
9850
 
9851
 
9852
 
9853
 
9854
 
9855
 
9856
 
9857
 
9858
 
9859
 
9860
 
9861
 
9862
 
9863
 
9864
 
9865
 
9866
 
9867
 
9868
 
9869
 
9870
 
9871
 
9872
 
9873
 
9874
 
9875
 
9876
 
9877
 
9878
 
9879
 
9880
 
9881
 
9882
 
9883
 
9884
 
9885
 
9886
 
9887
 
9888
 
9889
 
9890
 
9891
 
9892
 
9893
 
9894
 
9895
 
9896
 
9897
 
9898
 
9899
 
9900
 
9901
 
9902
 
9903
 
9904
 
9905
 
9906
 
9907
 
9908
 
9909
 
9910
 
9911
 
9912
 
9913
 
9914
 
9915
 
9916
 
9917
 
9918
 
9919
 
9920
 
9921
 
9922
 
9923
 
9924
 
9925
 
9926
 
9927
 
9928
 
9929
 
9930
 
9931
 
9932
 
9933
 
9934
 
9935
 
9936
 
9937
 
9938
 
9939
 
9940
 
9941
 
9942
 
9943
 
9944
 
9945
 
9946
 
9947
 
9948
 
9949
 
9950
 
9951
 
9952
 
9953
 
9954
 
9955
 
9956
 
9957
 
9958
 
9959
 
9960
 
9961
 
9962
 
9963
 
9964
 
9965
 
9966
 
9967
 
9968
 
9969
 
9970
 
9971
 
9972
 
9973
 
9974
 
9975
 
9976
 
9977
 
9978
 
9979
 
9980
 
9981
 
9982
 
9983
 
9984
 
9985
 
9986
 
9987
 
9988
 
9989
 
9990
 
9991
 
9992
 
9993
 
9994
 
9995
 
9996
 
9997
 
9998
 
9999
 
10000
 
10001
 
10002
 
10003
 
10004
 
10005
 
10006
 
10007
 
10008
 
10009
 
10010
 
10011
 
10012
 
10013
 
10014
 
10015
 
10016
 
10017
 
10018
 
10019
 
10020
 
10021
 
10022
 
10023
 
10024
 
10025
 
10026
 
10027
 
10028
 
10029
 
10030
 
10031
 
10032
 
10033
 
10034
 
10035
 
10036
 
10037
 
10038
 
10039
 
10040
 
10041
 
10042
 
10043
 
10044
 
10045
 
10046
 
10047
 
10048
 
10049
 
10050
 
10051
 
10052
 
10053
 
10054
 
10055
 
10056
 
10057
 
10058
 
10059
 
10060
 
10061
 
10062
 
10063
 
10064
 
10065
 
10066
 
10067
 
10068
 
10069
 
10070
 
10071
 
10072
 
10073
 
10074
 
10075
 
10076
 
10077
 
10078
 
10079
 
10080
 
10081
 
10082
 
10083
 
10084
 
10085
 
10086
 
10087
 
10088
 
10089
 
10090
 
10091
 
10092
 
10093
 
10094
 
10095
 
10096
 
10097
 
10098
 
10099
 
10100
 
10101
 
10102
 
10103
 
10104
 
10105
 
10106
 
10107
 
10108
 
10109
 
10110
 
10111
 
10112
 
10113
 
10114
 
10115
 
10116
 
10117
 
10118
 
10119
 
10120
 
10121
 
10122
 
10123
 
10124
 
10125
 
10126
 
10127
 
10128
 
10129
 
10130
 
10131
 
10132
 
10133
 
10134
 
10135
 
10136
 
10137
 
10138
 
10139
 
10140
 
10141
 
10142
 
10143
 
10144
 
10145
 
10146
 
10147
 
10148
 
10149
 
10150
 
10151
 
10152
 
10153
 
10154
 
10155
 
10156
 
10157
 
10158
 
10159
 
10160
 
10161
 
10162
 
10163
 
10164
 
10165
 
10166
 
10167
 
10168
 
10169
 
10170
 
10171
 
10172
 
10173
 
10174
 
10175
 
10176
 
10177
 
10178
 
10179
 
10180
 
10181
 
10182
 
10183
 
10184
 
10185
 
10186
 
10187
 
10188
 
10189
 
10190
 
10191
 
10192
 
10193
 
10194
 
10195
 
10196
 
10197
 
10198
 
10199
 
10200
 
10201
 
10202
 
10203
 
10204
 
10205
 
10206
 
10207
 
10208
 
10209
 
10210
 
10211
 
10212
 
10213
 
10214
 
10215
 
10216
 
10217
 
10218
 
10219
 
10220
 
10221
 
10222
 
10223
 
10224
 
10225
 
10226
 
10227
 
10228
 
10229
 
10230
 
10231
 
10232
 
10233
 
10234
 
10235
 
10236
 
10237
 
10238
 
10239
 
10240
 
10241
 
10242
 
10243
 
10244
 
10245
 
10246
 
10247
 
10248
 
10249
 
10250
 
10251
 
10252
 
10253
 
10254
 
10255
 
10256
 
10257
 
10258
 
10259
 
10260
 
10261
 
10262
 
10263
 
10264
 
10265
 
10266
 
10267
 
10268
 
10269
 
10270
 
10271
 
10272
 
10273
 
10274
 
10275
 
10276
 
10277
 
10278
 
10279
 
10280
 
10281
 
10282
 
10283
 
10284
 
10285
 
10286
 
10287
 
10288
 
10289
 
10290
 
10291
 
10292
 
10293
 
10294
 
10295
 
10296
 
10297
 
10298
 
10299
 
10300
 
10301
 
10302
 
10303
 
10304
 
10305
 
10306
 
10307
 
10308
 
10309
 
10310
 
10311
 
10312
 
10313
 
10314
 
10315
 
10316
 
10317
 
10318
 
10319
 
10320
 
10321
 
10322
 
10323
 
10324
 
10325
 
10326
 
10327
 
10328
 
10329
 
10330
 
10331
 
10332
 
10333
 
10334
 
10335
 
10336
 
10337
 
10338
 
10339
 
10340
 
10341
 
10342
 
10343
 
10344
 
10345
 
10346
 
10347
 
10348
 
10349
 
10350
 
10351
 
10352
 
10353
 
10354
 
10355
 
10356
 
10357
 
10358
 
10359
 
10360
 
10361
 
10362
 
10363
 
10364
 
10365
 
10366
 
10367
 
10368
 
10369
 
10370
 
10371
 
10372
 
10373
 
10374
 
10375
 
10376
 
10377
 
10378
 
10379
 
10380
 
10381
 
10382
 
10383
 
10384
 
10385
 
10386
 
10387
 
10388
 
10389
 
10390
 
10391
 
10392
 
10393
 
10394
 
10395
 
10396
 
10397
 
10398
 
10399
 
10400
 
10401
 
10402
 
10403
 
10404
 
10405
 
10406
 
10407
 
10408
 
10409
 
10410
 
10411
 
10412
 
10413
 
10414
 
10415
 
10416
 
10417
 
10418
 
10419
 
10420
 
10421
 
10422
 
10423
 
10424
 
10425
 
10426
 
10427
 
10428
 
10429
 
10430
 
10431
 
10432
 
10433
 
10434
 
10435
 
10436
 
10437
 
10438
 
10439
 
10440
 
10441
 
10442
 
10443
 
10444
 
10445
 
10446
 
10447
 
10448
 
10449
 
10450
 
10451
 
10452
 
10453
 
10454
 
10455
 
10456
 
10457
 
10458
 
10459
 
10460
 
10461
 
10462
 
10463
 
10464
 
10465
 
10466
 
10467
 
10468
 
10469
 
10470
 
10471
 
10472
 
10473
 
10474
 
10475
 
10476
 
10477
 
10478
 
10479
 
10480
 
10481
 
10482
 
10483
 
10484
 
10485
 
10486
 
10487
 
10488
 
10489
 
10490
 
10491
 
10492
 
10493
 
10494
 
10495
 
10496
 
10497
 
10498
 
10499
 
10500
 
10501
 
10502
 
10503
 
10504
 
10505
 
10506
 
10507
 
10508
 
10509
 
10510
 
10511
 
10512
 
10513
 
10514
 
10515
 
10516
 
10517
 
10518
 
10519
 
10520
 
10521
 
10522
 
10523
 
10524
 
10525
 
10526
 
10527
 
10528
 
10529
 
10530
 
10531
 
10532
 
10533
 
10534
 
10535
 
10536
 
10537
 
10538
 
10539
 
10540
 
10541
 
10542
 
10543
 
10544
 
10545
 
10546
 
10547
 
10548
 
10549
 
10550
 
10551
 
10552
 
10553
 
10554
 
10555
 
10556
 
10557
 
10558
 
10559
 
10560
 
10561
 
10562
 
10563
 
10564
 
10565
 
10566
 
10567
 
10568
 
10569
 
10570
 
10571
 
10572
 
10573
 
10574
 
10575
 
10576
 
10577
 
10578
 
10579
 
10580
 
10581
 
10582
 
10583
 
10584
 
10585
 
10586
 
10587
 
10588
 
10589
 
10590
 
10591
 
10592
 
10593
 
10594
 
10595
 
10596
 
10597
 
10598
 
10599
 
10600
 
10601
 
10602
 
10603
 
10604
 
10605
 
10606
 
10607
 
10608
 
10609
 
10610
 
10611
 
10612
 
10613
 
10614
 
10615
 
10616
 
10617
 
10618
 
10619
 
10620
 
10621
 
10622
 
10623
 
10624
 
10625
 
10626
 
10627
 
10628
 
10629
 
10630
 
10631
 
10632
 
10633
 
10634
 
10635
 
10636
 
10637
 
10638
 
10639
 
10640
 
10641
 
10642
 
10643
 
10644
 
10645
 
10646
 
10647
 
10648
 
10649
 
10650
 
10651
 
10652
 
10653
 
10654
 
10655
 
10656
 
10657
 
10658
 
10659
 
10660
 
10661
 
10662
 
10663
 
10664
 
10665
 
10666
 
10667
 
10668
 
10669
 
10670
 
10671
 
10672
 
10673
 
10674
 
10675
 
10676
 
10677
 
10678
 
10679
 
10680
 
10681
 
10682
 
10683
 
10684
 
10685
 
10686
 
10687
 
10688
 
10689
 
10690
 
10691
 
10692
 
10693
 
10694
 
10695
 
10696
 
10697
 
10698
 
10699
 
10700
 
10701
 
10702
 
10703
 
10704
 
10705
 
10706
 
10707
 
10708
 
10709
 
10710
 
10711
 
10712
 
10713
 
10714
 
10715
 
10716
 
10717
 
10718
 
10719
 
10720
 
10721
 
10722
 
10723
 
10724
 
10725
 
10726
 
10727
 
10728
 
10729
 
10730
 
10731
 
10732
 
10733
 
10734
 
10735
 
10736
 
10737
 
10738
 
10739
 
10740
 
10741
 
10742
 
10743
 
10744
 
10745
 
10746
 
10747
 
10748
 
10749
 
10750
 
10751
 
10752
 
10753
 
10754
 
10755
 
10756
 
10757
 
10758
 
10759
 
10760
 
10761
 
10762
 
10763
 
10764
 
10765
 
10766
 
10767
 
10768
 
10769
 
10770
 
10771
 
10772
 
10773
 
10774
 
10775
 
10776
 
10777
 
10778
 
10779
 
10780
 
10781
 
10782
 
10783
 
10784
 
10785
 
10786
 
10787
 
10788
 
10789
 
10790
 
10791
 
10792
 
10793
 
10794
 
10795
 
10796
 
10797
 
10798
 
10799
 
10800
 
10801
 
10802
 
10803
 
10804
 
10805
 
10806
 
10807
 
10808
 
10809
 
10810
 
10811
 
10812
 
10813
 
10814
 
10815
 
10816
 
10817
 
10818
 
10819
 
10820
 
10821
 
10822
 
10823
 
10824
 
10825
 
10826
 
10827
 
10828
 
10829
 
10830
 
10831
 
10832
 
10833
 
10834
 
10835
 
10836
 
10837
 
10838
 
10839
 
10840
 
10841
 
10842
 
10843
 
10844
 
10845
 
10846
 
10847
 
10848
 
10849
 
10850
 
10851
 
10852
 
10853
 
10854
 
10855
 
10856
 
10857
 
10858
 
10859
 
10860
 
10861
 
10862
 
10863
 
10864
 
10865
 
10866
 
10867
 
10868
 
10869
 
10870
 
10871
 
10872
 
10873
 
10874
 
10875
 
10876
 
10877
 
10878
 
10879
 
10880
 
10881
 
10882
 
10883
 
10884
 
10885
 
10886
 
10887
 
10888
 
10889
 
10890
 
10891
 
10892
 
10893
 
10894
 
10895
 
10896
 
10897
 
10898
 
10899
 
10900
 
10901
 
10902
 
10903
 
10904
 
10905
 
10906
 
10907
 
10908
 
10909
 
10910
 
10911
 
10912
 
10913
 
10914
 
10915
 
10916
 
10917
 
10918
 
10919
 
10920
 
10921
 
10922
 
10923
 
10924
 
10925
 
10926
 
10927
 
10928
 
10929
 
10930
 
10931
 
10932
 
10933
 
10934
 
10935
 
10936
 
10937
 
10938
 
10939
 
10940
 
10941
 
10942
 
10943
 
10944
 
10945
 
10946
 
10947
 
10948
 
10949
 
10950
 
10951
 
10952
 
10953
 
10954
 
10955
 
10956
 
10957
 
10958
 
10959
 
10960
 
10961
 
10962
 
10963
 
10964
 
10965
 
10966
 
10967
 
10968
 
10969
 
10970
 
10971
 
10972
 
10973
 
10974
 
10975
 
10976
 
10977
 
10978
 
10979
 
10980
 
10981
 
10982
 
10983
 
10984
 
10985
 
10986
 
10987
 
10988
 
10989
 
10990
 
10991
 
10992
 
10993
 
10994
 
10995
 
10996
 
10997
 
10998
 
10999
 
11000
 
11001
 
11002
 
11003
 
11004
 
11005
 
11006
 
11007
 
11008
 
11009
 
11010
 
11011
 
11012
 
11013
 
11014
 
11015
 
11016
 
11017
 
11018
 
11019
 
11020
 
11021
 
11022
 
11023
 
11024
 
11025
 
11026
 
11027
 
11028
 
11029
 
11030
 
11031
 
11032
 
11033
 
11034
 
11035
 
11036
 
11037
 
11038
 
11039
 
11040
 
11041
 
11042
 
11043
 
11044
 
11045
 
11046
 
11047
 
11048
 
11049
 
11050
 
11051
 
11052
 
11053
 
11054
 
11055
 
11056
 
11057
 
11058
 
11059
 
11060
 
11061
 
11062
 
11063
 
11064
 
11065
 
11066
 
11067
 
11068
 
11069
 
11070
 
11071
 
11072
 
11073
 
11074
 
11075
 
11076
 
11077
 
11078
 
11079
 
11080
 
11081
 
11082
 
11083
 
11084
 
11085
 
11086
 
11087
 
11088
 
11089
 
11090
 
11091
 
11092
 
11093
 
11094
 
11095
 
11096
 
11097
 
11098
 
11099
 
11100
 
11101
 
11102
 
11103
 
11104
 
11105
 
11106
 
11107
 
11108
 
11109
 
11110
 
11111
 
11112
 
11113
 
11114
 
11115
 
11116
 
11117
 
11118
 
11119
 
11120
 
11121
 
11122
 
11123
 
11124
 
11125
 
11126
 
11127
 
11128
 
11129
 
11130
 
11131
 
11132
 
11133
 
11134
 
11135
 
11136
 
11137
 
11138
 
11139
 
11140
 
11141
 
11142
 
11143
 
11144
 
11145
 
11146
 
11147
 
11148
 
11149
 
11150
 
11151
 
11152
 
11153
 
11154
 
11155
 
11156
 
11157
 
11158
 
11159
 
11160
 
11161
 
11162
 
11163
 
11164
 
11165
 
11166
 
11167
 
11168
 
11169
 
11170
 
11171
 
11172
 
11173
 
11174
 
11175
 
11176
 
11177
 
11178
 
11179
 
11180
 
11181
 
11182
 
11183
 
11184
 
11185
 
11186
 
11187
 
11188
 
11189
 
11190
 
11191
 
11192
 
11193
 
11194
 
11195
 
11196
 
11197
 
11198
 
11199
 
11200
 
11201
 
11202
 
11203
 
11204
 
11205
 
11206
 
11207
 
11208
 
11209
 
11210
 
11211
 
11212
 
11213
 
11214
 
11215
 
11216
 
11217
 
11218
 
11219
 
11220
 
11221
 
11222
 
11223
 
11224
 
11225
 
11226
 
11227
 
11228
 
11229
 
11230
 
11231
 
11232
 
11233
 
11234
 
11235
 
11236
 
11237
 
11238
 
11239
 
11240
 
11241
 
11242
 
11243
 
11244
 
11245
 
11246
 
11247
 
11248
 
11249
 
11250
 
11251
 
11252
 
11253
 
11254
 
11255
 
11256
 
11257
 
11258
 
11259
 
11260
 
11261
 
11262
 
11263
 
11264
 
11265
 
11266
 
11267
 
11268
 
11269
 
11270
 
11271
 
11272
 
11273
 
11274
 
11275
 
11276
 
11277
 
11278
 
11279
 
11280
 
11281
 
11282
 
11283
 
11284
 
11285
 
11286
 
11287
 
11288
 
11289
 
11290
 
11291
 
11292
 
11293
 
11294
 
11295
 
11296
 
11297
 
11298
 
11299
 
11300
 
11301
 
11302
 
11303
 
11304
 
11305
 
11306
 
11307
 
11308
 
11309
 
11310
 
11311
 
11312
 
11313
 
11314
 
11315
 
11316
 
11317
 
11318
 
11319
 
11320
 
11321
 
11322
 
11323
 
11324
 
11325
 
11326
 
11327
 
11328
 
11329
 
11330
 
11331
 
11332
 
11333
 
11334
 
11335
 
11336
 
11337
 
11338
 
11339
 
11340
 
11341
 
11342
 
11343
 
11344
 
11345
 
11346
 
11347
 
11348
 
11349
 
11350
 
11351
 
11352
 
11353
 
11354
 
11355
 
11356
 
11357
 
11358
 
11359
 
11360
 
11361
 
11362
 
11363
 
11364
 
11365
 
11366
 
11367
 
11368
 
11369
 
11370
 
11371
 
11372
 
11373
 
11374
 
11375
 
11376
 
11377
 
11378
 
11379
 
11380
 
11381
 
11382
 
11383
 
11384
 
11385
 
11386
 
11387
 
11388
 
11389
 
11390
 
11391
 
11392
 
11393
 
11394
 
11395
 
11396
 
11397
 
11398
 
11399
 
11400
 
11401
 
11402
 
11403
 
11404
 
11405
 
11406
 
11407
 
11408
 
11409
 
11410
 
11411
 
11412
 
11413
 
11414
 
11415
 
11416
 
11417
 
11418
 
11419
 
11420
 
11421
 
11422
 
11423
 
11424
 
11425
 
11426
 
11427
 
11428
 
11429
 
11430
 
11431
 
11432
 
11433
 
11434
 
11435
 
11436
 
11437
 
11438
 
11439
 
11440
 
11441
 
11442
 
11443
 
11444
 
11445
 
11446
 
11447
 
11448
 
11449
 
11450
 
11451
 
11452
 
11453
 
11454
 
11455
 
11456
 
11457
 
11458
 
11459
 
11460
 
11461
 
11462
 
11463
 
11464
 
11465
 
11466
 
11467
 
11468
 
11469
 
11470
 
11471
 
11472
 
11473
 
11474
 
11475
 
11476
 
11477
 
11478
 
11479
 
11480
 
11481
 
11482
 
11483
 
11484
 
11485
 
11486
 
11487
 
11488
 
11489
 
11490
 
11491
 
11492
 
11493
 
11494
 
11495
 
11496
 
11497
 
11498
 
11499
 
11500
 
11501
 
11502
 
11503
 
11504
 
11505
 
11506
 
11507
 
11508
 
11509
 
11510
 
11511
 
11512
 
11513
 
11514
 
11515
 
11516
 
11517
 
11518
 
11519
 
11520
 
11521
 
11522
 
11523
 
11524
 
11525
 
11526
 
11527
 
11528
 
11529
 
11530
 
11531
 
11532
 
11533
 
11534
 
11535
 
11536
 
11537
 
11538
 
11539
 
11540
 
11541
 
11542
 
11543
 
11544
 
11545
 
11546
 
11547
 
11548
 
11549
 
11550
 
11551
 
11552
 
11553
 
11554
 
11555
 
11556
 
11557
 
11558
 
11559
 
11560
 
11561
 
11562
 
11563
 
11564
 
11565
 
11566
 
11567
 
11568
 
11569
 
11570
 
11571
 
11572
 
11573
 
11574
 
11575
 
11576
 
11577
 
11578
 
11579
 
11580
 
11581
 
11582
 
11583
 
11584
 
11585
 
11586
 
11587
 
11588
 
11589
 
11590
 
11591
 
11592
 
11593
 
11594
 
11595
 
11596
 
11597
 
11598
 
11599
 
11600
 
11601
 
11602
 
11603
 
11604
 
11605
 
11606
 
11607
 
11608
 
11609
 
11610
 
11611
 
11612
 
11613
 
11614
 
11615
 
11616
 
11617
 
11618
 
11619
 
11620
 
11621
 
11622
 
11623
 
11624
 
11625
 
11626
 
11627
 
11628
 
11629
 
11630
 
11631
 
11632
 
11633
 
11634
 
11635
 
11636
 
11637
 
11638
 
11639
 
11640
 
11641
 
11642
 
11643
 
11644
 
11645
 
11646
 
11647
 
11648
 
11649
 
11650
 
11651
 
11652
 
11653
 
11654
 
11655
 
11656
 
11657
 
11658
 
11659
 
11660
 
11661
 
11662
 
11663
 
11664
 
11665
 
11666
 
11667
 
11668
 
11669
 
11670
 
11671
 
11672
 
11673
 
11674
 
11675
 
11676
 
11677
 
11678
 
11679
 
11680
 
11681
 
11682
 
11683
 
11684
 
11685
 
11686
 
11687
 
11688
 
11689
 
11690
 
11691
 
11692
 
11693
 
11694
 
11695
 
11696
 
11697
 
11698
 
11699
 
11700
 
11701
 
11702
 
11703
 
11704
 
11705
 
11706
 
11707
 
11708
 
11709
 
11710
 
11711
 
11712
 
11713
 
11714
 
11715
 
11716
 
11717
 
11718
 
11719
 
11720
 
11721
 
11722
 
11723
 
11724
 
11725
 
11726
 
11727
 
11728
 
11729
 
11730
 
11731
 
11732
 
11733
 
11734
 
11735
 
11736
 
11737
 
11738
 
11739
 
11740
 
11741
 
11742
 
11743
 
11744
 
11745
 
11746
 
11747
 
11748
 
11749
 
11750
 
11751
 
11752
 
11753
 
11754
 
11755
 
11756
 
11757
 
11758
 
11759
 
11760
 
11761
 
11762
 
11763
 
11764
 
11765
 
11766
 
11767
 
11768
 
11769
 
11770
 
11771
 
11772
 
11773
 
11774
 
11775
 
11776
 
11777
 
11778
 
11779
 
11780
 
11781
 
11782
 
11783
 
11784
 
11785
 
11786
 
11787
 
11788
 
11789
 
11790
 
11791
 
11792
 
11793
 
11794
 
11795
 
11796
 
11797
 
11798
 
11799
 
11800
 
11801
 
11802
 
11803
 
11804
 
11805
 
11806
 
11807
 
11808
 
11809
 
11810
 
11811
 
11812
 
11813
 
11814
 
11815
 
11816
 
11817
 
11818
 
11819
 
11820
 
11821
 
11822
 
11823
 
11824
 
11825
 
11826
 
11827
 
11828
 
11829
 
11830
 
11831
 
11832
 
11833
 
11834
 
11835
 
11836
 
11837
 
11838
 
11839
 
11840
 
11841
 
11842
 
11843
 
11844
 
11845
 
11846
 
11847
 
11848
 
11849
 
11850
 
11851
 
11852
 
11853
 
11854
 
11855
 
11856
 
11857
 
11858
 
11859
 
11860
 
11861
 
11862
 
11863
 
11864
 
11865
 
11866
 
11867
 
11868
 
11869
 
11870
 
11871
 
11872
 
11873
 
11874
 
11875
 
11876
 
11877
 
11878
 
11879
 
11880
 
11881
 
11882
 
11883
 
11884
 
11885
 
11886
 
11887
 
11888
 
11889
 
11890
 
11891
 
11892
 
11893
 
11894
 
11895
 
11896
 
11897
 
11898
 
11899
 
11900
 
11901
 
11902
 
11903
 
11904
 
11905
 
11906
 
11907
 
11908
 
11909
 
11910
 
11911
 
11912
 
11913
 
11914
 
11915
 
11916
 
11917
 
11918
 
11919
 
11920
 
11921
 
11922
 
11923
 
11924
 
11925
 
11926
 
11927
 
11928
 
11929
 
11930
 
11931
 
11932
 
11933
 
11934
 
11935
 
11936
 
11937
 
11938
 
11939
 
11940
 
11941
 
11942
 
11943
 
11944
 
11945
 
11946
 
11947
 
11948
 
11949
 
11950
 
11951
 
11952
 
11953
 
11954
 
11955
 
11956
 
11957
 
11958
 
11959
 
11960
 
11961
 
11962
 
11963
 
11964
 
11965
 
11966
 
11967
 
11968
 
11969
 
11970
 
11971
 
11972
 
11973
 
11974
 
11975
 
11976
 
11977
 
11978
 
11979
 
11980
 
11981
 
11982
 
11983
 
11984
 
11985
 
11986
 
11987
 
11988
 
11989
 
11990
 
11991
 
11992
 
11993
 
11994
 
11995
 
11996
 
11997
 
11998
 
11999
 
12000
 
12001
 
12002
 
12003
 
12004
 
12005
 
12006
 
12007
 
12008
 
12009
 
12010
 
12011
 
12012
 
12013
 
12014
 
12015
 
12016
 
12017
 
12018
 
12019
 
12020
 
12021
 
12022
 
12023
 
12024
 
12025
 
12026
 
12027
 
12028
 
12029
 
12030
 
12031
 
12032
 
12033
 
12034
 
12035
 
12036
 
12037
 
12038
 
12039
 
12040
 
12041
 
12042
 
12043
 
12044
 
12045
 
12046
 
12047
 
12048
 
12049
 
12050
 
12051
 
12052
 
12053
 
12054
 
12055
 
12056
 
12057
 
12058
 
12059
 
12060
 
12061
 
12062
 
12063
 
12064
 
12065
 
12066
 
12067
 
12068
 
12069
 
12070
 
12071
 
12072
 
12073
 
12074
 
12075
 
12076
 
12077
 
12078
 
12079
 
12080
 
12081
 
12082
 
12083
 
12084
 
12085
 
12086
 
12087
 
12088
 
12089
 
12090
 
12091
 
12092
 
12093
 
12094
 
12095
 
12096
 
12097
 
12098
 
12099
 
12100
 
12101
 
12102
 
12103
 
12104
 
12105
 
12106
 
12107
 
12108
 
12109
 
12110
 
12111
 
12112
 
12113
 
12114
 
12115
 
12116
 
12117
 
12118
 
12119
 
12120
 
12121
 
12122
 
12123
 
12124
 
12125
 
12126
 
12127
 
12128
 
12129
 
12130
 
12131
 
12132
 
12133
 
12134
 
12135
 
12136
 
12137
 
12138
 
12139
 
12140
 
12141
 
12142
 
12143
 
12144
 
12145
 
12146
 
12147
 
12148
 
12149
 
12150
 
12151
 
12152
 
12153
 
12154
 
12155
 
12156
 
12157
 
12158
 
12159
 
12160
 
12161
 
12162
 
12163
 
12164
 
12165
 
12166
 
12167
 
12168
 
12169
 
12170
 
12171
 
12172
 
12173
 
12174
 
12175
 
12176
 
12177
 
12178
 
12179
 
12180
 
12181
 
12182
 
12183
 
12184
 
12185
 
12186
 
12187
 
12188
 
12189
 
12190
 
12191
 
12192
 
12193
 
12194
 
12195
 
12196
 
12197
 
12198
 
12199
 
12200
 
12201
 
12202
 
12203
 
12204
 
12205
 
12206
 
12207
 
12208
 
12209
 
12210
 
12211
 
12212
 
12213
 
12214
 
12215
 
12216
 
12217
 
12218
 
12219
 
12220
 
12221
 
12222
 
12223
 
12224
 
12225
 
12226
 
12227
 
12228
 
12229
 
12230
 
12231
 
12232
 
12233
 
12234
 
12235
 
12236
 
12237
 
12238
 
12239
 
12240
 
12241
 
12242
 
12243
 
12244
 
12245
 
12246
 
12247
 
12248
 
12249
 
12250
 
12251
 
12252
 
12253
 
12254
 
12255
 
12256
 
12257
 
12258
 
12259
 
12260
 
12261
 
12262
 
12263
 
12264
 
12265
 
12266
 
12267
 
12268
 
12269
 
12270
 
12271
 
12272
 
12273
 
12274
 
12275
 
12276
 
12277
 
12278
 
12279
 
12280
 
12281
 
12282
 
12283
 
12284
 
12285
 
12286
 
12287
 
12288
 
12289
 
12290
 
12291
 
12292
 
12293
 
12294
 
12295
 
12296
 
12297
 
12298
 
12299
 
12300
 
12301
 
12302
 
12303
 
12304
 
12305
 
12306
 
12307
 
12308
 
12309
 
12310
 
12311
 
12312
 
12313
 
12314
 
12315
 
12316
 
12317
 
12318
 
12319
 
12320
 
12321
 
12322
 
12323
 
12324
 
12325
 
12326
 
12327
 
12328
 
12329
 
12330
 
12331
 
12332
 
12333
 
12334
 
12335
 
12336
 
12337
 
12338
 
12339
 
12340
 
12341
 
12342
 
12343
 
12344
 
12345
 
12346
 
12347
 
12348
 
12349
 
12350
 
12351
 
12352
 
12353
 
12354
 
12355
 
12356
 
12357
 
12358
 
12359
 
12360
 
12361
 
12362
 
12363
 
12364
 
12365
 
12366
 
12367
 
12368
 
12369
 
12370
 
12371
 
12372
 
12373
 
12374
 
12375
 
12376
 
12377
 
12378
 
12379
 
12380
 
12381
 
12382
 
12383
 
12384
 
12385
 
12386
 
12387
 
12388
 
12389
 
12390
 
12391
 
12392
 
12393
 
12394
 
12395
 
12396
 
12397
 
12398
 
12399
 
12400
 
12401
 
12402
 
12403
 
12404
 
12405
 
12406
 
12407
 
12408
 
12409
 
12410
 
12411
 
12412
 
12413
 
12414
 
12415
 
12416
 
12417
 
12418
 
12419
 
12420
 
12421
 
12422
 
12423
 
12424
 
12425
 
12426
 
12427
 
12428
 
12429
 
12430
 
12431
 
12432
 
12433
 
12434
 
12435
 
12436
 
12437
 
12438
 
12439
 
12440
 
12441
 
12442
 
12443
 
12444
 
12445
 
12446
 
12447
 
12448
 
12449
 
12450
 
12451
 
12452
 
12453
 
12454
 
12455
 
12456
 
12457
 
12458
 
12459
 
12460
 
12461
 
12462
 
12463
 
12464
 
12465
 
12466
 
12467
 
12468
 
12469
 
12470
 
12471
 
12472
 
12473
 
12474
 
12475
 
12476
 
12477
 
12478
 
12479
 
12480
 
12481
 
12482
 
12483
 
12484
 
12485
 
12486
 
12487
 
12488
 
12489
 
12490
 
12491
 
12492
 
12493
 
12494
 
12495
 
12496
 
12497
 
12498
 
12499
 
12500
 
12501
 
12502
 
12503
 
12504
 
12505
 
12506
 
12507
 
12508
 
12509
 
12510
 
12511
 
12512
 
12513
 
12514
 
12515
 
12516
 
12517
 
12518
 
12519
 
12520
 
12521
 
12522
 
12523
 
12524
 
12525
 
12526
 
12527
 
12528
 
12529
 
12530
 
12531
 
12532
 
12533
 
12534
 
12535
 
12536
 
12537
 
12538
 
12539
 
12540
 
12541
 
12542
 
12543
 
12544
 
12545
 
12546
 
12547
 
12548
 
12549
 
12550
 
12551
 
12552
 
12553
 
12554
 
12555
 
12556
 
12557
 
12558
 
12559
 
12560
 
12561
 
12562
 
12563
 
12564
 
12565
 
12566
 
12567
 
12568
 
12569
 
12570
 
12571
 
12572
 
12573
 
12574
 
12575
 
12576
 
12577
 
12578
 
12579
 
12580
 
12581
 
12582
 
12583
 
12584
 
12585
 
12586
 
12587
 
12588
 
12589
 
12590
 
12591
 
12592
 
12593
 
12594
 
12595
 
12596
 
12597
 
12598
 
12599
 
12600
 
12601
 
12602
 
12603
 
12604
 
12605
 
12606
 
12607
 
12608
 
12609
 
12610
 
12611
 
12612
 
12613
 
12614
 
12615
 
12616
 
12617
 
12618
 
12619
 
12620
 
12621
 
12622
 
12623
 
12624
 
12625
 
12626
 
12627
 
12628
 
12629
 
12630
 
12631
 
12632
 
12633
 
12634
 
12635
 
12636
 
12637
 
12638
 
12639
 
12640
 
12641
 
12642
 
12643
 
12644
 
12645
 
12646
 
12647
 
12648
 
12649
 
12650
 
12651
 
12652
 
12653
 
12654
 
12655
 
12656
 
12657
 
12658
 
12659
 
12660
 
12661
 
12662
 
12663
 
12664
 
12665
 
12666
 
12667
 
12668
 
12669
 
12670
 
12671
 
12672
 
12673
 
12674
 
12675
 
12676
 
12677
 
12678
 
12679
 
12680
 
12681
 
12682
 
12683
 
12684
 
12685
 
12686
 
12687
 
12688
 
12689
 
12690
 
12691
 
12692
 
12693
 
12694
 
12695
 
12696
 
12697
 
12698
 
12699
 
12700
 
12701
 
12702
 
12703
 
12704
 
12705
 
12706
 
12707
 
12708
 
12709
 
12710
 
12711
 
12712
 
12713
 
12714
 
12715
 
12716
 
12717
 
12718
 
12719
 
12720
 
12721
 
12722
 
12723
 
12724
 
12725
 
12726
 
12727
 
12728
 
12729
 
12730
 
12731
 
12732
 
12733
 
12734
 
12735
 
12736
 
12737
 
12738
 
12739
 
12740
 
12741
 
12742
 
12743
 
12744
 
12745
 
12746
 
12747
 
12748
 
12749
 
12750
 
12751
 
12752
 
12753
 
12754
 
12755
 
12756
 
12757
 
12758
 
12759
 
12760
 
12761
 
12762
 
12763
 
12764
 
12765
 
12766
 
12767
 
12768
 
12769
 
12770
 
12771
 
12772
 
12773
 
12774
 
12775
 
12776
 
12777
 
12778
 
12779
 
12780
 
12781
 
12782
 
12783
 
12784
 
12785
 
12786
 
12787
 
12788
 
12789
 
12790
 
12791
 
12792
 
12793
 
12794
 
12795
 
12796
 
12797
 
12798
 
12799
 
12800
 
12801
 
12802
 
12803
 
12804
 
12805
 
12806
 
12807
 
12808
 
12809
 
12810
 
12811
 
12812
 
12813
 
12814
 
12815
 
12816
 
12817
 
12818
 
12819
 
12820
 
12821
 
12822
 
12823
 
12824
 
12825
 
12826
 
12827
 
12828
 
12829
 
12830
 
12831
 
12832
 
12833
 
12834
 
12835
 
12836
 
12837
 
12838
 
12839
 
12840
 
12841
 
12842
 
12843
 
12844
 
12845
 
12846
 
12847
 
12848
 
12849
 
12850
 
12851
 
12852
 
12853
 
12854
 
12855
 
12856
 
12857
 
12858
 
12859
 
12860
 
12861
 
12862
 
12863
 
12864
 
12865
 
12866
 
12867
 
12868
 
12869
 
12870
 
12871
 
12872
 
12873
 
12874
 
12875
 
12876
 
12877
 
12878
 
12879
 
12880
 
12881
 
12882
 
12883
 
12884
 
12885
 
12886
 
12887
 
12888
 
12889
 
12890
 
12891
 
12892
 
12893
 
12894
 
12895
 
12896
 
12897
 
12898
 
12899
 
12900
 
12901
 
12902
 
12903
 
12904
 
12905
 
12906
 
12907
 
12908
 
12909
 
12910
 
12911
 
12912
 
12913
 
12914
 
12915
 
12916
 
12917
 
12918
 
12919
 
12920
 
12921
 
12922
 
12923
 
12924
 
12925
 
12926
 
12927
 
12928
 
12929
 
12930
 
12931
 
12932
 
12933
 
12934
 
12935
 
12936
 
12937
 
12938
 
12939
 
12940
 
12941
 
12942
 
12943
 
12944
 
12945
 
12946
 
12947
 
12948
 
12949
 
12950
 
12951
 
12952
 
12953
 
12954
 
12955
 
12956
 
12957
 
12958
 
12959
 
12960
 
12961
 
12962
 
12963
 
12964
 
12965
 
12966
 
12967
 
12968
 
12969
 
12970
 
12971
 
12972
 
12973
 
12974
 
12975
 
12976
 
12977
 
12978
 
12979
 
12980
 
12981
 
12982
 
12983
 
12984
 
12985
 
12986
 
12987
 
12988
 
12989
 
12990
 
12991
 
12992
 
12993
 
12994
 
12995
 
12996
 
12997
 
12998
 
12999
 
13000
 
13001
 
13002
 
13003
 
13004
 
13005
 
13006
 
13007
 
13008
 
13009
 
13010
 
13011
 
13012
 
13013
 
13014
 
13015
 
13016
 
13017
 
13018
 
13019
 
13020
 
13021
 
13022
 
13023
 
13024
 
13025
 
13026
 
13027
 
13028
 
13029
 
13030
 
13031
 
13032
 
13033
 
13034
 
13035
 
13036
 
13037
 
13038
 
13039
 
13040
 
13041
 
13042
 
13043
 
13044
 
13045
 
13046
 
13047
 
13048
 
13049
 
13050
 
13051
 
13052
 
13053
 
13054
 
13055
 
13056
 
13057
 
13058
 
13059
 
13060
 
13061
 
13062
 
13063
 
13064
 
13065
 
13066
 
13067
 
13068
 
13069
 
13070
 
13071
 
13072
 
13073
 
13074
 
13075
 
13076
 
13077
 
13078
 
13079
 
13080
 
13081
 
13082
 
13083
 
13084
 
13085
 
13086
 
13087
 
13088
 
13089
 
13090
 
13091
 
13092
 
13093
 
13094
 
13095
 
13096
 
13097
 
13098
 
13099
 
13100
 
13101
 
13102
 
13103
 
13104
 
13105
 
13106
 
13107
 
13108
 
13109
 
13110
 
13111
 
13112
 
13113
 
13114
 
13115
 
13116
 
13117
 
13118
 
13119
 
13120
 
13121
 
13122
 
13123
 
13124
 
13125
 
13126
 
13127
 
13128
 
13129
 
13130
 
13131
 
13132
 
13133
 
13134
 
13135
 
13136
 
13137
 
13138
 
13139
 
13140
 
13141
 
13142
 
13143
 
13144
 
13145
 
13146
 
13147
 
13148
 
13149
 
13150
 
13151
 
13152
 
13153
 
13154
 
13155
 
13156
 
13157
 
13158
 
13159
 
13160
 
13161
 
13162
 
13163
 
13164
 
13165
 
13166
 
13167
 
13168
 
13169
 
13170
 
13171
 
13172
 
13173
 
13174
 
13175
 
13176
 
13177
 
13178
 
13179
 
13180
 
13181
 
13182
 
13183
 
13184
 
13185
 
13186
 
13187
 
13188
 
13189
 
13190
 
13191
 
13192
 
13193
 
13194
 
13195
 
13196
 
13197
 
13198
 
13199
 
13200
 
13201
 
13202
 
13203
 
13204
 
13205
 
13206
 
13207
 
13208
 
13209
 
13210
 
13211
 
13212
 
13213
 
13214
 
13215
 
13216
 
13217
 
13218
 
13219
 
13220
 
13221
 
13222
 
13223
 
13224
 
13225
 
13226
 
13227
 
13228
 
13229
 
13230
 
13231
 
13232
 
13233
 
13234
 
13235
 
13236
 
13237
 
13238
 
13239
 
13240
 
13241
 
13242
 
13243
 
13244
 
13245
 
13246
 
13247
 
13248
 
13249
 
13250
 
13251
 
13252
 
13253
 
13254
 
13255
 
13256
 
13257
 
13258
 
13259
 
13260
 
13261
 
13262
 
13263
 
13264
 
13265
 
13266
 
13267
 
13268
 
13269
 
13270
 
13271
 
13272
 
13273
 
13274
 
13275
 
13276
 
13277
 
13278
 
13279
 
13280
 
13281
 
13282
 
13283
 
13284
 
13285
 
13286
 
13287
 
13288
 
13289
 
13290
 
13291
 
13292
 
13293
 
13294
 
13295
 
13296
 
13297
 
13298
 
13299
 
13300
 
13301
 
13302
 
13303
 
13304
 
13305
 
13306
 
13307
 
13308
 
13309
 
13310
 
13311
 
13312
 
13313
 
13314
 
13315
 
13316
 
13317
 
13318
 
13319
 
13320
 
13321
 
13322
 
13323
 
13324
 
13325
 
13326
 
13327
 
13328
 
13329
 
13330
 
13331
 
13332
 
13333
 
13334
 
13335
 
13336
 
13337
 
13338
 
13339
 
13340
 
13341
 
13342
 
13343
 
13344
 
13345
 
13346
 
13347
 
13348
 
13349
 
13350
 
13351
 
13352
 
13353
 
13354
 
13355
 
13356
 
13357
 
13358
 
13359
 
13360
 
13361
 
13362
 
13363
 
13364
 
13365
 
13366
 
13367
 
13368
 
13369
 
13370
 
13371
 
13372
 
13373
 
13374
 
13375
 
13376
 
13377
 
13378
 
13379
 
13380
 
13381
 
13382
 
13383
 
13384
 
13385
 
13386
 
13387
 
13388
 
13389
 
13390
 
13391
 
13392
 
13393
 
13394
 
13395
 
13396
 
13397
 
13398
 
13399
 
13400
 
13401
 
13402
 
13403
 
13404
 
13405
 
13406
 
13407
 
13408
 
13409
 
13410
 
13411
 
13412
 
13413
 
13414
 
13415
 
13416
 
13417
 
13418
 
13419
 
13420
 
13421
 
13422
 
13423
 
13424
 
13425
 
13426
 
13427
 
13428
 
13429
 
13430
 
13431
 
13432
 
13433
 
13434
 
13435
 
13436
 
13437
 
13438
 
13439
 
13440
 
13441
 
13442
 
13443
 
13444
 
13445
 
13446
 
13447
 
13448
 
13449
 
13450
 
13451
 
13452
 
13453
 
13454
 
13455
 
13456
 
13457
 
13458
 
13459
 
13460
 
13461
 
13462
 
13463
 
13464
 
13465
 
13466
 
13467
 
13468
 
13469
 
13470
 
13471
 
13472
 
13473
 
13474
 
13475
 
13476
 
13477
 
13478
 
13479
 
13480
 
13481
 
13482
 
13483
 
13484
 
13485
 
13486
 
13487
 
13488
 
13489
 
13490
 
13491
 
13492
 
13493
 
13494
 
13495
 
13496
 
13497
 
13498
 
13499
 
13500
 
13501
 
13502
 
13503
 
13504
 
13505
 
13506
 
13507
 
13508
 
13509
 
13510
 
13511
 
13512
 
13513
 
13514
 
13515
 
13516
 
13517
 
13518
 
13519
 
13520
 
13521
 
13522
 
13523
 
13524
 
13525
 
13526
 
13527
 
13528
 
13529
 
13530
 
13531
 
13532
 
13533
 
13534
 
13535
 
13536
 
13537
 
13538
 
13539
 
13540
 
13541
 
13542
 
13543
 
13544
 
13545
 
13546
 
13547
 
13548
 
13549
 
13550
 
13551
 
13552
 
13553
 
13554
 
13555
 
13556
 
13557
 
13558
 
13559
 
13560
 
13561
 
13562
 
13563
 
13564
 
13565
 
13566
 
13567
 
13568
 
13569
 
13570
 
13571
 
13572
 
13573
 
13574
 
13575
 
13576
 
13577
 
13578
 
13579
 
13580
 
13581
 
13582
 
13583
 
13584
 
13585
 
13586
 
13587
 
13588
 
13589
 
13590
 
13591
 
13592
 
13593
 
13594
 
13595
 
13596
 
13597
 
13598
 
13599
 
13600
 
13601
 
13602
 
13603
 
13604
 
13605
 
13606
 
13607
 
13608
 
13609
 
13610
 
13611
 
13612
 
13613
 
13614
 
13615
 
13616
 
13617
 
13618
 
13619
 
13620
 
13621
 
13622
 
13623
 
13624
 
13625
 
13626
 
13627
 
13628
 
13629
 
13630
 
13631
 
13632
 
13633
 
13634
 
13635
 
13636
 
13637
 
13638
 
13639
 
13640
 
13641
 
13642
 
13643
 
13644
 
13645
 
13646
 
13647
 
13648
 
13649
 
13650
 
13651
 
13652
 
13653
 
13654
 
13655
 
13656
 
13657
 
13658
 
13659
 
13660
 
13661
 
13662
 
13663
 
13664
 
13665
 
13666
 
13667
 
13668
 
13669
 
13670
 
13671
 
13672
 
13673
 
13674
 
13675
 
13676
 
13677
 
13678
 
13679
 
13680
 
13681
 
13682
 
13683
 
13684
 
13685
 
13686
 
13687
 
13688
 
13689
 
13690
 
13691
 
13692
 
13693
 
13694
 
13695
 
13696
 
13697
 
13698
 
13699
 
13700
 
13701
 
13702
 
13703
 
13704
 
13705
 
13706
 
13707
 
13708
 
13709
 
13710
 
13711
 
13712
 
13713
 
13714
 
13715
 
13716
 
13717
 
13718
 
13719
 
13720
 
13721
 
13722
 
13723
 
13724
 
13725
 
13726
 
13727
 
13728
 
13729
 
13730
 
13731
 
13732
 
13733
 
13734
 
13735
 
13736
 
13737
 
13738
 
13739
 
13740
 
13741
 
13742
 
13743
 
13744
 
13745
 
13746
 
13747
 
13748
 
13749
 
13750
 
13751
 
13752
 
13753
 
13754
 
13755
 
13756
 
13757
 
13758
 
13759
 
13760
 
13761
 
13762
 
13763
 
13764
 
13765
 
13766
 
13767
 
13768
 
13769
 
13770
 
13771
 
13772
 
13773
 
13774
 
13775
 
13776
 
13777
 
13778
 
13779
 
13780
 
13781
 
13782
 
13783
 
13784
 
13785
 
13786
 
13787
 
13788
 
13789
 
13790
 
13791
 
13792
 
13793
 
13794
 
13795
 
13796
 
13797
 
13798
 
13799
 
13800
 
13801
 
13802
 
13803
 
13804
 
13805
 
13806
 
13807
 
13808
 
13809
 
13810
 
13811
 
13812
 
13813
 
13814
 
13815
 
13816
 
13817
 
13818
 
13819
 
13820
 
13821
 
13822
 
13823
 
13824
 
13825
 
13826
 
13827
 
13828
 
13829
 
13830
 
13831
 
13832
 
13833
 
13834
 
13835
 
13836
 
13837
 
13838
 
13839
 
13840
 
13841
 
13842
 
13843
 
13844
 
13845
 
13846
 
13847
 
13848
 
13849
 
13850
 
13851
 
13852
 
13853
 
13854
 
13855
 
13856
 
13857
 
13858
 
13859
 
13860
 
13861
 
13862
 
13863
 
13864
 
13865
 
13866
 
13867
 
13868
 
13869
 
13870
 
13871
 
13872
 
13873
 
13874
 
13875
 
13876
 
13877
 
13878
 
13879
 
13880
 
13881
 
13882
 
13883
 
13884
 
13885
 
13886
 
13887
 
13888
 
13889
 
13890
 
13891
 
13892
 
13893
 
13894
 
13895
 
13896
 
13897
 
13898
 
13899
 
13900
 
13901
 
13902
 
13903
 
13904
 
13905
 
13906
 
13907
 
13908
 
13909
 
13910
 
13911
 
13912
 
13913
 
13914
 
13915
 
13916
 
13917
 
13918
 
13919
 
13920
 
13921
 
13922
 
13923
 
13924
 
13925
 
13926
 
13927
 
13928
 
13929
 
13930
 
13931
 
13932
 
13933
 
13934
 
13935
 
13936
 
13937
 
13938
 
13939
 
13940
 
13941
 
13942
 
13943
 
13944
 
13945
 
13946
 
13947
 
13948
 
13949
 
13950
 
13951
 
13952
 
13953
 
13954
 
13955
 
13956
 
13957
 
13958
 
13959
 
13960
 
13961
 
13962
 
13963
 
13964
 
13965
 
13966
 
13967
 
13968
 
13969
 
13970
 
13971
 
13972
 
13973
 
13974
 
13975
 
13976
 
13977
 
13978
 
13979
 
13980
 
13981
 
13982
 
13983
 
13984
 
13985
 
13986
 
13987
 
13988
 
13989
 
13990
 
13991
 
13992
 
13993
 
13994
 
13995
 
13996
 
13997
 
13998
 
13999
 
14000
 
14001
 
14002
 
14003
 
14004
 
14005
 
14006
 
14007
 
14008
 
14009
 
14010
 
14011
 
14012
 
14013
 
14014
 
14015
 
14016
 
14017
 
14018
 
14019
 
14020
 
14021
 
14022
 
14023
 
14024
 
14025
 
14026
 
14027
 
14028
 
14029
 
14030
 
14031
 
14032
 
14033
 
14034
 
14035
 
14036
 
14037
 
14038
 
14039
 
14040
 
14041
 
14042
 
14043
 
14044
 
14045
 
14046
 
14047
 
14048
 
14049
 
14050
 
14051
 
14052
 
14053
 
14054
 
14055
 
14056
 
14057
 
14058
 
14059
 
14060
 
14061
 
14062
 
14063
 
14064
 
14065
 
14066
 
14067
 
14068
 
14069
 
14070
 
14071
 
14072
 
14073
 
14074
 
14075
 
14076
 
14077
 
14078
 
14079
 
14080
 
14081
 
14082
 
14083
 
14084
 
14085
 
14086
 
14087
 
14088
 
14089
 
14090
 
14091
 
14092
 
14093
 
14094
 
14095
 
14096
 
14097
 
14098
 
14099
 
14100
 
14101
 
14102
 
14103
 
14104
 
14105
 
14106
 
14107
 
14108
 
14109
 
14110
 
14111
 
14112
 
14113
 
14114
 
14115
 
14116
 
14117
 
14118
 
14119
 
14120
 
14121
 
14122
 
14123
 
14124
 
14125
 
14126
 
14127
 
14128
 
14129
 
14130
 
14131
 
14132
 
14133
 
14134
 
14135
 
14136
 
14137
 
14138
 
14139
 
14140
 
14141
 
14142
 
14143
 
14144
 
14145
 
14146
 
14147
 
14148
 
14149
 
14150
 
14151
 
14152
 
14153
 
14154
 
14155
 
14156
 
14157
 
14158
 
14159
 
14160
 
14161
 
14162
 
14163
 
14164
 
14165
 
14166
 
14167
 
14168
 
14169
 
14170
 
14171
 
14172
 
14173
 
14174
 
14175
 
14176
 
14177
 
14178
 
14179
 
14180
 
14181
 
14182
 
14183
 
14184
 
14185
 
14186
 
14187
 
14188
 
14189
 
14190
 
14191
 
14192
 
14193
 
14194
 
14195
 
14196
 
14197
 
14198
 
14199
 
14200
 
14201
 
14202
 
14203
 
14204
 
14205
 
14206
 
14207
 
14208
 
14209
 
14210
 
14211
 
14212
 
14213
 
14214
 
14215
 
14216
 
14217
 
14218
 
14219
 
14220
 
14221
 
14222
 
14223
 
14224
 
14225
 
14226
 
14227
 
14228
 
14229
 
14230
 
14231
 
14232
 
14233
 
14234
 
14235
 
14236
 
14237
 
14238
 
14239
 
14240
 
14241
 
14242
 
14243
 
14244
 
14245
 
14246
 
14247
 
14248
 
14249
 
14250
 
14251
 
14252
 
14253
 
14254
 
14255
 
14256
 
14257
 
14258
 
14259
 
14260
 
14261
 
14262
 
14263
 
14264
 
14265
 
14266
 
14267
 
14268
 
14269
 
14270
 
14271
 
14272
 
14273
 
14274
 
14275
 
14276
 
14277
 
14278
 
14279
 
14280
 
14281
 
14282
 
14283
 
14284
 
14285
 
14286
 
14287
 
14288
 
14289
 
14290
 
14291
 
14292
 
14293
 
14294
 
14295
 
14296
 
14297
 
14298
 
14299
 
14300
 
14301
 
14302
 
14303
 
14304
 
14305
 
14306
 
14307
 
14308
 
14309
 
14310
 
14311
 
14312
 
14313
 
14314
 
14315
 
14316
 
14317
 
14318
 
14319
 
14320
 
14321
 
14322
 
14323
 
14324
 
14325
 
14326
 
14327
 
14328
 
14329
 
14330
 
14331
 
14332
 
14333
 
14334
 
14335
 
14336
 
14337
 
14338
 
14339
 
14340
 
14341
 
14342
 
14343
 
14344
 
14345
 
14346
 
14347
 
14348
 
14349
 
14350
 
14351
 
14352
 
14353
 
14354
 
14355
 
14356
 
14357
 
14358
 
14359
 
14360
 
14361
 
14362
 
14363
 
14364
 
14365
 
14366
 
14367
 
14368
 
14369
 
14370
 
14371
 
14372
 
14373
 
14374
 
14375
 
14376
 
14377
 
14378
 
14379
 
14380
 
14381
 
14382
 
14383
 
14384
 
14385
 
14386
 
14387
 
14388
 
14389
 
14390
 
14391
 
14392
 
14393
 
14394
 
14395
 
14396
 
14397
 
14398
 
14399
 
14400
 
14401
 
14402
 
14403
 
14404
 
14405
 
14406
 
14407
 
14408
 
14409
 
14410
 
14411
 
14412
 
14413
 
14414
 
14415
 
14416
 
14417
 
14418
 
14419
 
14420
 
14421
 
14422
 
14423
 
14424
 
14425
 
14426
 
14427
 
14428
 
14429
 
14430
 
14431
 
14432
 
14433
 
14434
 
14435
 
14436
 
14437
 
14438
 
14439
 
14440
 
14441
 
14442
 
14443
 
14444
 
14445
 
14446
 
14447
 
14448
 
14449
 
14450
 
14451
 
14452
 
14453
 
14454
 
14455
 
14456
 
14457
 
14458
 
14459
 
14460
 
14461
 
14462
 
14463
 
14464
 
14465
 
14466
 
14467
 
14468
 
14469
 
14470
 
14471
 
14472
 
14473
 
14474
 
14475
 
14476
 
14477
 
14478
 
14479
 
14480
 
14481
 
14482
 
14483
 
14484
 
14485
 
14486
 
14487
 
14488
 
14489
 
14490
 
14491
 
14492
 
14493
 
14494
 
14495
 
14496
 
14497
 
14498
 
14499
 
14500
 
14501
 
14502
 
14503
 
14504
 
14505
 
14506
 
14507
 
14508
 
14509
 
14510
 
14511
 
14512
 
14513
 
14514
 
14515
 
14516
 
14517
 
14518
 
14519
 
14520
 
14521
 
14522
 
14523
 
14524
 
14525
 
14526
 
14527
 
14528
 
14529
 
14530
 
14531
 
14532
 
14533
 
14534
 
14535
 
14536
 
14537
 
14538
 
14539
 
14540
 
14541
 
14542
 
14543
 
14544
 
14545
 
14546
 
14547
 
14548
 
14549
 
14550
 
14551
 
14552
 
14553
 
14554
 
14555
 
14556
 
14557
 
14558
 
14559
 
14560
 
14561
 
14562
 
14563
 
14564
 
14565
 
14566
 
14567
 
14568
 
14569
 
14570
 
14571
 
14572
 
14573
 
14574
 
14575
 
14576
 
14577
 
14578
 
14579
 
14580
 
14581
 
14582
 
14583
 
14584
 
14585
 
14586
 
14587
 
14588
 
14589
 
14590
 
14591
 
14592
 
14593
 
14594
 
14595
 
14596
 
14597
 
14598
 
14599
 
14600
 
14601
 
14602
 
14603
 
14604
 
14605
 
14606
 
14607
 
14608
 
14609
 
14610
 
14611
 
14612
 
14613
 
14614
 
14615
 
14616
 
14617
 
14618
 
14619
 
14620
 
14621
 
14622
 
14623
 
14624
 
14625
 
14626
 
14627
 
14628
 
14629
 
14630
 
14631
 
14632
 
14633
 
14634
 
14635
 
14636
 
14637
 
14638
 
14639
 
14640
 
14641
 
14642
 
14643
 
14644
 
14645
 
14646
 
14647
 
14648
 
14649
 
14650
 
14651
 
14652
 
14653
 
14654
 
14655
 
14656
 
14657
 
14658
 
14659
 
14660
 
14661
 
14662
 
14663
 
14664
 
14665
 
14666
 
14667
 
14668
 
14669
 
14670
 
14671
 
14672
 
14673
 
14674
 
14675
 
14676
 
14677
 
14678
 
14679
 
14680
 
14681
 
14682
 
14683
 
14684
 
14685
 
14686
 
14687
 
14688
 
14689
 
14690
 
14691
 
14692
 
14693
 
14694
 
14695
 
14696
 
14697
 
14698
 
14699
 
14700
 
14701
 
14702
 
14703
 
14704
 
14705
 
14706
 
14707
 
14708
 
14709
 
14710
 
14711
 
14712
 
14713
 
14714
 
14715
 
14716
 
14717
 
14718
 
14719
 
14720
 
14721
 
14722
 
14723
 
14724
 
14725
 
14726
 
14727
 
14728
 
14729
 
14730
 
14731
 
14732
 
14733
 
14734
 
14735
 
14736
 
14737
 
14738
 
14739
 
14740
 
14741
 
14742
 
14743
 
14744
 
14745
 
14746
 
14747
 
14748
 
14749
 
14750
 
14751
 
14752
 
14753
 
14754
 
14755
 
14756
 
14757
 
14758
 
14759
 
14760
 
14761
 
14762
 
14763
 
14764
 
14765
 
14766
 
14767
 
14768
 
14769
 
14770
 
14771
 
14772
 
14773
 
14774
 
14775
 
14776
 
14777
 
14778
 
14779
 
14780
 
14781
 
14782
 
14783
 
14784
 
14785
 
14786
 
14787
 
14788
 
14789
 
14790
 
14791
 
14792
 
14793
 
14794
 
14795
 
14796
 
14797
 
14798
 
14799
 
14800
 
14801
 
14802
 
14803
 
14804
 
14805
 
14806
 
14807
 
14808
 
14809
 
14810
 
14811
 
14812
 
14813
 
14814
 
14815
 
14816
 
14817
 
14818
 
14819
 
14820
 
14821
 
14822
 
14823
 
14824
 
14825
 
14826
 
14827
 
14828
 
14829
 
14830
 
14831
 
14832
 
14833
 
14834
 
14835
 
14836
 
14837
 
14838
 
14839
 
14840
 
14841
 
14842
 
14843
 
14844
 
14845
 
14846
 
14847
 
14848
 
14849
 
14850
 
14851
 
14852
 
14853
 
14854
 
14855
 
14856
 
14857
 
14858
 
14859
 
14860
 
14861
 
14862
 
14863
 
14864
 
14865
 
14866
 
14867
 
14868
 
14869
 
14870
 
14871
 
14872
 
14873
 
14874
 
14875
 
14876
 
14877
 
14878
 
14879
 
14880
 
14881
 
14882
 
14883
 
14884
 
14885
 
14886
 
14887
 
14888
 
14889
 
14890
 
14891
 
14892
 
14893
 
14894
 
14895
 
14896
 
14897
 
14898
 
14899
 
14900
 
14901
 
14902
 
14903
 
14904
 
14905
 
14906
 
14907
 
14908
 
14909
 
14910
 
14911
 
14912
 
14913
 
14914
 
14915
 
14916
 
14917
 
14918
 
14919
 
14920
 
14921
 
14922
 
14923
 
14924
 
14925
 
14926
 
14927
 
14928
 
14929
 
14930
 
14931
 
14932
 
14933
 
14934
 
14935
 
14936
 
14937
 
14938
 
14939
 
14940
 
14941
 
14942
 
14943
 
14944
 
14945
 
14946
 
14947
 
14948
 
14949
 
14950
 
14951
 
14952
 
14953
 
14954
 
14955
 
14956
 
14957
 
14958
 
14959
 
14960
 
14961
 
14962
 
14963
 
14964
 
14965
 
14966
 
14967
 
14968
 
14969
 
14970
 
14971
 
14972
 
14973
 
14974
 
14975
 
14976
 
14977
 
14978
 
14979
 
14980
 
14981
 
14982
 
14983
 
14984
 
14985
 
14986
 
14987
 
14988
 
14989
 
14990
 
14991
 
14992
 
14993
 
14994
 
14995
 
14996
 
14997
 
14998
 
14999
 
15000
 
15001
 
15002
 
15003
 
15004
 
15005
 
15006
 
15007
 
15008
 
15009
 
15010
 
15011
 
15012
 
15013
 
15014
 
15015
 
15016
 
15017
 
15018
 
15019
 
15020
 
15021
 
15022
 
15023
 
15024
 
15025
 
15026
 
15027
 
15028
 
15029
 
15030
 
15031
 
15032
 
15033
 
15034
 
15035
 
15036
 
15037
 
15038
 
15039
 
15040
 
15041
 
15042
 
15043
 
15044
 
15045
 
15046
 
15047
 
15048
 
15049
 
15050
 
15051
 
15052
 
15053
 
15054
 
15055
 
15056
 
15057
 
15058
 
15059
 
15060
 
15061
 
15062
 
15063
 
15064
 
15065
 
15066
 
15067
 
15068
 
15069
 
15070
 
15071
 
15072
 
15073
 
15074
 
15075
 
15076
 
15077
 
15078
 
15079
 
15080
 
15081
 
15082
 
15083
 
15084
 
15085
 
15086
 
15087
 
15088
 
15089
 
15090
 
15091
 
15092
 
15093
 
15094
 
15095
 
15096
 
15097
 
15098
 
15099
 
15100
 
15101
 
15102
 
15103
 
15104
 
15105
 
15106
 
15107
 
15108
 
15109
 
15110
 
15111
 
15112
 
15113
 
15114
 
15115
 
15116
 
15117
 
15118
 
15119
 
15120
 
15121
 
15122
 
15123
 
15124
 
15125
 
15126
 
15127
 
15128
 
15129
 
15130
 
15131
 
15132
 
15133
 
15134
 
15135
 
15136
 
15137
 
15138
 
15139
 
15140
 
15141
 
15142
 
15143
 
15144
 
15145
 
15146
 
15147
 
15148
 
15149
 
15150
 
15151
 
15152
 
15153
 
15154
 
15155
 
15156
 
15157
 
15158
 
15159
 
15160
 
15161
 
15162
 
15163
 
15164
 
15165
 
15166
 
15167
 
15168
 
15169
 
15170
 
15171
 
15172
 
15173
 
15174
 
15175
 
15176
 
15177
 
15178
 
15179
 
15180
 
15181
 
15182
 
15183
 
15184
 
15185
 
15186
 
15187
 
15188
 
15189
 
15190
 
15191
 
15192
 
15193
 
15194
 
15195
 
15196
 
15197
 
15198
 
15199
 
15200
 
15201
 
15202
 
15203
 
15204
 
15205
 
15206
 
15207
 
15208
 
15209
 
15210
 
15211
 
15212
 
15213
 
15214
 
15215
 
15216
 
15217
 
15218
 
15219
 
15220
 
15221
 
15222
 
15223
 
15224
 
15225
 
15226
 
15227
 
15228
 
15229
 
15230
 
15231
 
15232
 
15233
 
15234
 
15235
 
15236
 
15237
 
15238
 
15239
 
15240
 
15241
 
15242
 
15243
 
15244
 
15245
 
15246
 
15247
 
15248
 
15249
 
15250
 
15251
 
15252
 
15253
 
15254
 
15255
 
15256
 
15257
 
15258
 
15259
 
15260
 
15261
 
15262
 
15263
 
15264
 
15265
 
15266
 
15267
 
15268
 
15269
 
15270
 
15271
 
15272
 
15273
 
15274
 
15275
 
15276
 
15277
 
15278
 
15279
 
15280
 
15281
 
15282
 
15283
 
15284
 
15285
 
15286
 
15287
 
15288
 
15289
 
15290
 
15291
 
15292
 
15293
 
15294
 
15295
 
15296
 
15297
 
15298
 
15299
 
15300
 
15301
 
15302
 
15303
 
15304
 
15305
 
15306
 
15307
 
15308
 
15309
 
15310
 
15311
 
15312
 
15313
 
15314
 
15315
 
15316
 
15317
 
15318
 
15319
 
15320
 
15321
 
15322
 
15323
 
15324
 
15325
 
15326
 
15327
 
15328
 
15329
 
15330
 
15331
 
15332
 
15333
 
15334
 
15335
 
15336
 
15337
 
15338
 
15339
 
15340
 
15341
 
15342
 
15343
 
15344
 
15345
 
15346
 
15347
 
15348
 
15349
 
15350
 
15351
 
15352
 
15353
 
15354
 
15355
 
15356
 
15357
 
15358
 
15359
 
15360
 
15361
 
15362
 
15363
 
15364
 
15365
 
15366
 
15367
 
15368
 
15369
 
15370
 
15371
 
15372
 
15373
 
15374
 
15375
 
15376
 
15377
 
15378
 
15379
 
15380
 
15381
 
15382
 
15383
 
15384
 
15385
 
15386
 
15387
 
15388
 
15389
 
15390
 
15391
 
15392
 
15393
 
15394
 
15395
 
15396
 
15397
 
15398
 
15399
 
15400
 
15401
 
15402
 
15403
 
15404
 
15405
 
15406
 
15407
 
15408
 
15409
 
15410
 
15411
 
15412
 
15413
 
15414
 
15415
 
15416
 
15417
 
15418
 
15419
 
15420
 
15421
 
15422
 
15423
 
15424
 
15425
 
15426
 
15427
 
15428
 
15429
 
15430
 
15431
 
15432
 
15433
 
15434
 
15435
 
15436
 
15437
 
15438
 
15439
 
15440
 
15441
 
15442
 
15443
 
15444
 
15445
 
15446
 
15447
 
15448
 
15449
 
15450
 
15451
 
15452
 
15453
 
15454
 
15455
 
15456
 
15457
 
15458
 
15459
 
15460
 
15461
 
15462
 
15463
 
15464
 
15465
 
15466
 
15467
 
15468
 
15469
 
15470
 
15471
 
15472
 
15473
 
15474
 
15475
 
15476
 
15477
 
15478
 
15479
 
15480
 
15481
 
15482
 
15483
 
15484
 
15485
 
15486
 
15487
 
15488
 
15489
 
15490
 
15491
 
15492
 
15493
 
15494
 
15495
 
15496
 
15497
 
15498
 
15499
 
15500
 
15501
 
15502
 
15503
 
15504
 
15505
 
15506
 
15507
 
15508
 
15509
 
15510
 
15511
 
15512
 
15513
 
15514
 
15515
 
15516
 
15517
 
15518
 
15519
 
15520
 
15521
 
15522
 
15523
 
15524
 
15525
 
15526
 
15527
 
15528
 
15529
 
15530
 
15531
 
15532
 
15533
 
15534
 
15535
 
15536
 
15537
 
15538
 
15539
 
15540
 
15541
 
15542
 
15543
 
15544
 
15545
 
15546
 
15547
 
15548
 
15549
 
15550
 
15551
 
15552
 
15553
 
15554
 
15555
 
15556
 
15557
 
15558
 
15559
 
15560
 
15561
 
15562
 
15563
 
15564
 
15565
 
15566
 
15567
 
15568
 
15569
 
15570
 
15571
 
15572
 
15573
 
15574
 
15575
 
15576
 
15577
 
15578
 
15579
 
15580
 
15581
 
15582
 
15583
 
15584
 
15585
 
15586
 
15587
 
15588
 
15589
 
15590
 
15591
 
15592
 
15593
 
15594
 
15595
 
15596
 
15597
 
15598
 
15599
 
15600
 
15601
 
15602
 
15603
 
15604
 
15605
 
15606
 
15607
 
15608
 
15609
 
15610
 
15611
 
15612
 
15613
 
15614
 
15615
 
15616
 
15617
 
15618
 
15619
 
15620
 
15621
 
15622
 
15623
 
15624
 
15625
 
15626
 
15627
 
15628
 
15629
 
15630
 
15631
 
15632
 
15633
 
15634
 
15635
 
15636
 
15637
 
15638
 
15639
 
15640
 
15641
 
15642
 
15643
 
15644
 
15645
 
15646
 
15647
 
15648
 
15649
 
15650
 
15651
 
15652
 
15653
 
15654
 
15655
 
15656
 
15657
 
15658
 
15659
 
15660
 
15661
 
15662
 
15663
 
15664
 
15665
 
15666
 
15667
 
15668
 
15669
 
15670
 
15671
 
15672
 
15673
 
15674
 
15675
 
15676
 
15677
 
15678
 
15679
 
15680
 
15681
 
15682
 
15683
 
15684
 
15685
 
15686
 
15687
 
15688
 
15689
 
15690
 
15691
 
15692
 
15693
 
15694
 
15695
 
15696
 
15697
 
15698
 
15699
 
15700
 
15701
 
15702
 
15703
 
15704
 
15705
 
15706
 
15707
 
15708
 
15709
 
15710
 
15711
 
15712
 
15713
 
15714
 
15715
 
15716
 
15717
 
15718
 
15719
 
15720
 
15721
 
15722
 
15723
 
15724
 
15725
 
15726
 
15727
 
15728
 
15729
 
15730
 
15731
 
15732
 
15733
 
15734
 
15735
 
15736
 
15737
 
15738
 
15739
 
15740
 
15741
 
15742
 
15743
 
15744
 
15745
 
15746
 
15747
 
15748
 
15749
 
15750
 
15751
 
15752
 
15753
 
15754
 
15755
 
15756
 
15757
 
15758
 
15759
 
15760
 
15761
 
15762
 
15763
 
15764
 
15765
 
15766
 
15767
 
15768
 
15769
 
15770
 
15771
 
15772
 
15773
 
15774
 
15775
 
15776
 
15777
 
15778
 
15779
 
15780
 
15781
 
15782
 
15783
 
15784
 
15785
 
15786
 
15787
 
15788
 
15789
 
15790
 
15791
 
15792
 
15793
 
15794
 
15795
 
15796
 
15797
 
15798
 
15799
 
15800
 
15801
 
15802
 
15803
 
15804
 
15805
 
15806
 
15807
 
15808
 
15809
 
15810
 
15811
 
15812
 
15813
 
15814
 
15815
 
15816
 
15817
 
15818
 
15819
 
15820
 
15821
 
15822
 
15823
 
15824
 
15825
 
15826
 
15827
 
15828
 
15829
 
15830
 
15831
 
15832
 
15833
 
15834
 
15835
 
15836
 
15837
 
15838
 
15839
 
15840
 
15841
 
15842
 
15843
 
15844
 
15845
 
15846
 
15847
 
15848
 
15849
 
15850
 
15851
 
15852
 
15853
 
15854
 
15855
 
15856
 
15857
 
15858
 
15859
 
15860
 
15861
 
15862
 
15863
 
15864
 
15865
 
15866
 
15867
 
15868
 
15869
 
15870
 
15871
 
15872
 
15873
 
15874
 
15875
 
15876
 
15877
 
15878
 
15879
 
15880
 
15881
 
15882
 
15883
 
15884
 
15885
 
15886
 
15887
 
15888
 
15889
 
15890
 
15891
 
15892
 
15893
 
15894
 
15895
 
15896
 
15897
 
15898
 
15899
 
15900
 
15901
 
15902
 
15903
 
15904
 
15905
 
15906
 
15907
 
15908
 
15909
 
15910
 
15911
 
15912
 
15913
 
15914
 
15915
 
15916
 
15917
 
15918
 
15919
 
15920
 
15921
 
15922
 
15923
 
15924
 
15925
 
15926
 
15927
 
15928
 
15929
 
15930
 
15931
 
15932
 
15933
 
15934
 
15935
 
15936
 
15937
 
15938
 
15939
 
15940
 
15941
 
15942
 
15943
 
15944
 
15945
 
15946
 
15947
 
15948
 
15949
 
15950
 
15951
 
15952
 
15953
 
15954
 
15955
 
15956
 
15957
 
15958
 
15959
 
15960
 
15961
 
15962
 
15963
 
15964
 
15965
 
15966
 
15967
 
15968
 
15969
 
15970
 
15971
 
15972
 
15973
 
15974
 
15975
 
15976
 
15977
 
15978
 
15979
 
15980
 
15981
 
15982
 
15983
 
15984
 
15985
 
15986
 
15987
 
15988
 
15989
 
15990
 
15991
 
15992
 
15993
 
15994
 
15995
 
15996
 
15997
 
15998
 
15999
 
16000
 
16001
 
16002
 
16003
 
16004
 
16005
 
16006
 
16007
 
16008
 
16009
 
16010
 
16011
 
16012
 
16013
 
16014
 
16015
 
16016
 
16017
 
16018
 
16019
 
16020
 
16021
 
16022
 
16023
 
16024
 
16025
 
16026
 
16027
 
16028
 
16029
 
16030
 
16031
 
16032
 
16033
 
16034
 
16035
 
16036
 
16037
 
16038
 
16039
 
16040
 
16041
 
16042
 
16043
 
16044
 
16045
 
16046
 
16047
 
16048
 
16049
 
16050
 
16051
 
16052
 
16053
 
16054
 
16055
 
16056
 
16057
 
16058
 
16059
 
16060
 
16061
 
16062
 
16063
 
16064
 
16065
 
16066
 
16067
 
16068
 
16069
 
16070
 
16071
 
16072
 
16073
 
16074
 
16075
 
16076
 
16077
 
16078
 
16079
 
16080
 
16081
 
16082
 
16083
 
16084
 
16085
 
16086
 
16087
 
16088
 
16089
 
16090
 
16091
 
16092
 
16093
 
16094
 
16095
 
16096
 
16097
 
16098
 
16099
 
16100
 
16101
 
16102
 
16103
 
16104
 
16105
 
16106
 
16107
 
16108
 
16109
 
16110
 
16111
 
16112
 
16113
 
16114
 
16115
 
16116
 
16117
 
16118
 
16119
 
16120
 
16121
 
16122
 
16123
 
16124
 
16125
 
16126
 
16127
 
16128
 
16129
 
16130
 
16131
 
16132
 
16133
 
16134
 
16135
 
16136
 
16137
 
16138
 
16139
 
16140
 
16141
 
16142
 
16143
 
16144
 
16145
 
16146
 
16147
 
16148
 
16149
 
16150
 
16151
 
16152
 
16153
 
16154
 
16155
 
16156
 
16157
 
16158
 
16159
 
16160
 
16161
 
16162
 
16163
 
16164
 
16165
 
16166
 
16167
 
16168
 
16169
 
16170
 
16171
 
16172
 
16173
 
16174
 
16175
 
16176
 
16177
 
16178
 
16179
 
16180
 
16181
 
16182
 
16183
 
16184
 
16185
 
16186
 
16187
 
16188
 
16189
 
16190
 
16191
 
16192
 
16193
 
16194
 
16195
 
16196
 
16197
 
16198
 
16199
 
16200
 
16201
 
16202
 
16203
 
16204
 
16205
 
16206
 
16207
 
16208
 
16209
 
16210
 
16211
 
16212
 
16213
 
16214
 
16215
 
16216
 
16217
 
16218
 
16219
 
16220
 
16221
 
16222
 
16223
 
16224
 
16225
 
16226
 
16227
 
16228
 
16229
 
16230
 
16231
 
16232
 
16233
 
16234
 
16235
 
16236
 
16237
 
16238
 
16239
 
16240
 
16241
 
16242
 
16243
 
16244
 
16245
 
16246
 
16247
 
16248
 
16249
 
16250
 
16251
 
16252
 
16253
 
16254
 
16255
 
16256
 
16257
 
16258
 
16259
 
16260
 
16261
 
16262
 
16263
 
16264
 
16265
 
16266
 
16267
 
16268
 
16269
 
16270
 
16271
 
16272
 
16273
 
16274
 
16275
 
16276
 
16277
 
16278
 
16279
 
16280
 
16281
 
16282
 
16283
 
16284
 
16285
 
16286
 
16287
 
16288
 
16289
 
16290
 
16291
 
16292
 
16293
 
16294
 
16295
 
16296
 
16297
 
16298
 
16299
 
16300
 
16301
 
16302
 
16303
 
16304
 
16305
 
16306
 
16307
 
16308
 
16309
 
16310
 
16311
 
16312
 
16313
 
16314
 
16315
 
16316
 
16317
 
16318
 
16319
 
16320
 
16321
 
16322
 
16323
 
16324
 
16325
 
16326
 
16327
 
16328
 
16329
 
16330
 
16331
 
16332
 
16333
 
16334
 
16335
 
16336
 
16337
 
16338
 
16339
 
16340
 
16341
 
16342
 
16343
 
16344
 
16345
 
16346
 
16347
 
16348
 
16349
 
16350
 
16351
 
16352
 
16353
 
16354
 
16355
 
16356
 
16357
 
16358
 
16359
 
16360
 
16361
 
16362
 
16363
 
16364
 
16365
 
16366
 
16367
 
16368
 
16369
 
16370
 
16371
 
16372
 
16373
 
16374
 
16375
 
16376
 
16377
 
16378
 
16379
 
16380
 
16381
 
16382
 
16383
 
16384
 
16385
 
16386
 
16387
 
16388
 
16389
 
16390
 
16391
 
16392
 
16393
 
16394
 
16395
 
16396
 
16397
 
16398
 
16399
 
16400
 
16401
 
16402
 
16403
 
16404
 
16405
 
16406
 
16407
 
16408
 
16409
 
16410
 
16411
 
16412
 
16413
 
16414
 
16415
 
16416
 
16417
 
16418
 
16419
 
16420
 
16421
 
16422
 
16423
 
16424
 
16425
 
16426
 
16427
 
16428
 
16429
 
16430
 
16431
 
16432
 
16433
 
16434
 
16435
 
16436
 
16437
 
16438
 
16439
 
16440
 
16441
 
16442
 
16443
 
16444
 
16445
 
16446
 
16447
 
16448
 
16449
 
16450
 
16451
 
16452
 
16453
 
16454
 
16455
 
16456
 
16457
 
16458
 
16459
 
16460
 
16461
 
16462
 
16463
 
16464
 
16465
 
16466
 
16467
 
16468
 
16469
 
16470
 
16471
 
16472
 
16473
 
16474
 
16475
 
16476
 
16477
 
16478
 
16479
 
16480
 
16481
 
16482
 
16483
 
16484
 
16485
 
16486
 
16487
 
16488
 
16489
 
16490
 
16491
 
16492
 
16493
 
16494
 
16495
 
16496
 
16497
 
16498
 
16499
 
16500
 
16501
 
16502
 
16503
 
16504
 
16505
 
16506
 
16507
 
16508
 
16509
 
16510
 
16511
 
16512
 
16513
 
16514
 
16515
 
16516
 
16517
 
16518
 
16519
 
16520
 
16521
 
16522
 
16523
 
16524
 
16525
 
16526
 
16527
 
16528
 
16529
 
16530
 
16531
 
16532
 
16533
 
16534
 
16535
 
16536
 
16537
 
16538
 
16539
 
16540
 
16541
 
16542
 
16543
 
16544
 
16545
 
16546
 
16547
 
16548
 
16549
 
16550
 
16551
 
16552
 
16553
 
16554
 
16555
 
16556
 
16557
 
16558
 
16559
 
16560
 
16561
 
16562
 
16563
 
16564
 
16565
 
16566
 
16567
 
16568
 
16569
 
16570
 
16571
 
16572
 
16573
 
16574
 
16575
 
16576
 
16577
 
16578
 
16579
 
16580
 
16581
 
16582
 
16583
 
16584
 
16585
 
16586
 
16587
 
16588
 
16589
 
16590
 
16591
 
16592
 
16593
 
16594
 
16595
 
16596
 
16597
 
16598
 
16599
 
16600
 
16601
 
16602
 
16603
 
16604
 
16605
 
16606
 
16607
 
16608
 
16609
 
16610
 
16611
 
16612
 
16613
 
16614
 
16615
 
16616
 
16617
 
16618
 
16619
 
16620
 
16621
 
16622
 
16623
 
16624
 
16625
 
16626
 
16627
 
16628
 
16629
 
16630
 
16631
 
16632
 
16633
 
16634
 
16635
 
16636
 
16637
 
16638
 
16639
 
16640
 
16641
 
16642
 
16643
 
16644
 
16645
 
16646
 
16647
 
16648
 
16649
 
16650
 
16651
 
16652
 
16653
 
16654
 
16655
 
16656
 
16657
 
16658
 
16659
 
16660
 
16661
 
16662
 
16663
 
16664
 
16665
 
16666
 
16667
 
16668
 
16669
 
16670
 
16671
 
16672
 
16673
 
16674
 
16675
 
16676
 
16677
 
16678
 
16679
 
16680
 
16681
 
16682
 
16683
 
16684
 
16685
 
16686
 
16687
 
16688
 
16689
 
16690
 
16691
 
16692
 
16693
 
16694
 
16695
 
16696
 
16697
 
16698
 
16699
 
16700
 
16701
 
16702
 
16703
 
16704
 
16705
 
16706
 
16707
 
16708
 
16709
 
16710
 
16711
 
16712
 
16713
 
16714
 
16715
 
16716
 
16717
 
16718
 
16719
 
16720
 
16721
 
16722
 
16723
 
16724
 
16725
 
16726
 
16727
 
16728
 
16729
 
16730
 
16731
 
16732
 
16733
 
16734
 
16735
 
16736
 
16737
 
16738
 
16739
 
16740
 
16741
 
16742
 
16743
 
16744
 
16745
 
16746
 
16747
 
16748
 
16749
 
16750
 
16751
 
16752
 
16753
 
16754
 
16755
 
16756
 
16757
 
16758
 
16759
 
16760
 
16761
 
16762
 
16763
 
16764
 
16765
 
16766
 
16767
 
16768
 
16769
 
16770
 
16771
 
16772
 
16773
 
16774
 
16775
 
16776
 
16777
 
16778
 
16779
 
16780
 
16781
 
16782
 
16783
 
16784
 
16785
 
16786
 
16787
 
16788
 
16789
 
16790
 
16791
 
16792
 
16793
 
16794
 
16795
 
16796
 
16797
 
16798
 
16799
 
16800
 
16801
 
16802
 
16803
 
16804
 
16805
 
16806
 
16807
 
16808
 
16809
 
16810
 
16811
 
16812
 
16813
 
16814
 
16815
 
16816
 
16817
 
16818
 
16819
 
16820
 
16821
 
16822
 
16823
 
16824
 
16825
 
16826
 
16827
 
16828
 
16829
 
16830
 
16831
 
16832
 
16833
 
16834
 
16835
 
16836
 
16837
 
16838
 
16839
 
16840
 
16841
 
16842
 
16843
 
16844
 
16845
 
16846
 
16847
 
16848
 
16849
 
16850
 
16851
 
16852
 
16853
 
16854
 
16855
 
16856
 
16857
 
16858
 
16859
 
16860
 
16861
 
16862
 
16863
 
16864
 
16865
 
16866
 
16867
 
16868
 
16869
 
16870
 
16871
 
16872
 
16873
 
16874
 
16875
 
16876
 
16877
 
16878
 
16879
 
16880
 
16881
 
16882
 
16883
 
16884
 
16885
 
16886
 
16887
 
16888
 
16889
 
16890
 
16891
 
16892
 
16893
 
16894
 
16895
 
16896
 
16897
 
16898
 
16899
 
16900
 
16901
 
16902
 
16903
 
16904
 
16905
 
16906
 
16907
 
16908
 
16909
 
16910
 
16911
 
16912
 
16913
 
16914
 
16915
 
16916
 
16917
 
16918
 
16919
 
16920
 
16921
 
16922
 
16923
 
16924
 
16925
 
16926
 
16927
 
16928
 
16929
 
16930
 
16931
 
16932
 
16933
 
16934
 
16935
 
16936
 
16937
 
16938
 
16939
 
16940
 
16941
 
16942
 
16943
 
16944
 
16945
 
16946
 
16947
 
16948
 
16949
 
16950
 
16951
 
16952
 
16953
 
16954
 
16955
 
16956
 
16957
 
16958
 
16959
 
16960
 
16961
 
16962
 
16963
 
16964
 
16965
 
16966
 
16967
 
16968
 
16969
 
16970
 
16971
 
16972
 
16973
 
16974
 
16975
 
16976
 
16977
 
16978
 
16979
 
16980
 
16981
 
16982
 
16983
 
16984
 
16985
 
16986
 
16987
 
16988
 
16989
 
16990
 
16991
 
16992
 
16993
 
16994
 
16995
 
16996
 
16997
 
16998
 
16999
 
17000
 
17001
 
17002
 
17003
 
17004
 
17005
 
17006
 
17007
 
17008
 
17009
 
17010
 
17011
 
17012
 
17013
 
17014
 
17015
 
17016
 
17017
 
17018
 
17019
 
17020
 
17021
 
17022
 
17023
 
17024
 
17025
 
17026
 
17027
 
17028
 
17029
 
17030
 
17031
 
17032
 
17033
 
17034
 
17035
 
17036
 
17037
 
17038
 
17039
 
17040
 
17041
 
17042
 
17043
 
17044
 
17045
 
17046
 
17047
 
17048
 
17049
 
17050
 
17051
 
17052
 
17053
 
17054
 
17055
 
17056
 
17057
 
17058
 
17059
 
17060
 
17061
 
17062
 
17063
 
17064
 
17065
 
17066
 
17067
 
17068
 
17069
 
17070
 
17071
 
17072
 
17073
 
17074
 
17075
 
17076
 
17077
 
17078
 
17079
 
17080
 
17081
 
17082
 
17083
 
17084
 
17085
 
17086
 
17087
 
17088
 
17089
 
17090
 
17091
 
17092
 
17093
 
17094
 
17095
 
17096
 
17097
 
17098
 
17099
 
17100
 
17101
 
17102
 
17103
 
17104
 
17105
 
17106
 
17107
 
17108
 
17109
 
17110
 
17111
 
17112
 
17113
 
17114
 
17115
 
17116
 
17117
 
17118
 
17119
 
17120
 
17121
 
17122
 
17123
 
17124
 
17125
 
17126
 
17127
 
17128
 
17129
 
17130
 
17131
 
17132
 
17133
 
17134
 
17135
 
17136
 
17137
 
17138
 
17139
 
17140
 
17141
 
17142
 
17143
 
17144
 
17145
 
17146
 
17147
 
17148
 
17149
 
17150
 
17151
 
17152
 
17153
 
17154
 
17155
 
17156
 
17157
 
17158
 
17159
 
17160
 
17161
 
17162
 
17163
 
17164
 
17165
 
17166
 
17167
 
17168
 
17169
 
17170
 
17171
 
17172
 
17173
 
17174
 
17175
 
17176
 
17177
 
17178
 
17179
 
17180
 
17181
 
17182
 
17183
 
17184
 
17185
 
17186
 
17187
 
17188
 
17189
 
17190
 
17191
 
17192
 
17193
 
17194
 
17195
 
17196
 
17197
 
17198
 
17199
 
17200
 
17201
 
17202
 
17203
 
17204
 
17205
 
17206
 
17207
 
17208
 
17209
 
17210
 
17211
 
17212
 
17213
 
17214
 
17215
 
17216
 
17217
 
17218
 
17219
 
17220
 
17221
 
17222
 
17223
 
17224
 
17225
 
17226
 
17227
 
17228
 
17229
 
17230
 
17231
 
17232
 
17233
 
17234
 
17235
 
17236
 
17237
 
17238
 
17239
 
17240
 
17241
 
17242
 
17243
 
17244
 
17245
 
17246
 
17247
 
17248
 
17249
 
17250
 
17251
 
17252
 
17253
 
17254
 
17255
 
17256
 
17257
 
17258
 
17259
 
17260
 
17261
 
17262
 
17263
 
17264
 
17265
 
17266
 
17267
 
17268
 
17269
 
17270
 
17271
 
17272
 
17273
 
17274
 
17275
 
17276
 
17277
 
17278
 
17279
 
17280
 
17281
 
17282
 
17283
 
17284
 
17285
 
17286
 
17287
 
17288
 
17289
 
17290
 
17291
 
17292
 
17293
 
17294
 
17295
 
17296
 
17297
 
17298
 
17299
 
17300
 
17301
 
17302
 
17303
 
17304
 
17305
 
17306
 
17307
 
17308
 
17309
 
17310
 
17311
 
17312
 
17313
 
17314
 
17315
 
17316
 
17317
 
17318
 
17319
 
17320
 
17321
 
17322
 
17323
 
17324
 
17325
 
17326
 
17327
 
17328
 
17329
 
17330
 
17331
 
17332
 
17333
 
17334
 
17335
 
17336
 
17337
 
17338
 
17339
 
17340
 
17341
 
17342
 
17343
 
17344
 
17345
 
17346
 
17347
 
17348
 
17349
 
17350
 
17351
 
17352
 
17353
 
17354
 
17355
 
17356
 
17357
 
17358
 
17359
 
17360
 
17361
 
17362
 
17363
 
17364
 
17365
 
17366
 
17367
 
17368
 
17369
 
17370
 
17371
 
17372
 
17373
 
17374
 
17375
 
17376
 
17377
 
17378
 
17379
 
17380
 
17381
 
17382
 
17383
 
17384
 
17385
 
17386
 
17387
 
17388
 
17389
 
17390
 
17391
 
17392
 
17393
 
17394
 
17395
 
17396
 
17397
 
17398
 
17399
 
17400
 
17401
 
17402
 
17403
 
17404
 
17405
 
17406
 
17407
 
17408
 
17409
 
17410
 
17411
 
17412
 
17413
 
17414
 
17415
 
17416
 
17417
 
17418
 
17419
 
17420
 
17421
 
17422
 
17423
 
17424
 
17425
 
17426
 
17427
 
17428
 
17429
 
17430
 
17431
 
17432
 
17433
 
17434
 
17435
 
17436
 
17437
 
17438
 
17439
 
17440
 
17441
 
17442
 
17443
 
17444
 
17445
 
17446
 
17447
 
17448
 
17449
 
17450
 
17451
 
17452
 
17453
 
17454
 
17455
 
17456
 
17457
 
17458
 
17459
 
17460
 
17461
 
17462
 
17463
 
17464
 
17465
 
17466
 
17467
 
17468
 
17469
 
17470
 
17471
 
17472
 
17473
 
17474
 
17475
 
17476
 
17477
 
17478
 
17479
 
17480
 
17481
 
17482
 
17483
 
17484
 
17485
 
17486
 
17487
 
17488
 
17489
 
17490
 
17491
 
17492
 
17493
 
17494
 
17495
 
17496
 
17497
 
17498
 
17499
 
17500
 
17501
 
17502
 
17503
 
17504
 
17505
 
17506
 
17507
 
17508
 
17509
 
17510
 
17511
 
17512
 
17513
 
17514
 
17515
 
17516
 
17517
 
17518
 
17519
 
17520
 
17521
 
17522
 
17523
 
17524
 
17525
 
17526
 
17527
 
17528
 
17529
 
17530
 
17531
 
17532
 
17533
 
17534
 
17535
 
17536
 
17537
 
17538
 
17539
 
17540
 
17541
 
17542
 
17543
 
17544
 
17545
 
17546
 
17547
 
17548
 
17549
 
17550
 
17551
 
17552
 
17553
 
17554
 
17555
 
17556
 
17557
 
17558
 
17559
 
17560
 
17561
 
17562
 
17563
 
17564
 
17565
 
17566
 
17567
 
17568
 
17569
 
17570
 
17571
 
17572
 
17573
 
17574
 
17575
 
17576
 
17577
 
17578
 
17579
 
17580
 
17581
 
17582
 
17583
 
17584
 
17585
 
17586
 
17587
 
17588
 
17589
 
17590
 
17591
 
17592
 
17593
 
17594
 
17595
 
17596
 
17597
 
17598
 
17599
 
17600
 
17601
 
17602
 
17603
 
17604
 
17605
 
17606
 
17607
 
17608
 
17609
 
17610
 
17611
 
17612
 
17613
 
17614
 
17615
 
17616
 
17617
 
17618
 
17619
 
17620
 
17621
 
17622
 
17623
 
17624
 
17625
 
17626
 
17627
 
17628
 
17629
 
17630
 
17631
 
17632
 
17633
 
17634
 
17635
 
17636
 
17637
 
17638
 
17639
 
17640
 
17641
 
17642
 
17643
 
17644
 
17645
 
17646
 
17647
 
17648
 
17649
 
17650
 
17651
 
17652
 
17653
 
17654
 
17655
 
17656
 
17657
 
17658
 
17659
 
17660
 
17661
 
17662
 
17663
 
17664
 
17665
 
17666
 
17667
 
17668
 
17669
 
17670
 
17671
 
17672
 
17673
 
17674
 
17675
 
17676
 
17677
 
17678
 
17679
 
17680
 
17681
 
17682
 
17683
 
17684
 
17685
 
17686
 
17687
 
17688
 
17689
 
17690
 
17691
 
17692
 
17693
 
17694
 
17695
 
17696
 
17697
 
17698
 
17699
 
17700
 
17701
 
17702
 
17703
 
17704
 
17705
 
17706
 
17707
 
17708
 
17709
 
17710
 
17711
 
17712
 
17713
 
17714
 
17715
 
17716
 
17717
 
17718
 
17719
 
17720
 
17721
 
17722
 
17723
 
17724
 
17725
 
17726
 
17727
 
17728
 
17729
 
17730
 
17731
 
17732
 
17733
 
17734
 
17735
 
17736
 
17737
 
17738
 
17739
 
17740
 
17741
 
17742
 
17743
 
17744
 
17745
 
17746
 
17747
 
17748
 
17749
 
17750
 
17751
 
17752
 
17753
 
17754
 
17755
 
17756
 
17757
 
17758
 
17759
 
17760
 
17761
 
17762
 
17763
 
17764
 
17765
 
17766
 
17767
 
17768
 
17769
 
17770
 
17771
 
17772
 
17773
 
17774
 
17775
 
17776
 
17777
 
17778
 
17779
 
17780
 
17781
 
17782
 
17783
 
17784
 
17785
 
17786
 
17787
 
17788
 
17789
 
17790
 
17791
 
17792
 
17793
 
17794
 
17795
 
17796
 
17797
 
17798
 
17799
 
17800
 
17801
 
17802
 
17803
 
17804
 
17805
 
17806
 
17807
 
17808
 
17809
 
17810
 
17811
 
17812
 
17813
 
17814
 
17815
 
17816
 
17817
 
17818
 
17819
 
17820
 
17821
 
17822
 
17823
 
17824
 
17825
 
17826
 
17827
 
17828
 
17829
 
17830
 
17831
 
17832
 
17833
 
17834
 
17835
 
17836
 
17837
 
17838
 
17839
 
17840
 
17841
 
17842
 
17843
 
17844
 
17845
 
17846
 
17847
 
17848
 
17849
 
17850
 
17851
 
17852
 
17853
 
17854
 
17855
 
17856
 
17857
 
17858
 
17859
 
17860
 
17861
 
17862
 
17863
 
17864
 
17865
 
17866
 
17867
 
17868
 
17869
 
17870
 
17871
 
17872
 
17873
 
17874
 
17875
 
17876
 
17877
 
17878
 
17879
 
17880
 
17881
 
17882
 
17883
 
17884
 
17885
 
17886
 
17887
 
17888
 
17889
 
17890
 
17891
 
17892
 
17893
 
17894
 
17895
 
17896
 
17897
 
17898
 
17899
 
17900
 
17901
 
17902
 
17903
 
17904
 
17905
 
17906
 
17907
 
17908
 
17909
 
17910
 
17911
 
17912
 
17913
 
17914
 
17915
 
17916
 
17917
 
17918
 
17919
 
17920
 
17921
 
17922
 
17923
 
17924
 
17925
 
17926
 
17927
 
17928
 
17929
 
17930
 
17931
 
17932
 
17933
 
17934
 
17935
 
17936
 
17937
 
17938
 
17939
 
17940
 
17941
 
17942
 
17943
 
17944
 
17945
 
17946
 
17947
 
17948
 
17949
 
17950
 
17951
 
17952
 
17953
 
17954
 
17955
 
17956
 
17957
 
17958
 
17959
 
17960
 
17961
 
17962
 
17963
 
17964
 
17965
 
17966
 
17967
 
17968
 
17969
 
17970
 
17971
 
17972
 
17973
 
17974
 
17975
 
17976
 
17977
 
17978
 
17979
 
17980
 
17981
 
17982
 
17983
 
17984
 
17985
 
17986
 
17987
 
17988
 
17989
 
17990
 
17991
 
17992
 
17993
 
17994
 
17995
 
17996
 
17997
 
17998
 
17999
 
18000
 
18001
 
18002
 
18003
 
18004
 
18005
 
18006
 
18007
 
18008
 
18009
 
18010
 
18011
 
18012
 
18013
 
18014
 
18015
 
18016
 
18017
 
18018
 
18019
 
18020
 
18021
 
18022
 
18023
 
18024
 
18025
 
18026
 
18027
 
18028
 
18029
 
18030
 
18031
 
18032
 
18033
 
18034
 
18035
 
18036
 
18037
 
18038
 
18039
 
18040
 
18041
 
18042
 
18043
 
18044
 
18045
 
18046
 
18047
 
18048
 
18049
 
18050
 
18051
 
18052
 
18053
 
18054
 
18055
 
18056
 
18057
 
18058
 
18059
 
18060
 
18061
 
18062
 
18063
 
18064
 
18065
 
18066
 
18067
 
18068
 
18069
 
18070
 
18071
 
18072
 
18073
 
18074
 
18075
 
18076
 
18077
 
18078
 
18079
 
18080
 
18081
 
18082
 
18083
 
18084
 
18085
 
18086
 
18087
 
18088
 
18089
 
18090
 
18091
 
18092
 
18093
 
18094
 
18095
 
18096
 
18097
 
18098
 
18099
 
18100
 
18101
 
18102
 
18103
 
18104
 
18105
 
18106
 
18107
 
18108
 
18109
 
18110
 
18111
 
18112
 
18113
 
18114
 
18115
 
18116
 
18117
 
18118
 
18119
 
18120
 
18121
 
18122
 
18123
 
18124
 
18125
 
18126
 
18127
 
18128
 
18129
 
18130
 
18131
 
18132
 
18133
 
18134
 
18135
 
18136
 
18137
 
18138
 
18139
 
18140
 
18141
 
18142
 
18143
 
18144
 
18145
 
18146
 
18147
 
18148
 
18149
 
18150
 
18151
 
18152
 
18153
 
18154
 
18155
 
18156
 
18157
 
18158
 
18159
 
18160
 
18161
 
18162
 
18163
 
18164
 
18165
 
18166
 
18167
 
18168
 
18169
 
18170
 
18171
 
18172
 
18173
 
18174
 
18175
 
18176
 
18177
 
18178
 
18179
 
18180
 
18181
 
18182
 
18183
 
18184
 
18185
 
18186
 
18187
 
18188
 
18189
 
18190
 
18191
 
18192
 
18193
 
18194
 
18195
 
18196
 
18197
 
18198
 
18199
 
18200
 
18201
 
18202
 
18203
 
18204
 
18205
 
18206
 
18207
 
18208
 
18209
 
18210
 
18211
 
18212
 
18213
 
18214
 
18215
 
18216
 
18217
 
18218
 
18219
 
18220
 
18221
 
18222
 
18223
 
18224
 
18225
 
18226
 
18227
 
18228
 
18229
 
18230
 
18231
 
18232
 
18233
 
18234
 
18235
 
18236
 
18237
 
18238
 
18239
 
18240
 
18241
 
18242
 
18243
 
18244
 
18245
 
18246
 
18247
 
18248
 
18249
 
18250
 
18251
 
18252
 
18253
 
18254
 
18255
 
18256
 
18257
 
18258
 
18259
 
18260
 
18261
 
18262
 
18263
 
18264
 
18265
 
18266
 
18267
 
18268
 
18269
 
18270
 
18271
 
18272
 
18273
 
18274
 
18275
 
18276
 
18277
 
18278
 
18279
 
18280
 
18281
 
18282
 
18283
 
18284
 
18285
 
18286
 
18287
 
18288
 
18289
 
18290
 
18291
 
18292
 
18293
 
18294
 
18295
 
18296
 
18297
 
18298
 
18299
 
18300
 
18301
 
18302
 
18303
 
18304
 
18305
 
18306
 
18307
 
18308
 
18309
 
18310
 
18311
 
18312
 
18313
 
18314
 
18315
 
18316
 
18317
 
18318
 
18319
 
18320
 
18321
 
18322
 
18323
 
18324
 
18325
 
18326
 
18327
 
18328
 
18329
 
18330
 
18331
 
18332
 
18333
 
18334
 
18335
 
18336
 
18337
 
18338
 
18339
 
18340
 
18341
 
18342
 
18343
 
18344
 
18345
 
18346
 
18347
 
18348
 
18349
 
18350
 
18351
 
18352
 
18353
 
18354
 
18355
 
18356
 
18357
 
18358
 
18359
 
18360
 
18361
 
18362
 
18363
 
18364
 
18365
 
18366
 
18367
 
18368
 
18369
 
18370
 
18371
 
18372
 
18373
 
18374
 
18375
 
18376
 
18377
 
18378
 
18379
 
18380
 
18381
 
18382
 
18383
 
18384
 
18385
 
18386
 
18387
 
18388
 
18389
 
18390
 
18391
 
18392
 
18393
 
18394
 
18395
 
18396
 
18397
 
18398
 
18399
 
18400
 
18401
 
18402
 
18403
 
18404
 
18405
 
18406
 
18407
 
18408
 
18409
 
18410
 
18411
 
18412
 
18413
 
18414
 
18415
 
18416
 
18417
 
18418
 
18419
 
18420
 
18421
 
18422
 
18423
 
18424
 
18425
 
18426
 
18427
 
18428
 
18429
 
18430
 
18431
 
18432
 
18433
 
18434
 
18435
 
18436
 
18437
 
18438
 
18439
 
18440
 
18441
 
18442
 
18443
 
18444
 
18445
 
18446
 
18447
 
18448
 
18449
 
18450
 
18451
 
18452
 
18453
 
18454
 
18455
 
18456
 
18457
 
18458
 
18459
 
18460
 
18461
 
18462
 
18463
 
18464
 
18465
 
18466
 
18467
 
18468
 
18469
 
18470
 
18471
 
18472
 
18473
 
18474
 
18475
 
18476
 
18477
 
18478
 
18479
 
18480
 
18481
 
18482
 
18483
 
18484
 
18485
 
18486
 
18487
 
18488
 
18489
 
18490
 
18491
 
18492
 
18493
 
18494
 
18495
 
18496
 
18497
 
18498
 
18499
 
18500
 
18501
 
18502
 
18503
 
18504
 
18505
 
18506
 
18507
 
18508
 
18509
 
18510
 
18511
 
18512
 
18513
 
18514
 
18515
 
18516
 
18517
 
18518
 
18519
 
18520
 
18521
 
18522
 
18523
 
18524
 
18525
 
18526
 
18527
 
18528
 
18529
 
18530
 
18531
 
18532
 
18533
 
18534
 
18535
 
18536
 
18537
 
18538
 
18539
 
18540
 
18541
 
18542
 
18543
 
18544
 
18545
 
18546
 
18547
 
18548
 
18549
 
18550
 
18551
 
18552
 
18553
 
18554
 
18555
 
18556
 
18557
 
18558
 
18559
 
18560
 
18561
 
18562
 
18563
 
18564
 
18565
 
18566
 
18567
 
18568
 
18569
 
18570
 
18571
 
18572
 
18573
 
18574
 
18575
 
18576
 
18577
 
18578
 
18579
 
18580
 
18581
 
18582
 
18583
 
18584
 
18585
 
18586
 
18587
 
18588
 
18589
 
18590
 
18591
 
18592
 
18593
 
18594
 
18595
 
18596
 
18597
 
18598
 
18599
 
18600
 
18601
 
18602
 
18603
 
18604
 
18605
 
18606
 
18607
 
18608
 
18609
 
18610
 
18611
 
18612
 
18613
 
18614
 
18615
 
18616
 
18617
 
18618
 
18619
 
18620
 
18621
 
18622
 
18623
 
18624
 
18625
 
18626
 
18627
 
18628
 
18629
 
18630
 
18631
 
18632
 
18633
 
18634
 
18635
 
18636
 
18637
 
18638
 
18639
 
18640
 
18641
 
18642
 
18643
 
18644
 
18645
 
18646
 
18647
 
18648
 
18649
 
18650
 
18651
 
18652
 
18653
 
18654
 
18655
 
18656
 
18657
 
18658
 
18659
 
18660
 
18661
 
18662
 
18663
 
18664
 
18665
 
18666
 
18667
 
18668
 
18669
 
18670
 
18671
 
18672
 
18673
 
18674
 
18675
 
18676
 
18677
 
18678
 
18679
 
18680
 
18681
 
18682
 
18683
 
18684
 
18685
 
18686
 
18687
 
18688
 
18689
 
18690
 
18691
 
18692
 
18693
 
18694
 
18695
 
18696
 
18697
 
18698
 
18699
 
18700
 
18701
 
18702
 
18703
 
18704
 
18705
 
18706
 
18707
 
18708
 
18709
 
18710
 
18711
 
18712
 
18713
 
18714
 
18715
 
18716
 
18717
 
18718
 
18719
 
18720
 
18721
 
18722
 
18723
 
18724
 
18725
 
18726
 
18727
 
18728
 
18729
 
18730
 
18731
 
18732
 
18733
 
18734
 
18735
 
18736
 
18737
 
18738
 
18739
 
18740
 
18741
 
18742
 
18743
 
18744
 
18745
 
18746
 
18747
 
18748
 
18749
 
18750
 
18751
 
18752
 
18753
 
18754
 
18755
 
18756
 
18757
 
18758
 
18759
 
18760
 
18761
 
18762
 
18763
 
18764
 
18765
 
18766
 
18767
 
18768
 
18769
 
18770
 
18771
 
18772
 
18773
 
18774
 
18775
 
18776
 
18777
 
18778
 
18779
 
18780
 
18781
 
18782
 
18783
 
18784
 
18785
 
18786
 
18787
 
18788
 
18789
 
18790
 
18791
 
18792
 
18793
 
18794
 
18795
 
18796
 
18797
 
18798
 
18799
 
18800
 
18801
 
18802
 
18803
 
18804
 
18805
 
18806
 
18807
 
18808
 
18809
 
18810
 
18811
 
18812
 
18813
 
18814
 
18815
 
18816
 
18817
 
18818
 
18819
 
18820
 
18821
 
18822
 
18823
 
18824
 
18825
 
18826
 
18827
 
18828
 
18829
 
18830
 
18831
 
18832
 
18833
 
18834
 
18835
 
18836
 
18837
 
18838
 
18839
 
18840
 
18841
 
18842
 
18843
 
18844
 
18845
 
18846
 
18847
 
18848
 
18849
 
18850
 
18851
 
18852
 
18853
 
18854
 
18855
 
18856
 
18857
 
18858
 
18859
 
18860
 
18861
 
18862
 
18863
 
18864
 
18865
 
18866
 
18867
 
18868
 
18869
 
18870
 
18871
 
18872
 
18873
 
18874
 
18875
 
18876
 
18877
 
18878
 
18879
 
18880
 
18881
 
18882
 
18883
 
18884
 
18885
 
18886
 
18887
 
18888
 
18889
 
18890
 
18891
 
18892
 
18893
 
18894
 
18895
 
18896
 
18897
 
18898
 
18899
 
18900
 
18901
 
18902
 
18903
 
18904
 
18905
 
18906
 
18907
 
18908
 
18909
 
18910
 
18911
 
18912
 
18913
 
18914
 
18915
 
18916
 
18917
 
18918
 
18919
 
18920
 
18921
 
18922
 
18923
 
18924
 
18925
 
18926
 
18927
 
18928
 
18929
 
18930
 
18931
 
18932
 
18933
 
18934
 
18935
 
18936
 
18937
 
18938
 
18939
 
18940
 
18941
 
18942
 
18943
 
18944
 
18945
 
18946
 
18947
 
18948
 
18949
 
18950
 
18951
 
18952
 
18953
 
18954
 
18955
 
18956
 
18957
 
18958
 
18959
 
18960
 
18961
 
18962
 
18963
 
18964
 
18965
 
18966
 
18967
 
18968
 
18969
 
18970
 
18971
 
18972
 
18973
 
18974
 
18975
 
18976
 
18977
 
18978
 
18979
 
18980
 
18981
 
18982
 
18983
 
18984
 
18985
 
18986
 
18987
 
18988
 
18989
 
18990
 
18991
 
18992
 
18993
 
18994
 
18995
 
18996
 
18997
 
18998
 
18999
 
19000
 
19001
 
19002
 
19003
 
19004
 
19005
 
19006
 
19007
 
19008
 
19009
 
19010
 
19011
 
19012
 
19013
 
19014
 
19015
 
19016
 
19017
 
19018
 
19019
 
19020
 
19021
 
19022
 
19023
 
19024
 
19025
 
19026
 
19027
 
19028
 
19029
 
19030
 
19031
 
19032
 
19033
 
19034
 
19035
 
19036
 
19037
 
19038
 
19039
 
19040
 
19041
 
19042
 
19043
 
19044
 
19045
 
19046
 
19047
 
19048
 
19049
 
19050
 
19051
 
19052
 
19053
 
19054
 
19055
 
19056
 
19057
 
19058
 
19059
 
19060
 
19061
 
19062
 
19063
 
19064
 
19065
 
19066
 
19067
 
19068
 
19069
 
19070
 
19071
 
19072
 
19073
 
19074
 
19075
 
19076
 
19077
 
19078
 
19079
 
19080
 
19081
 
19082
 
19083
 
19084
 
19085
 
19086
 
19087
 
19088
 
19089
 
19090
 
19091
 
19092
 
19093
 
19094
 
19095
 
19096
 
19097
 
19098
 
19099
 
19100
 
19101
 
19102
 
19103
 
19104
 
19105
 
19106
 
19107
 
19108
 
19109
 
19110
 
19111
 
19112
 
19113
 
19114
 
19115
 
19116
 
19117
 
19118
 
19119
 
19120
 
19121
 
19122
 
19123
 
19124
 
19125
 
19126
 
19127
 
19128
 
19129
 
19130
 
19131
 
19132
 
19133
 
19134
 
19135
 
19136
 
19137
 
19138
 
19139
 
19140
 
19141
 
19142
 
19143
 
19144
 
19145
 
19146
 
19147
 
19148
 
19149
 
19150
 
19151
 
19152
 
19153
 
19154
 
19155
 
19156
 
19157
 
19158
 
19159
 
19160
 
19161
 
19162
 
19163
 
19164
 
19165
 
19166
 
19167
 
19168
 
19169
 
19170
 
19171
 
19172
 
19173
 
19174
 
19175
 
19176
 
19177
 
19178
 
19179
 
19180
 
19181
 
19182
 
19183
 
19184
 
19185
 
19186
 
19187
 
19188
 
19189
 
19190
 
19191
 
19192
 
19193
 
19194
 
19195
 
19196
 
19197
 
19198
 
19199
 
19200
 
19201
 
19202
 
19203
 
19204
 
19205
 
19206
 
19207
 
19208
 
19209
 
19210
 
19211
 
19212
 
19213
 
19214
 
19215
 
19216
 
19217
 
19218
 
19219
 
19220
 
19221
 
19222
 
19223
 
19224
 
19225
 
19226
 
19227
 
19228
 
19229
 
19230
 
19231
 
19232
 
19233
 
19234
 
19235
 
19236
 
19237
 
19238
 
19239
 
19240
 
19241
 
19242
 
19243
 
19244
 
19245
 
19246
 
19247
 
19248
 
19249
 
19250
 
19251
 
19252
 
19253
 
19254
 
19255
 
19256
 
19257
 
19258
 
19259
 
19260
 
19261
 
19262
 
19263
 
19264
 
19265
 
19266
 
19267
 
19268
 
19269
 
19270
 
19271
 
19272
 
19273
 
19274
 
19275
 
19276
 
19277
 
19278
 
19279
 
19280
 
19281
 
19282
 
19283
 
19284
 
19285
 
19286
 
19287
 
19288
 
19289
 
19290
 
19291
 
19292
 
19293
 
19294
 
19295
 
19296
 
19297
 
19298
 
19299
 
19300
 
19301
 
19302
 
19303
 
19304
 
19305
 
19306
 
19307
 
19308
 
19309
 
19310
 
19311
 
19312
 
19313
 
19314
 
19315
 
19316
 
19317
 
19318
 
19319
 
19320
 
19321
 
19322
 
19323
 
19324
 
19325
 
19326
 
19327
 
19328
 
19329
 
19330
 
19331
 
19332
 
19333
 
19334
 
19335
 
19336
 
19337
 
19338
 
19339
 
19340
 
19341
 
19342
 
19343
 
19344
 
19345
 
19346
 
19347
 
19348
 
19349
 
19350
 
19351
 
19352
 
19353
 
19354
 
19355
 
19356
 
19357
 
19358
 
19359
 
19360
 
19361
 
19362
 
19363
 
19364
 
19365
 
19366
 
19367
 
19368
 
19369
 
19370
 
19371
 
19372
 
19373
 
19374
 
19375
 
19376
 
19377
 
19378
 
19379
 
19380
 
19381
 
19382
 
19383
 
19384
 
19385
 
19386
 
19387
 
19388
 
19389
 
19390
 
19391
 
19392
 
19393
 
19394
 
19395
 
19396
 
19397
 
19398
 
19399
 
19400
 
19401
 
19402
 
19403
 
19404
 
19405
 
19406
 
19407
 
19408
 
19409
 
19410
 
19411
 
19412
 
19413
 
19414
 
19415
 
19416
 
19417
 
19418
 
19419
 
19420
 
19421
 
19422
 
19423
 
19424
 
19425
 
19426
 
19427
 
19428
 
19429
 
19430
 
19431
 
19432
 
19433
 
19434
 
19435
 
19436
 
19437
 
19438
 
19439
 
19440
 
19441
 
19442
 
19443
 
19444
 
19445
 
19446
 
19447
 
19448
 
19449
 
19450
 
19451
 
19452
 
19453
 
19454
 
19455
 
19456
 
19457
 
19458
 
19459
 
19460
 
19461
 
19462
 
19463
 
19464
 
19465
 
19466
 
19467
 
19468
 
19469
 
19470
 
19471
 
19472
 
19473
 
19474
 
19475
 
19476
 
19477
 
19478
 
19479
 
19480
 
19481
 
19482
 
19483
 
19484
 
19485
 
19486
 
19487
 
19488
 
19489
 
19490
 
19491
 
19492
 
19493
 
19494
 
19495
 
19496
 
19497
 
19498
 
19499
 
19500
 
19501
 
19502
 
19503
 
19504
 
19505
 
19506
 
19507
 
19508
 
19509
 
19510
 
19511
 
19512
 
19513
 
19514
 
19515
 
19516
 
19517
 
19518
 
19519
 
19520
 
19521
 
19522
 
19523
 
19524
 
19525
 
19526
 
19527
 
19528
 
19529
 
19530
 
19531
 
19532
 
19533
 
19534
 
19535
 
19536
 
19537
 
19538
 
19539
 
19540
 
19541
 
19542
 
19543
 
19544
 
19545
 
19546
 
19547
 
19548
 
19549
 
19550
 
19551
 
19552
 
19553
 
19554
 
19555
 
19556
 
19557
 
19558
 
19559
 
19560
 
19561
 
19562
 
19563
 
19564
 
19565
 
19566
 
19567
 
19568
 
19569
 
19570
 
19571
 
19572
 
19573
 
19574
 
19575
 
19576
 
19577
 
19578
 
19579
 
19580
 
19581
 
19582
 
19583
 
19584
 
19585
 
19586
 
19587
 
19588
 
19589
 
19590
 
19591
 
19592
 
19593
 
19594
 
19595
 
19596
 
19597
 
19598
 
19599
 
19600
 
19601
 
19602
 
19603
 
19604
 
19605
 
19606
 
19607
 
19608
 
19609
 
19610
 
19611
 
19612
 
19613
 
19614
 
19615
 
19616
 
19617
 
19618
 
19619
 
19620
 
19621
 
19622
 
19623
 
19624
 
19625
 
19626
 
19627
 
19628
 
19629
 
19630
 
19631
 
19632
 
19633
 
19634
 
19635
 
19636
 
19637
 
19638
 
19639
 
19640
 
19641
 
19642
 
19643
 
19644
 
19645
 
19646
 
19647
 
19648
 
19649
 
19650
 
19651
 
19652
 
19653
 
19654
 
19655
 
19656
 
19657
 
19658
 
19659
 
19660
 
19661
 
19662
 
19663
 
19664
 
19665
 
19666
 
19667
 
19668
 
19669
 
19670
 
19671
 
19672
 
19673
 
19674
 
19675
 
19676
 
19677
 
19678
 
19679
 
19680
 
19681
 
19682
 
19683
 
19684
 
19685
 
19686
 
19687
 
19688
 
19689
 
19690
 
19691
 
19692
 
19693
 
19694
 
19695
 
19696
 
19697
 
19698
 
19699
 
19700
 
19701
 
19702
 
19703
 
19704
 
19705
 
19706
 
19707
 
19708
 
19709
 
19710
 
19711
 
19712
 
19713
 
19714
 
19715
 
19716
 
19717
 
19718
 
19719
 
19720
 
19721
 
19722
 
19723
 
19724
 
19725
 
19726
 
19727
 
19728
 
19729
 
19730
 
19731
 
19732
 
19733
 
19734
 
19735
 
19736
 
19737
 
19738
 
19739
 
19740
 
19741
 
19742
 
19743
 
19744
 
19745
 
19746
 
19747
 
19748
 
19749
 
19750
 
19751
 
19752
 
19753
 
19754
 
19755
 
19756
 
19757
 
19758
 
19759
 
19760
 
19761
 
19762
 
19763
 
19764
 
19765
 
19766
 
19767
 
19768
 
19769
 
19770
 
19771
 
19772
 
19773
 
19774
 
19775
 
19776
 
19777
 
19778
 
19779
 
19780
 
19781
 
19782
 
19783
 
19784
 
19785
 
19786
 
19787
 
19788
 
19789
 
19790
 
19791
 
19792
 
19793
 
19794
 
19795
 
19796
 
19797
 
19798
 
19799
 
19800
 
19801
 
19802
 
19803
 
19804
 
19805
 
19806
 
19807
 
19808
 
19809
 
19810
 
19811
 
19812
 
19813
 
19814
 
19815
 
19816
 
19817
 
19818
 
19819
 
19820
 
19821
 
19822
 
19823
 
19824
 
19825
 
19826
 
19827
 
19828
 
19829
 
19830
 
19831
 
19832
 
19833
 
19834
 
19835
 
19836
 
19837
 
19838
 
19839
 
19840
 
19841
 
19842
 
19843
 
19844
 
19845
 
19846
 
19847
 
19848
 
19849
 
19850
 
19851
 
19852
 
19853
 
19854
 
19855
 
19856
 
19857
 
19858
 
19859
 
19860
 
19861
 
19862
 
19863
 
19864
 
19865
 
19866
 
19867
 
19868
 
19869
 
19870
 
19871
 
19872
 
19873
 
19874
 
19875
 
19876
 
19877
 
19878
 
19879
 
19880
 
19881
 
19882
 
19883
 
19884
 
19885
 
19886
 
19887
 
19888
 
19889
 
19890
 
19891
 
19892
 
19893
 
19894
 
19895
 
19896
 
19897
 
19898
 
19899
 
19900
 
19901
 
19902
 
19903
 
19904
 
19905
 
19906
 
19907
 
19908
 
19909
 
19910
 
19911
 
19912
 
19913
 
19914
 
19915
 
19916
 
19917
 
19918
 
19919
 
19920
 
19921
 
19922
 
19923
 
19924
 
19925
 
19926
 
19927
 
19928
 
19929
 
19930
 
19931
 
19932
 
19933
 
19934
 
19935
 
19936
 
19937
 
19938
 
19939
 
19940
 
19941
 
19942
 
19943
 
19944
 
19945
 
19946
 
19947
 
19948
 
19949
 
19950
 
19951
 
19952
 
19953
 
19954
 
19955
 
19956
 
19957
 
19958
 
19959
 
19960
 
19961
 
19962
 
19963
 
19964
 
19965
 
19966
 
19967
 
19968
 
19969
 
19970
 
19971
 
19972
 
19973
 
19974
 
19975
 
19976
 
19977
 
19978
 
19979
 
19980
 
19981
 
19982
 
19983
 
19984
 
19985
 
19986
 
19987
 
19988
 
19989
 
19990
 
19991
 
19992
 
19993
 
19994
 
19995
 
19996
 
19997
 
19998
 
19999
 
20000
 
20001
 
20002
 
20003
 
20004
 
20005
 
20006
 
20007
 
20008
 
20009
 
20010
 
20011
 
20012
 
20013
 
20014
 
20015
 
20016
 
20017
 
20018
 
20019
 
20020
 
20021
 
20022
 
20023
 
20024
 
20025
 
20026
 
20027
 
20028
 
20029
 
20030
 
20031
 
20032
 
20033
 
20034
 
20035
 
20036
 
20037
 
20038
 
20039
 
20040
 
20041
 
20042
 
20043
 
20044
 
20045
 
20046
 
20047
 
20048
 
20049
 
20050
 
20051
 
20052
 
20053
 
20054
 
20055
 
20056
 
20057
 
20058
 
20059
 
20060
 
20061
 
20062
 
20063
 
20064
 
20065
 
20066
 
20067
 
20068
 
20069
 
20070
 
20071
 
20072
 
20073
 
20074
 
20075
 
20076
 
20077
 
20078
 
20079
 
20080
 
20081
 
20082
 
20083
 
20084
 
20085
 
20086
 
20087
 
20088
 
20089
 
20090
 
20091
 
20092
 
20093
 
20094
 
20095
 
20096
 
20097
 
20098
 
20099
 
20100
 
20101
 
20102
 
20103
 
20104
 
20105
 
20106
 
20107
 
20108
 
20109
 
20110
 
20111
 
20112
 
20113
 
20114
 
20115
 
20116
 
20117
 
20118
 
20119
 
20120
 
20121
 
20122
 
20123
 
20124
 
20125
 
20126
 
20127
 
20128
 
20129
 
20130
 
20131
 
20132
 
20133
 
20134
 
20135
 
20136
 
20137
 
20138
 
20139
 
20140
 
20141
 
20142
 
20143
 
20144
 
20145
 
20146
 
20147
 
20148
 
20149
 
20150
 
20151
 
20152
 
20153
 
20154
 
20155
 
20156
 
20157
 
20158
 
20159
 
20160
 
20161
 
20162
 
20163
 
20164
 
20165
 
20166
 
20167
 
20168
 
20169
 
20170
 
20171
 
20172
 
20173
 
20174
 
20175
 
20176
 
20177
 
20178
 
20179
 
20180
 
20181
 
20182
 
20183
 
20184
 
20185
 
20186
 
20187
 
20188
 
20189
 
20190
 
20191
 
20192
 
20193
 
20194
 
20195
 
20196
 
20197
 
20198
 
20199
 
20200
 
20201
 
20202
 
20203
 
20204
 
20205
 
20206
 
20207
 
20208
 
20209
 
20210
 
20211
 
20212
 
20213
 
20214
 
20215
 
20216
 
20217
 
20218
 
20219
 
20220
 
20221
 
20222
 
20223
 
20224
 
20225
 
20226
 
20227
 
20228
 
20229
 
20230
 
20231
 
20232
 
20233
 
20234
 
20235
 
20236
 
20237
 
20238
 
20239
 
20240
 
20241
 
20242
 
20243
 
20244
 
20245
 
20246
 
20247
 
20248
 
20249
 
20250
 
20251
 
20252
 
20253
 
20254
 
20255
 
20256
 
20257
 
20258
 
20259
 
20260
 
20261
 
20262
 
20263
 
20264
 
20265
 
20266
 
20267
 
20268
 
20269
 
20270
 
20271
 
20272
 
20273
 
20274
 
20275
 
20276
 
20277
 
20278
 
20279
 
20280
 
20281
 
20282
 
20283
 
20284
 
20285
 
20286
 
20287
 
20288
 
20289
 
20290
 
20291
 
20292
 
20293
 
20294
 
20295
 
20296
 
20297
 
20298
 
20299
 
20300
 
20301
 
20302
 
20303
 
20304
 
20305
 
20306
 
20307
 
20308
 
20309
 
20310
 
20311
 
20312
 
20313
 
20314
 
20315
 
20316
 
20317
 
20318
 
20319
 
20320
 
20321
 
20322
 
20323
 
20324
 
20325
 
20326
 
20327
 
20328
 
20329
 
20330
 
20331
 
20332
 
20333
 
20334
 
20335
 
20336
 
20337
 
20338
 
20339
 
20340
 
20341
 
20342
 
20343
 
20344
 
20345
 
20346
 
20347
 
20348
 
20349
 
20350
 
20351
 
20352
 
20353
 
20354
 
20355
 
20356
 
20357
 
20358
 
20359
 
20360
 
20361
 
20362
 
20363
 
20364
 
20365
 
20366
 
20367
 
20368
 
20369
 
20370
 
20371
 
20372
 
20373
 
20374
 
20375
 
20376
 
20377
 
20378
 
20379
 
20380
 
20381
 
20382
 
20383
 
20384
 
20385
 
20386
 
20387
 
20388
 
20389
 
20390
 
20391
 
20392
 
20393
 
20394
 
20395
 
20396
 
20397
 
20398
 
20399
 
20400
 
20401
 
20402
 
20403
 
20404
 
20405
 
20406
 
20407
 
20408
 
20409
 
20410
 
20411
 
20412
 
20413
 
20414
 
20415
 
20416
 
20417
 
20418
 
20419
 
20420
 
20421
 
20422
 
20423
 
20424
 
20425
 
20426
 
20427
 
20428
 
20429
 
20430
 
20431
 
20432
 
20433
 
20434
 
20435
 
20436
 
20437
 
20438
 
20439
 
20440
 
20441
 
20442
 
20443
 
20444
 
20445
 
20446
 
20447
 
20448
 
20449
 
20450
 
20451
 
20452
 
20453
 
20454
 
20455
 
20456
 
20457
 
20458
 
20459
 
20460
 
20461
 
20462
 
20463
 
20464
 
20465
 
20466
 
20467
 
20468
 
20469
 
20470
 
20471
 
20472
 
20473
 
20474
 
20475
 
20476
 
20477
 
20478
 
20479
 
20480
 
20481
 
20482
 
20483
 
20484
 
20485
 
20486
 
20487
 
20488
 
20489
 
20490
 
20491
 
20492
 
20493
 
20494
 
20495
 
20496
 
20497
 
20498
 
20499
 
20500
 
20501
 
20502
 
20503
 
20504
 
20505
 
20506
 
20507
 
20508
 
20509
 
20510
 
20511
 
20512
 
20513
 
20514
 
20515
 
20516
 
20517
 
20518
 
20519
 
20520
 
20521
 
20522
 
20523
 
20524
 
20525
 
20526
 
20527
 
20528
 
20529
 
20530
 
20531
 
20532
 
20533
 
20534
 
20535
 
20536
 
20537
 
20538
 
20539
 
20540
 
20541
 
20542
 
20543
 
20544
 
20545
 
20546
 
20547
 
20548
 
20549
 
20550
 
20551
 
20552
 
20553
 
20554
 
20555
 
20556
 
20557
 
20558
 
20559
 
20560
 
20561
 
20562
 
20563
 
20564
 
20565
 
20566
 
20567
 
20568
 
20569
 
20570
 
20571
 
20572
 
20573
 
20574
 
20575
 
20576
 
20577
 
20578
 
20579
 
20580
 
20581
 
20582
 
20583
 
20584
 
20585
 
20586
 
20587
 
20588
 
20589
 
20590
 
20591
 
20592
 
20593
 
20594
 
20595
 
20596
 
20597
 
20598
 
20599
 
20600
 
20601
 
20602
 
20603
 
20604
 
20605
 
20606
 
20607
 
20608
 
20609
 
20610
 
20611
 
20612
 
20613
 
20614
 
20615
 
20616
 
20617
 
20618
 
20619
 
20620
 
20621
 
20622
 
20623
 
20624
 
20625
 
20626
 
20627
 
20628
 
20629
 
20630
 
20631
 
20632
 
20633
 
20634
 
20635
 
20636
 
20637
 
20638
 
20639
 
20640
 
20641
 
20642
 
20643
 
20644
 
20645
 
20646
 
20647
 
20648
 
20649
 
20650
 
20651
 
20652
 
20653
 
20654
 
20655
 
20656
 
20657
 
20658
 
20659
 
20660
 
20661
 
20662
 
20663
 
20664
 
20665
 
20666
 
20667
 
20668
 
20669
 
20670
 
20671
 
20672
 
20673
 
20674
 
20675
 
20676
 
20677
 
20678
 
20679
 
20680
 
20681
 
20682
 
20683
 
20684
 
20685
 
20686
 
20687
 
20688
 
20689
 
20690
 
20691
 
20692
 
20693
 
20694
 
20695
 
20696
 
20697
 
20698
 
20699
 
20700
 
20701
 
20702
 
20703
 
20704
 
20705
 
20706
 
20707
 
20708
 
20709
 
20710
 
20711
 
20712
 
20713
 
20714
 
20715
 
20716
 
20717
 
20718
 
20719
 
20720
 
20721
 
20722
 
20723
 
20724
 
20725
 
20726
 
20727
 
20728
 
20729
 
20730
 
20731
 
20732
 
20733
 
20734
 
20735
 
20736
 
20737
 
20738
 
20739
 
20740
 
20741
 
20742
 
20743
 
20744
 
20745
 
20746
 
20747
 
20748
 
20749
 
20750
 
20751
 
20752
 
20753
 
20754
 
20755
 
20756
 
20757
 
20758
 
20759
 
20760
 
20761
 
20762
 
20763
 
20764
 
20765
 
20766
 
20767
 
20768
 
20769
 
20770
 
20771
 
20772
 
20773
 
20774
 
20775
 
20776
 
20777
 
20778
 
20779
 
20780
 
20781
 
20782
 
20783
 
20784
 
20785
 
20786
 
20787
 
20788
 
20789
 
20790
 
20791
 
20792
 
20793
 
20794
 
20795
 
20796
 
20797
 
20798
 
20799
 
20800
 
20801
 
20802
 
20803
 
20804
 
20805
 
20806
 
20807
 
20808
 
20809
 
20810
 
20811
 
20812
 
20813
 
20814
 
20815
 
20816
 
20817
 
20818
 
20819
 
20820
 
20821
 
20822
 
20823
 
20824
 
20825
 
20826
 
20827
 
20828
 
20829
 
20830
 
20831
 
20832
 
20833
 
20834
 
20835
 
20836
 
20837
 
20838
 
20839
 
20840
 
20841
 
20842
 
20843
 
20844
 
20845
 
20846
 
20847
 
20848
 
20849
 
20850
 
20851
 
20852
 
20853
 
20854
 
20855
 
20856
 
20857
 
20858
 
20859
 
20860
 
20861
 
20862
 
20863
 
20864
 
20865
 
20866
 
20867
 
20868
 
20869
 
20870
 
20871
 
20872
 
20873
 
20874
 
20875
 
20876
 
20877
 
20878
 
20879
 
20880
 
20881
 
20882
 
20883
 
20884
 
20885
 
20886
 
20887
 
20888
 
20889
 
20890
 
20891
 
20892
 
20893
 
20894
 
20895
 
20896
 
20897
 
20898
 
20899
 
20900
 
20901
 
20902
 
20903
 
20904
 
20905
 
20906
 
20907
 
20908
 
20909
 
20910
 
20911
 
20912
 
20913
 
20914
 
20915
 
20916
 
20917
 
20918
 
20919
 
20920
 
20921
 
20922
 
20923
 
20924
 
20925
 
20926
 
20927
 
20928
 
20929
 
20930
 
20931
 
20932
 
20933
 
20934
 
20935
 
20936
 
20937
 
20938
 
20939
 
20940
 
20941
 
20942
 
20943
 
20944
 
20945
 
20946
 
20947
 
20948
 
20949
 
20950
 
20951
 
20952
 
20953
 
20954
 
20955
 
20956
 
20957
 
20958
 
20959
 
20960
 
20961
 
20962
 
20963
 
20964
 
20965
 
20966
 
20967
 
20968
 
20969
 
20970
 
20971
 
20972
 
20973
 
20974
 
20975
 
20976
 
20977
 
20978
 
20979
 
20980
 
20981
 
20982
 
20983
 
20984
 
20985
 
20986
 
20987
 
20988
 
20989
 
20990
 
20991
 
20992
 
20993
 
20994
 
20995
 
20996
 
20997
 
20998
 
20999
 
21000
 
21001
 
21002
 
21003
 
21004
 
21005
 
21006
 
21007
 
21008
 
21009
 
21010
 
21011
 
21012
 
21013
 
21014
 
21015
 
21016
 
21017
 
21018
 
21019
 
21020
 
21021
 
21022
 
21023
 
21024
 
21025
 
21026
 
21027
 
21028
 
21029
 
21030
 
21031
 
21032
 
21033
 
21034
 
21035
 
21036
 
21037
 
21038
 
21039
 
21040
 
21041
 
21042
 
21043
 
21044
 
21045
 
21046
 
21047
 
21048
 
21049
 
21050
 
21051
 
21052
 
21053
 
21054
 
21055
 
21056
 
21057
 
21058
 
21059
 
21060
 
21061
 
21062
 
21063
 
21064
 
21065
 
21066
 
21067
 
21068
 
21069
 
21070
 
21071
 
21072
 
21073
 
21074
 
21075
 
21076
 
21077
 
21078
 
21079
 
21080
 
21081
 
21082
 
21083
 
21084
 
21085
 
21086
 
21087
 
21088
 
21089
 
21090
 
21091
 
21092
 
21093
 
21094
 
21095
 
21096
 
21097
 
21098
 
21099
 
21100
 
21101
 
21102
 
21103
 
21104
 
21105
 
21106
 
21107
 
21108
 
21109
 
21110
 
21111
 
21112
 
21113
 
21114
 
21115
 
21116
 
21117
 
21118
 
21119
 
21120
 
21121
 
21122
 
21123
 
21124
 
21125
 
21126
 
21127
 
21128
 
21129
 
21130
 
21131
 
21132
 
21133
 
21134
 
21135
 
21136
 
21137
 
21138
 
21139
 
21140
 
21141
 
21142
 
21143
 
21144
 
21145
 
21146
 
21147
 
21148
 
21149
 
21150
 
21151
 
21152
 
21153
 
21154
 
21155
 
21156
 
21157
 
21158
 
21159
 
21160
 
21161
 
21162
 
21163
 
21164
 
21165
 
21166
 
21167
 
21168
 
21169
 
21170
 
21171
 
21172
 
21173
 
21174
 
21175
 
21176
 
21177
 
21178
 
21179
 
21180
 
21181
 
21182
 
21183
 
21184
 
21185
 
21186
 
21187
 
21188
 
21189
 
21190
 
21191
 
21192
 
21193
 
21194
 
21195
 
21196
 
21197
 
21198
 
21199
 
21200
 
21201
 
21202
 
21203
 
21204
 
21205
 
21206
 
21207
 
21208
 
21209
 
21210
 
21211
 
21212
 
21213
 
21214
 
21215
 
21216
 
21217
 
21218
 
21219
 
21220
 
21221
 
21222
 
21223
 
21224
 
21225
 
21226
 
21227
 
21228
 
21229
 
21230
 
21231
 
21232
 
21233
 
21234
 
21235
 
21236
 
21237
 
21238
 
21239
 
21240
 
21241
 
21242
 
21243
 
21244
 
21245
 
21246
 
21247
 
21248
 
21249
 
21250
 
21251
 
21252
 
21253
 
21254
 
21255
 
21256
 
21257
 
21258
 
21259
 
21260
 
21261
 
21262
 
21263
 
21264
 
21265
 
21266
 
21267
 
21268
 
21269
 
21270
 
21271
 
21272
 
21273
 
21274
 
21275
 
21276
 
21277
 
21278
 
21279
 
21280
 
21281
 
21282
 
21283
 
21284
 
21285
 
21286
 
21287
 
21288
 
21289
 
21290
 
21291
 
21292
 
21293
 
21294
 
21295
 
21296
 
21297
 
21298
 
21299
 
21300
 
21301
 
21302
 
21303
 
21304
 
21305
 
21306
 
21307
 
21308
 
21309
 
21310
 
21311
 
21312
 
21313
 
21314
 
21315
 
21316
 
21317
 
21318
 
21319
 
21320
 
21321
 
21322
 
21323
 
21324
 
21325
 
21326
 
21327
 
21328
 
21329
 
21330
 
21331
 
21332
 
21333
 
21334
 
21335
 
21336
 
21337
 
21338
 
21339
 
21340
 
21341
 
21342
 
21343
 
21344
 
21345
 
21346
 
21347
 
21348
 
21349
 
21350
 
21351
 
21352
 
21353
 
21354
 
21355
 
21356
 
21357
 
21358
 
21359
 
21360
 
21361
 
21362
 
21363
 
21364
 
21365
 
21366
 
21367
 
21368
 
21369
 
21370
 
21371
 
21372
 
21373
 
21374
 
21375
 
21376
 
21377
 
21378
 
21379
 
21380
 
21381
 
21382
 
21383
 
21384
 
21385
 
21386
 
21387
 
21388
 
21389
 
21390
 
21391
 
21392
 
21393
 
21394
 
21395
 
21396
 
21397
 
21398
 
21399
 
21400
 
21401
 
21402
 
21403
 
21404
 
21405
 
21406
 
21407
 
21408
 
21409
 
21410
 
21411
 
21412
 
21413
 
21414
 
21415
 
21416
 
21417
 
21418
 
21419
 
21420
 
21421
 
21422
 
21423
 
21424
 
21425
 
21426
 
21427
 
21428
 
21429
 
21430
 
21431
 
21432
 
21433
 
21434
 
21435
 
21436
 
21437
 
21438
 
21439
 
21440
 
21441
 
21442
 
21443
 
21444
 
21445
 
21446
 
21447
 
21448
 
21449
 
21450
 
21451
 
21452
 
21453
 
21454
 
21455
 
21456
 
21457
 
21458
 
21459
 
21460
 
21461
 
21462
 
21463
 
21464
 
21465
 
21466
 
21467
 
21468
 
21469
 
21470
 
21471
 
21472
 
21473
 
21474
 
21475
 
21476
 
21477
 
21478
 
21479
 
21480
 
21481
 
21482
 
21483
 
21484
 
21485
 
21486
 
21487
 
21488
 
21489
 
21490
 
21491
 
21492
 
21493
 
21494
 
21495
 
21496
 
21497
 
21498
 
21499
 
21500
 
21501
 
21502
 
21503
 
21504
 
21505
 
21506
 
21507
 
21508
 
21509
 
21510
 
21511
 
21512
 
21513
 
21514
 
21515
 
21516
 
21517
 
21518
 
21519
 
21520
 
21521
 
21522
 
21523
 
21524
 
21525
 
21526
 
21527
 
21528
 
21529
 
21530
 
21531
 
21532
 
21533
 
21534
 
21535
 
21536
 
21537
 
21538
 
21539
 
21540
 
21541
 
21542
 
21543
 
21544
 
21545
 
21546
 
21547
 
21548
 
21549
 
21550
 
21551
 
21552
 
21553
 
21554
 
21555
 
21556
 
21557
 
21558
 
21559
 
21560
 
21561
 
21562
 
21563
 
21564
 
21565
 
21566
 
21567
 
21568
 
21569
 
21570
 
21571
 
21572
 
21573
 
21574
 
21575
 
21576
 
21577
 
21578
 
21579
 
21580
 
21581
 
21582
 
21583
 
21584
 
21585
 
21586
 
21587
 
21588
 
21589
 
21590
 
21591
 
21592
 
21593
 
21594
 
21595
 
21596
 
21597
 
21598
 
21599
 
21600
 
21601
 
21602
 
21603
 
21604
 
21605
 
21606
 
21607
 
21608
 
21609
 
21610
 
21611
 
21612
 
21613
 
21614
 
21615
 
21616
 
21617
 
21618
 
21619
 
21620
 
21621
 
21622
 
21623
 
21624
 
21625
 
21626
 
21627
 
21628
 
21629
 
21630
 
21631
 
21632
 
21633
 
21634
 
21635
 
21636
 
21637
 
21638
 
21639
 
21640
 
21641
 
21642
 
21643
 
21644
 
21645
 
21646
 
21647
 
21648
 
21649
 
21650
 
21651
 
21652
 
21653
 
21654
 
21655
 
21656
 
21657
 
21658
 
21659
 
21660
 
21661
 
21662
 
21663
 
21664
 
21665
 
21666
 
21667
 
21668
 
21669
 
21670
 
21671
 
21672
 
21673
 
21674
 
21675
 
21676
 
21677
 
21678
 
21679
 
21680
 
21681
 
21682
 
21683
 
21684
 
21685
 
21686
 
21687
 
21688
 
21689
 
21690
 
21691
 
21692
 
21693
 
21694
 
21695
 
21696
 
21697
 
21698
 
21699
 
21700
 
21701
 
21702
 
21703
 
21704
 
21705
 
21706
 
21707
 
21708
 
21709
 
21710
 
21711
 
21712
 
21713
 
21714
 
21715
 
21716
 
21717
 
21718
 
21719
 
21720
 
21721
 
21722
 
21723
 
21724
 
21725
 
21726
 
21727
 
21728
 
21729
 
21730
 
21731
 
21732
 
21733
 
21734
 
21735
 
21736
 
21737
 
21738
 
21739
 
21740
 
21741
 
21742
 
21743
 
21744
 
21745
 
21746
 
21747
 
21748
 
21749
 
21750
 
21751
 
21752
 
21753
 
21754
 
21755
 
21756
 
21757
 
21758
 
21759
 
21760
 
21761
 
21762
 
21763
 
21764
 
21765
 
21766
 
21767
 
21768
 
21769
 
21770
 
21771
 
21772
 
21773
 
21774
 
21775
 
21776
 
21777
 
21778
 
21779
 
21780
 
21781
 
21782
 
21783
 
21784
 
21785
 
21786
 
21787
 
21788
 
21789
 
21790
 
21791
 
21792
 
21793
 
21794
 
21795
 
21796
 
21797
 
21798
 
21799
 
21800
 
21801
 
21802
 
21803
 
21804
 
21805
 
21806
 
21807
 
21808
 
21809
 
21810
 
21811
 
21812
 
21813
 
21814
 
21815
 
21816
 
21817
 
21818
 
21819
 
21820
 
21821
 
21822
 
21823
 
21824
 
21825
 
21826
 
21827
 
21828
 
21829
 
21830
 
21831
 
21832
 
21833
 
21834
 
21835
 
21836
 
21837
 
21838
 
21839
 
21840
 
21841
 
21842
 
21843
 
21844
 
21845
 
21846
 
21847
 
21848
 
21849
 
21850
 
21851
 
21852
 
21853
 
21854
 
21855
 
21856
 
21857
 
21858
 
21859
 
21860
 
21861
 
21862
 
21863
 
21864
 
21865
 
21866
 
21867
 
21868
 
21869
 
21870
 
21871
 
21872
 
21873
 
21874
 
21875
 
21876
 
21877
 
21878
 
21879
 
21880
 
21881
 
21882
 
21883
 
21884
 
21885
 
21886
 
21887
 
21888
 
21889
 
21890
 
21891
 
21892
 
21893
 
21894
 
21895
 
21896
 
21897
 
21898
 
21899
 
21900
 
21901
 
21902
 
21903
 
21904
 
21905
 
21906
 
21907
 
21908
 
21909
 
21910
 
21911
 
21912
 
21913
 
21914
 
21915
 
21916
 
21917
 
21918
 
21919
 
21920
 
21921
 
21922
 
21923
 
21924
 
21925
 
21926
 
21927
 
21928
 
21929
 
21930
 
21931
 
21932
 
21933
 
21934
 
21935
 
21936
 
21937
 
21938
 
21939
 
21940
 
21941
 
21942
 
21943
 
21944
 
21945
 
21946
 
21947
 
21948
 
21949
 
21950
 
21951
 
21952
 
21953
 
21954
 
21955
 
21956
 
21957
 
21958
 
21959
 
21960
 
21961
 
21962
 
21963
 
21964
 
21965
 
21966
 
21967
 
21968
 
21969
 
21970
 
21971
 
21972
 
21973
 
21974
 
21975
 
21976
 
21977
 
21978
 
21979
 
21980
 
21981
 
21982
 
21983
 
21984
 
21985
 
21986
 
21987
 
21988
 
21989
 
21990
 
21991
 
21992
 
21993
 
21994
 
21995
 
21996
 
21997
 
21998
 
21999
 
22000
 
22001
 
22002
 
22003
 
22004
 
22005
 
22006
 
22007
 
22008
 
22009
 
22010
 
22011
 
22012
 
22013
 
22014
 
22015
 
22016
 
22017
 
22018
 
22019
 
22020
 
22021
 
22022
 
22023
 
22024
 
22025
 
22026
 
22027
 
22028
 
22029
 
22030
 
22031
 
22032
 
22033
 
22034
 
22035
 
22036
 
22037
 
22038
 
22039
 
22040
 
22041
 
22042
 
22043
 
22044
 
22045
 
22046
 
22047
 
22048
 
22049
 
22050
 
22051
 
22052
 
22053
 
22054
 
22055
 
22056
 
22057
 
22058
 
22059
 
22060
 
22061
 
22062
 
22063
 
22064
 
22065
 
22066
 
22067
 
22068
 
22069
 
22070
 
22071
 
22072
 
22073
 
22074
 
22075
 
22076
 
22077
 
22078
 
22079
 
22080
 
22081
 
22082
 
22083
 
22084
 
22085
 
22086
 
22087
 
22088
 
22089
 
22090
 
22091
 
22092
 
22093
 
22094
 
22095
 
22096
 
22097
 
22098
 
22099
 
22100
 
22101
 
22102
 
22103
 
22104
 
22105
 
22106
 
22107
 
22108
 
22109
 
22110
 
22111
 
22112
 
22113
 
22114
 
22115
 
22116
 
22117
 
22118
 
22119
 
22120
 
22121
 
22122
 
22123
 
22124
 
22125
 
22126
 
22127
 
22128
 
22129
 
22130
 
22131
 
22132
 
22133
 
22134
 
22135
 
22136
 
22137
 
22138
 
22139
 
22140
 
22141
 
22142
 
22143
 
22144
 
22145
 
22146
 
22147
 
22148
 
22149
 
22150
 
22151
 
22152
 
22153
 
22154
 
22155
 
22156
 
22157
 
22158
 
22159
 
22160
 
22161
 
22162
 
22163
 
22164
 
22165
 
22166
 
22167
 
22168
 
22169
 
22170
 
22171
 
22172
 
22173
 
22174
 
22175
 
22176
 
22177
 
22178
 
22179
 
22180
 
22181
 
22182
 
22183
 
22184
 
22185
 
22186
 
22187
 
22188
 
22189
 
22190
 
22191
 
22192
 
22193
 
22194
 
22195
 
22196
 
22197
 
22198
 
22199
 
22200
 
22201
 
22202
 
22203
 
22204
 
22205
 
22206
 
22207
 
22208
 
22209
 
22210
 
22211
 
22212
 
22213
 
22214
 
22215
 
22216
 
22217
 
22218
 
22219
 
22220
 
22221
 
22222
 
22223
 
22224
 
22225
 
22226
 
22227
 
22228
 
22229
 
22230
 
22231
 
22232
 
22233
 
22234
 
22235
 
22236
 
22237
 
22238
 
22239
 
22240
 
22241
 
22242
 
22243
 
22244
 
22245
 
22246
 
22247
 
22248
 
22249
 
22250
 
22251
 
22252
 
22253
 
22254
 
22255
 
22256
 
22257
 
22258
 
22259
 
22260
 
22261
 
22262
 
22263
 
22264
 
22265
 
22266
 
22267
 
22268
 
22269
 
22270
 
22271
 
22272
 
22273
 
22274
 
22275
 
22276
 
22277
 
22278
 
22279
 
22280
 
22281
 
22282
 
22283
 
22284
 
22285
 
22286
 
22287
 
22288
 
22289
 
22290
 
22291
 
22292
 
22293
 
22294
 
22295
 
22296
 
22297
 
22298
 
22299
 
22300
 
22301
 
22302
 
22303
 
22304
 
22305
 
22306
 
22307
 
22308
 
22309
 
22310
 
22311
 
22312
 
22313
 
22314
 
22315
 
22316
 
22317
 
22318
 
22319
 
22320
 
22321
 
22322
 
22323
 
22324
 
22325
 
22326
 
22327
 
22328
 
22329
 
22330
 
22331
 
22332
 
22333
 
22334
 
22335
 
22336
 
22337
 
22338
 
22339
 
22340
 
22341
 
22342
 
22343
 
22344
 
22345
 
22346
 
22347
 
22348
 
22349
 
22350
 
22351
 
22352
 
22353
 
22354
 
22355
 
22356
 
22357
 
22358
 
22359
 
22360
 
22361
 
22362
 
22363
 
22364
 
22365
 
22366
 
22367
 
22368
 
22369
 
22370
 
22371
 
22372
 
22373
 
22374
 
22375
 
22376
 
22377
 
22378
 
22379
 
22380
 
22381
 
22382
 
22383
 
22384
 
22385
 
22386
 
22387
 
22388
 
22389
 
22390
 
22391
 
22392
 
22393
 
22394
 
22395
 
22396
 
22397
 
22398
 
22399
 
22400
 
22401
 
22402
 
22403
 
22404
 
22405
 
22406
 
22407
 
22408
 
22409
 
22410
 
22411
 
22412
 
22413
 
22414
 
22415
 
22416
 
22417
 
22418
 
22419
 
22420
 
22421
 
22422
 
22423
 
22424
 
22425
 
22426
 
22427
 
22428
 
22429
 
22430
 
22431
 
22432
 
22433
 
22434
 
22435
 
22436
 
22437
 
22438
 
22439
 
22440
 
22441
 
22442
 
22443
 
22444
 
22445
 
22446
 
22447
 
22448
 
22449
 
22450
 
22451
 
22452
 
22453
 
22454
 
22455
 
22456
 
22457
 
22458
 
22459
 
22460
 
22461
 
22462
 
22463
 
22464
 
22465
 
22466
 
22467
 
22468
 
22469
 
22470
 
22471
 
22472
 
22473
 
22474
 
22475
 
22476
 
22477
 
22478
 
22479
 
22480
 
22481
 
22482
 
22483
 
22484
 
22485
 
22486
 
22487
 
22488
 
22489
 
22490
 
22491
 
22492
 
22493
 
22494
 
22495
 
22496
 
22497
 
22498
 
22499
 
22500
 
22501
 
22502
 
22503
 
22504
 
22505
 
22506
 
22507
 
22508
 
22509
 
22510
 
22511
 
22512
 
22513
 
22514
 
22515
 
22516
 
22517
 
22518
 
22519
 
22520
 
22521
 
22522
 
22523
 
22524
 
22525
 
22526
 
22527
 
22528
 
22529
 
22530
 
22531
 
22532
 
22533
 
22534
 
22535
 
22536
 
22537
 
22538
 
22539
 
22540
 
22541
 
22542
 
22543
 
22544
 
22545
 
22546
 
22547
 
22548
 
22549
 
22550
 
22551
 
22552
 
22553
 
22554
 
22555
 
22556
 
22557
 
22558
 
22559
 
22560
 
22561
 
22562
 
22563
 
22564
 
22565
 
22566
 
22567
 
22568
 
22569
 
22570
 
22571
 
22572
 
22573
 
22574
 
22575
 
22576
 
22577
 
22578
 
22579
 
22580
 
22581
 
22582
 
22583
 
22584
 
22585
 
22586
 
22587
 
22588
 
22589
 
22590
 
22591
 
22592
 
22593
 
22594
 
22595
 
22596
 
22597
 
22598
 
22599
 
22600
 
22601
 
22602
 
22603
 
22604
 
22605
 
22606
 
22607
 
22608
 
22609
 
22610
 
22611
 
22612
 
22613
 
22614
 
22615
 
22616
 
22617
 
22618
 
22619
 
22620
 
22621
 
22622
 
22623
 
22624
 
22625
 
22626
 
22627
 
22628
 
22629
 
22630
 
22631
 
22632
 
22633
 
22634
 
22635
 
22636
 
22637
 
22638
 
22639
 
22640
 
22641
 
22642
 
22643
 
22644
 
22645
 
22646
 
22647
 
22648
 
22649
 
22650
 
22651
 
22652
 
22653
 
22654
 
22655
 
22656
 
22657
 
22658
 
22659
 
22660
 
22661
 
22662
 
22663
 
22664
 
22665
 
22666
 
22667
 
22668
 
22669
 
22670
 
22671
 
22672
 
22673
 
22674
 
22675
 
22676
 
22677
 
22678
 
22679
 
22680
 
22681
 
22682
 
22683
 
22684
 
22685
 
22686
 
22687
 
22688
 
22689
 
22690
 
22691
 
22692
 
22693
 
22694
 
22695
 
22696
 
22697
 
22698
 
22699
 
22700
 
22701
 
22702
 
22703
 
22704
 
22705
 
22706
 
22707
 
22708
 
22709
 
22710
 
22711
 
22712
 
22713
 
22714
 
22715
 
22716
 
22717
 
22718
 
22719
 
22720
 
22721
 
22722
 
22723
 
22724
 
22725
 
22726
 
22727
 
22728
 
22729
 
22730
 
22731
 
22732
 
22733
 
22734
 
22735
 
22736
 
22737
 
22738
 
22739
 
22740
 
22741
 
22742
 
22743
 
22744
 
22745
 
22746
 
22747
 
22748
 
22749
 
22750
 
22751
 
22752
 
22753
 
22754
 
22755
 
22756
 
22757
 
22758
 
22759
 
22760
 
22761
 
22762
 
22763
 
22764
 
22765
 
22766
 
22767
 
22768
 
22769
 
22770
 
22771
 
22772
 
22773
 
22774
 
22775
 
22776
 
22777
 
22778
 
22779
 
22780
 
22781
 
22782
 
22783
 
22784
 
22785
 
22786
 
22787
 
22788
 
22789
 
22790
 
22791
 
22792
 
22793
 
22794
 
22795
 
22796
 
22797
 
22798
 
22799
 
22800
 
22801
 
22802
 
22803
 
22804
 
22805
 
22806
 
22807
 
22808
 
22809
 
22810
 
22811
 
22812
 
22813
 
22814
 
22815
 
22816
 
22817
 
22818
 
22819
 
22820
 
22821
 
22822
 
22823
 
22824
 
22825
 
22826
 
22827
 
22828
 
22829
 
22830
 
22831
 
22832
 
22833
 
22834
 
22835
 
22836
 
22837
 
22838
 
22839
 
22840
 
22841
 
22842
 
22843
 
22844
 
22845
 
22846
 
22847
 
22848
 
22849
 
22850
 
22851
 
22852
 
22853
 
22854
 
22855
 
22856
 
22857
 
22858
 
22859
 
22860
 
22861
 
22862
 
22863
 
22864
 
22865
 
22866
 
22867
 
22868
 
22869
 
22870
 
22871
 
22872
 
22873
 
22874
 
22875
 
22876
 
22877
 
22878
 
22879
 
22880
 
22881
 
22882
 
22883
 
22884
 
22885
 
22886
 
22887
 
22888
 
22889
 
22890
 
22891
 
22892
 
22893
 
22894
 
22895
 
22896
 
22897
 
22898
 
22899
 
22900
 
22901
 
22902
 
22903
 
22904
 
22905
 
22906
 
22907
 
22908
 
22909
 
22910
 
22911
 
22912
 
22913
 
22914
 
22915
 
22916
 
22917
 
22918
 
22919
 
22920
 
22921
 
22922
 
22923
 
22924
 
22925
 
22926
 
22927
 
22928
 
22929
 
22930
 
22931
 
22932
 
22933
 
22934
 
22935
 
22936
 
22937
 
22938
 
22939
 
22940
 
22941
 
22942
 
22943
 
22944
 
22945
 
22946
 
22947
 
22948
 
22949
 
22950
 
22951
 
22952
 
22953
 
22954
 
22955
 
22956
 
22957
 
22958
 
22959
 
22960
 
22961
 
22962
 
22963
 
22964
 
22965
 
22966
 
22967
 
22968
 
22969
 
22970
 
22971
 
22972
 
22973
 
22974
 
22975
 
22976
 
22977
 
22978
 
22979
 
22980
 
22981
 
22982
 
22983
 
22984
 
22985
 
22986
 
22987
 
22988
 
22989
 
22990
 
22991
 
22992
 
22993
 
22994
 
22995
 
22996
 
22997
 
22998
 
22999
 
23000
 
23001
 
23002
 
23003
 
23004
 
23005
 
23006
 
23007
 
23008
 
23009
 
23010
 
23011
 
23012
 
23013
 
23014
 
23015
 
23016
 
23017
 
23018
 
23019
 
23020
 
23021
 
23022
 
23023
 
23024
 
23025
 
23026
 
23027
 
23028
 
23029
 
23030
 
23031
 
23032
 
23033
 
23034
 
23035
 
23036
 
23037
 
23038
 
23039
 
23040
 
23041
 
23042
 
23043
 
23044
 
23045
 
23046
 
23047
 
23048
 
23049
 
23050
 
23051
 
23052
 
23053
 
23054
 
23055
 
23056
 
23057
 
23058
 
23059
 
23060
 
23061
 
23062
 
23063
 
23064
 
23065
 
23066
 
23067
 
23068
 
23069
 
23070
 
23071
 
23072
 
23073
 
23074
 
23075
 
23076
 
23077
 
23078
 
23079
 
23080
 
23081
 
23082
 
23083
 
23084
 
23085
 
23086
 
23087
 
23088
 
23089
 
23090
 
23091
 
23092
 
23093
 
23094
 
23095
 
23096
 
23097
 
23098
 
23099
 
23100
 
23101
 
23102
 
23103
 
23104
 
23105
 
23106
 
23107
 
23108
 
23109
 
23110
 
23111
 
23112
 
23113
 
23114
 
23115
 
23116
 
23117
 
23118
 
23119
 
23120
 
23121
 
23122
 
23123
 
23124
 
23125
 
23126
 
23127
 
23128
 
23129
 
23130
 
23131
 
23132
 
23133
 
23134
 
23135
 
23136
 
23137
 
23138
 
23139
 
23140
 
23141
 
23142
 
23143
 
23144
 
23145
 
23146
 
23147
 
23148
 
23149
 
23150
 
23151
 
23152
 
23153
 
23154
 
23155
 
23156
 
23157
 
23158
 
23159
 
23160
 
23161
 
23162
 
23163
 
23164
 
23165
 
23166
 
23167
 
23168
 
23169
 
23170
 
23171
 
23172
 
23173
 
23174
 
23175
 
23176
 
23177
 
23178
 
23179
 
23180
 
23181
 
23182
 
23183
 
23184
 
23185
 
23186
 
23187
 
23188
 
23189
 
23190
 
23191
 
23192
 
23193
 
23194
 
23195
 
23196
 
23197
 
23198
 
23199
 
23200
 
23201
 
23202
 
23203
 
23204
 
23205
 
23206
 
23207
 
23208
 
23209
 
23210
 
23211
 
23212
 
23213
 
23214
 
23215
 
23216
 
23217
 
23218
 
23219
 
23220
 
23221
 
23222
 
23223
 
23224
 
23225
 
23226
 
23227
 
23228
 
23229
 
23230
 
23231
 
23232
 
23233
 
23234
 
23235
 
23236
 
23237
 
23238
 
23239
 
23240
 
23241
 
23242
 
23243
 
23244
 
23245
 
23246
 
23247
 
23248
 
23249
 
23250
 
23251
 
23252
 
23253
 
23254
 
23255
 
23256
 
23257
 
23258
 
23259
 
23260
 
23261
 
23262
 
23263
 
23264
 
23265
 
23266
 
23267
 
23268
 
23269
 
23270
 
23271
 
23272
 
23273
 
23274
 
23275
 
23276
 
23277
 
23278
 
23279
 
23280
 
23281
 
23282
 
23283
 
23284
 
23285
 
23286
 
23287
 
23288
 
23289
 
23290
 
23291
 
23292
 
23293
 
23294
 
23295
 
23296
 
23297
 
23298
 
23299
 
23300
 
23301
 
23302
 
23303
 
23304
 
23305
 
23306
 
23307
 
23308
 
23309
 
23310
 
23311
 
23312
 
23313
 
23314
 
23315
 
23316
 
23317
 
23318
 
23319
 
23320
 
23321
 
23322
 
23323
 
23324
 
23325
 
23326
 
23327
 
23328
 
23329
 
23330
 
23331
 
23332
 
23333
 
23334
 
23335
 
23336
 
23337
 
23338
 
23339
 
23340
 
23341
 
23342
 
23343
 
23344
 
23345
 
23346
 
23347
 
23348
 
23349
 
23350
 
23351
 
23352
 
23353
 
23354
 
23355
 
23356
 
23357
 
23358
 
23359
 
23360
 
23361
 
23362
 
23363
 
23364
 
23365
 
23366
 
23367
 
23368
 
23369
 
23370
 
23371
 
23372
 
23373
 
23374
 
23375
 
23376
 
23377
 
23378
 
23379
 
23380
 
23381
 
23382
 
23383
 
23384
 
23385
 
23386
 
23387
 
23388
 
23389
 
23390
 
23391
 
23392
 
23393
 
23394
 
23395
 
23396
 
23397
 
23398
 
23399
 
23400
 
23401
 
23402
 
23403
 
23404
 
23405
 
23406
 
23407
 
23408
 
23409
 
23410
 
23411
 
23412
 
23413
 
23414
 
23415
 
23416
 
23417
 
23418
 
23419
 
23420
 
23421
 
23422
 
23423
 
23424
 
23425
 
23426
 
23427
 
23428
 
23429
 
23430
 
23431
 
23432
 
23433
 
23434
 
23435
 
23436
 
23437
 
23438
 
23439
 
23440
 
23441
 
23442
 
23443
 
23444
 
23445
 
23446
 
23447
 
23448
 
23449
 
23450
 
23451
 
23452
 
23453
 
23454
 
23455
 
23456
 
23457
 
23458
 
23459
 
23460
 
23461
 
23462
 
23463
 
23464
 
23465
 
23466
 
23467
 
23468
 
23469
 
23470
 
23471
 
23472
 
23473
 
23474
 
23475
 
23476
 
23477
 
23478
 
23479
 
23480
 
23481
 
23482
 
23483
 
23484
 
23485
 
23486
 
23487
 
23488
 
23489
 
23490
 
23491
 
23492
 
23493
 
23494
 
23495
 
23496
 
23497
 
23498
 
23499
 
23500
 
23501
 
23502
 
23503
 
23504
 
23505
 
23506
 
23507
 
23508
 
23509
 
23510
 
23511
 
23512
 
23513
 
23514
 
23515
 
23516
 
23517
 
23518
 
23519
 
23520
 
23521
 
23522
 
23523
 
23524
 
23525
 
23526
 
23527
 
23528
 
23529
 
23530
 
23531
 
23532
 
23533
 
23534
 
23535
 
23536
 
23537
 
23538
 
23539
 
23540
 
23541
 
23542
 
23543
 
23544
 
23545
 
23546
 
23547
 
23548
 
23549
 
23550
 
23551
 
23552
 
23553
 
23554
 
23555
 
23556
 
23557
 
23558
 
23559
 
23560
 
23561
 
23562
 
23563
 
23564
 
23565
 
23566
 
23567
 
23568
 
23569
 
23570
 
23571
 
23572
 
23573
 
23574
 
23575
 
23576
 
23577
 
23578
 
23579
 
23580
 
23581
 
23582
 
23583
 
23584
 
23585
 
23586
 
23587
 
23588
 
23589
 
23590
 
23591
 
23592
 
23593
 
23594
 
23595
 
23596
 
23597
 
23598
 
23599
 
23600
 
23601
 
23602
 
23603
 
23604
 
23605
 
23606
 
23607
 
23608
 
23609
 
23610
 
23611
 
23612
 
23613
 
23614
 
23615
 
23616
 
23617
 
23618
 
23619
 
23620
 
23621
 
23622
 
23623
 
23624
 
23625
 
23626
 
23627
 
23628
 
23629
 
23630
 
23631
 
23632
 
23633
 
23634
 
23635
 
23636
 
23637
 
23638
 
23639
 
23640
 
23641
 
23642
 
23643
 
23644
 
23645
 
23646
 
23647
 
23648
 
23649
 
23650
 
23651
 
23652
 
23653
 
23654
 
23655
 
23656
 
23657
 
23658
 
23659
 
23660
 
23661
 
23662
 
23663
 
23664
 
23665
 
23666
 
23667
 
23668
 
23669
 
23670
 
23671
 
23672
 
23673
 
23674
 
23675
 
23676
 
23677
 
23678
 
23679
 
23680
 
23681
 
23682
 
23683
 
23684
 
23685
 
23686
 
23687
 
23688
 
23689
 
23690
 
23691
 
23692
 
23693
 
23694
 
23695
 
23696
 
23697
 
23698
 
23699
 
23700
 
23701
 
23702
 
23703
 
23704
 
23705
 
23706
 
23707
 
23708
 
23709
 
23710
 
23711
 
23712
 
23713
 
23714
 
23715
 
23716
 
23717
 
23718
 
23719
 
23720
 
23721
 
23722
 
23723
 
23724
 
23725
 
23726
 
23727
 
23728
 
23729
 
23730
 
23731
 
23732
 
23733
 
23734
 
23735
 
23736
 
23737
 
23738
 
23739
 
23740
 
23741
 
23742
 
23743
 
23744
 
23745
 
23746
 
23747
 
23748
 
23749
 
23750
 
23751
 
23752
 
23753
 
23754
 
23755
 
23756
 
23757
 
23758
 
23759
 
23760
 
23761
 
23762
 
23763
 
23764
 
23765
 
23766
 
23767
 
23768
 
23769
 
23770
 
23771
 
23772
 
23773
 
23774
 
23775
 
23776
 
23777
 
23778
 
23779
 
23780
 
23781
 
23782
 
23783
 
23784
 
23785
 
23786
 
23787
 
23788
 
23789
 
23790
 
23791
 
23792
 
23793
 
23794
 
23795
 
23796
 
23797
 
23798
 
23799
 
23800
 
23801
 
23802
 
23803
 
23804
 
23805
 
23806
 
23807
 
23808
 
23809
 
23810
 
23811
 
23812
 
23813
 
23814
 
23815
 
23816
 
23817
 
23818
 
23819
 
23820
 
23821
 
23822
 
23823
 
23824
 
23825
 
23826
 
23827
 
23828
 
23829
 
23830
 
23831
 
23832
 
23833
 
23834
 
23835
 
23836
 
23837
 
23838
 
23839
 
23840
 
23841
 
23842
 
23843
 
23844
 
23845
 
23846
 
23847
 
23848
 
23849
 
23850
 
23851
 
23852
 
23853
 
23854
 
23855
 
23856
 
23857
 
23858
 
23859
 
23860
 
23861
 
23862
 
23863
 
23864
 
23865
 
23866
 
23867
 
23868
 
23869
 
23870
 
23871
 
23872
 
23873
 
23874
 
23875
 
23876
 
23877
 
23878
 
23879
 
23880
 
23881
 
23882
 
23883
 
23884
 
23885
 
23886
 
23887
 
23888
 
23889
 
23890
 
23891
 
23892
 
23893
 
23894
 
23895
 
23896
 
23897
 
23898
 
23899
 
23900
 
23901
 
23902
 
23903
 
23904
 
23905
 
23906
 
23907
 
23908
 
23909
 
23910
 
23911
 
23912
 
23913
 
23914
 
23915
 
23916
 
23917
 
23918
 
23919
 
23920
 
23921
 
23922
 
23923
 
23924
 
23925
 
23926
 
23927
 
23928
 
23929
 
23930
 
23931
 
23932
 
23933
 
23934
 
23935
 
23936
 
23937
 
23938
 
23939
 
23940
 
23941
 
23942
 
23943
 
23944
 
23945
 
23946
 
23947
 
23948
 
23949
 
23950
 
23951
 
23952
 
23953
 
23954
 
23955
 
23956
 
23957
 
23958
 
23959
 
23960
 
23961
 
23962
 
23963
 
23964
 
23965
 
23966
 
23967
 
23968
 
23969
 
23970
 
23971
 
23972
 
23973
 
23974
 
23975
 
23976
 
23977
 
23978
 
23979
 
23980
 
23981
 
23982
 
23983
 
23984
 
23985
 
23986
 
23987
 
23988
 
23989
 
23990
 
23991
 
23992
 
23993
 
23994
 
23995
 
23996
 
23997
 
23998
 
23999
 
24000
 
24001
 
24002
 
24003
 
24004
 
24005
 
24006
 
24007
 
24008
 
24009
 
24010
 
24011
 
24012
 
24013
 
24014
 
24015
 
24016
 
24017
 
24018
 
24019
 
24020
 
24021
 
24022
 
24023
 
24024
 
24025
 
24026
 
24027
 
24028
 
24029
 
24030
 
24031
 
24032
 
24033
 
24034
 
24035
 
24036
 
24037
 
24038
 
24039
 
24040
 
24041
 
24042
 
24043
 
24044
 
24045
 
24046
 
24047
 
24048
 
24049
 
24050
 
24051
 
24052
 
24053
 
24054
 
24055
 
24056
 
24057
 
24058
 
24059
 
24060
 
24061
 
24062
 
24063
 
24064
 
24065
 
24066
 
24067
 
24068
 
24069
 
24070
 
24071
 
24072
 
24073
 
24074
 
24075
 
24076
 
24077
 
24078
 
24079
 
24080
 
24081
 
24082
 
24083
 
24084
 
24085
 
24086
 
24087
 
24088
 
24089
 
24090
 
24091
 
24092
 
24093
 
24094
 
24095
 
24096
 
24097
 
24098
 
24099
 
24100
 
24101
 
24102
 
24103
 
24104
 
24105
 
24106
 
24107
 
24108
 
24109
 
24110
 
24111
 
24112
 
24113
 
24114
 
24115
 
24116
 
24117
 
24118
 
24119
 
24120
 
24121
 
24122
 
24123
 
24124
 
24125
 
24126
 
24127
 
24128
 
24129
 
24130
 
24131
 
24132
 
24133
 
24134
 
24135
 
24136
 
24137
 
24138
 
24139
 
24140
 
24141
 
24142
 
24143
 
24144
 
24145
 
24146
 
24147
 
24148
 
24149
 
24150
 
24151
 
24152
 
24153
 
24154
 
24155
 
24156
 
24157
 
24158
 
24159
 
24160
 
24161
 
24162
 
24163
 
24164
 
24165
 
24166
 
24167
 
24168
 
24169
 
24170
 
24171
 
24172
 
24173
 
24174
 
24175
 
24176
 
24177
 
24178
 
24179
 
24180
 
24181
 
24182
 
24183
 
24184
 
24185
 
24186
 
24187
 
24188
 
24189
 
24190
 
24191
 
24192
 
24193
 
24194
 
24195
 
24196
 
24197
 
24198
 
24199
 
24200
 
24201
 
24202
 
24203
 
24204
 
24205
 
24206
 
24207
 
24208
 
24209
 
24210
 
24211
 
24212
 
24213
 
24214
 
24215
 
24216
 
24217
 
24218
 
24219
 
24220
 
24221
 
24222
 
24223
 
24224
 
24225
 
24226
 
24227
 
24228
 
24229
 
24230
 
24231
 
24232
 
24233
 
24234
 
24235
 
24236
 
24237
 
24238
 
24239
 
24240
 
24241
 
24242
 
24243
 
24244
 
24245
 
24246
 
24247
 
24248
 
24249
 
24250
 
24251
 
24252
 
24253
 
24254
 
24255
 
24256
 
24257
 
24258
 
24259
 
24260
 
24261
 
24262
 
24263
 
24264
 
24265
 
24266
 
24267
 
24268
 
24269
 
24270
 
24271
 
24272
 
24273
 
24274
 
24275
 
24276
 
24277
 
24278
 
24279
 
24280
 
24281
 
24282
 
24283
 
24284
 
24285
 
24286
 
24287
 
24288
 
24289
 
24290
 
24291
 
24292
 
24293
 
24294
 
24295
 
24296
 
24297
 
24298
 
24299
 
24300
 
24301
 
24302
 
24303
 
24304
 
24305
 
24306
 
24307
 
24308
 
24309
 
24310
 
24311
 
24312
 
24313
 
24314
 
24315
 
24316
 
24317
 
24318
 
24319
 
24320
 
24321
 
24322
 
24323
 
24324
 
24325
 
24326
 
24327
 
24328
 
24329
 
24330
 
24331
 
24332
 
24333
 
24334
 
24335
 
24336
 
24337
 
24338
 
24339
 
24340
 
24341
 
24342
 
24343
 
24344
 
24345
 
24346
 
24347
 
24348
 
24349
 
24350
 
24351
 
24352
 
24353
 
24354
 
24355
 
24356
 
24357
 
24358
 
24359
 
24360
 
24361
 
24362
 
24363
 
24364
 
24365
 
24366
 
24367
 
24368
 
24369
 
24370
 
24371
 
24372
 
24373
 
24374
 
24375
 
24376
 
24377
 
24378
 
24379
 
24380
 
24381
 
24382
 
24383
 
24384
 
24385
 
24386
 
24387
 
24388
 
24389
 
24390
 
24391
 
24392
 
24393
 
24394
 
24395
 
24396
 
24397
 
24398
 
24399
 
24400
 
24401
 
24402
 
24403
 
24404
 
24405
 
24406
 
24407
 
24408
 
24409
 
24410
 
24411
 
24412
 
24413
 
24414
 
24415
 
24416
 
24417
 
24418
 
24419
 
24420
 
24421
 
24422
 
24423
 
24424
 
24425
 
24426
 
24427
 
24428
 
24429
 
24430
 
24431
 
24432
 
24433
 
24434
 
24435
 
24436
 
24437
 
24438
 
24439
 
24440
 
24441
 
24442
 
24443
 
24444
 
24445
 
24446
 
24447
 
24448
 
24449
 
24450
 
24451
 
24452
 
24453
 
24454
 
24455
 
24456
 
24457
 
24458
 
24459
 
24460
 
24461
 
24462
 
24463
 
24464
 
24465
 
24466
 
24467
 
24468
 
24469
 
24470
 
24471
 
24472
 
24473
 
24474
 
24475
 
24476
 
24477
 
24478
 
24479
 
24480
 
24481
 
24482
 
24483
 
24484
 
24485
 
24486
 
24487
 
24488
 
24489
 
24490
 
24491
 
24492
 
24493
 
24494
 
24495
 
24496
 
24497
 
24498
 
24499
 
24500
 
24501
 
24502
 
24503
 
24504
 
24505
 
24506
 
24507
 
24508
 
24509
 
24510
 
24511
 
24512
 
24513
 
24514
 
24515
 
24516
 
24517
 
24518
 
24519
 
24520
 
24521
 
24522
 
24523
 
24524
 
24525
 
24526
 
24527
 
24528
 
24529
 
24530
 
24531
 
24532
 
24533
 
24534
 
24535
 
24536
 
24537
 
24538
 
24539
 
24540
 
24541
 
24542
 
24543
 
24544
 
24545
 
24546
 
24547
 
24548
 
24549
 
24550
 
24551
 
24552
 
24553
 
24554
 
24555
 
24556
 
24557
 
24558
 
24559
 
24560
 
24561
 
24562
 
24563
 
24564
 
24565
 
24566
 
24567
 
24568
 
24569
 
24570
 
24571
 
24572
 
24573
 
24574
 
24575
 
24576
 
24577
 
24578
 
24579
 
24580
 
24581
 
24582
 
24583
 
24584
 
24585
 
24586
 
24587
 
24588
 
24589
 
24590
 
24591
 
24592
 
24593
 
24594
 
24595
 
24596
 
24597
 
24598
 
24599
 
24600
 
24601
 
24602
 
24603
 
24604
 
24605
 
24606
 
24607
 
24608
 
24609
 
24610
 
24611
 
24612
 
24613
 
24614
 
24615
 
24616
 
24617
 
24618
 
24619
 
24620
 
24621
 
24622
 
24623
 
24624
 
24625
 
24626
 
24627
 
24628
 
24629
 
24630
 
24631
 
24632
 
24633
 
24634
 
24635
 
24636
 
24637
 
24638
 
24639
 
24640
 
24641
 
24642
 
24643
 
24644
 
24645
 
24646
 
24647
 
24648
 
24649
 
24650
 
24651
 
24652
 
24653
 
24654
 
24655
 
24656
 
24657
 
24658
 
24659
 
24660
 
24661
 
24662
 
24663
 
24664
 
24665
 
24666
 
24667
 
24668
 
24669
 
24670
 
24671
 
24672
 
24673
 
24674
 
24675
 
24676
 
24677
 
24678
 
24679
 
24680
 
24681
 
24682
 
24683
 
24684
 
24685
 
24686
 
24687
 
24688
 
24689
 
24690
 
24691
 
24692
 
24693
 
24694
 
24695
 
24696
 
24697
 
24698
 
24699
 
24700
 
24701
 
24702
 
24703
 
24704
 
24705
 
24706
 
24707
 
24708
 
24709
 
24710
 
24711
 
24712
 
24713
 
24714
 
24715
 
24716
 
24717
 
24718
 
24719
 
24720
 
24721
 
24722
 
24723
 
24724
 
24725
 
24726
 
24727
 
24728
 
24729
 
24730
 
24731
 
24732
 
24733
 
24734
 
24735
 
24736
 
24737
 
24738
 
24739
 
24740
 
24741
 
24742
 
24743
 
24744
 
24745
 
24746
 
24747
 
24748
 
24749
 
24750
 
24751
 
24752
 
24753
 
24754
 
24755
 
24756
 
24757
 
24758
 
24759
 
24760
 
24761
 
24762
 
24763
 
24764
 
24765
 
24766
 
24767
 
24768
 
24769
 
24770
 
24771
 
24772
 
24773
 
24774
 
24775
 
24776
 
24777
 
24778
 
24779
 
24780
 
24781
 
24782
 
24783
 
24784
 
24785
 
24786
 
24787
 
24788
 
24789
 
24790
 
24791
 
24792
 
24793
 
24794
 
24795
 
24796
 
24797
 
24798
 
24799
 
24800
 
24801
 
24802
 
24803
 
24804
 
24805
 
24806
 
24807
 
24808
 
24809
 
24810
 
24811
 
24812
 
24813
 
24814
 
24815
 
24816
 
24817
 
24818
 
24819
 
24820
 
24821
 
24822
 
24823
 
24824
 
24825
 
24826
 
24827
 
24828
 
24829
 
24830
 
24831
 
24832
 
24833
 
24834
 
24835
 
24836
 
24837
 
24838
 
24839
 
24840
 
24841
 
24842
 
24843
 
24844
 
24845
 
24846
 
24847
 
24848
 
24849
 
24850
 
24851
 
24852
 
24853
 
24854
 
24855
 
24856
 
24857
 
24858
 
24859
 
24860
 
24861
 
24862
 
24863
 
24864
 
24865
 
24866
 
24867
 
24868
 
24869
 
24870
 
24871
 
24872
 
24873
 
24874
 
24875
 
24876
 
24877
 
24878
 
24879
 
24880
 
24881
 
24882
 
24883
 
24884
 
24885
 
24886
 
24887
 
24888
 
24889
 
24890
 
24891
 
24892
 
24893
 
24894
 
24895
 
24896
 
24897
 
24898
 
24899
 
24900
 
24901
 
24902
 
24903
 
24904
 
24905
 
24906
 
24907
 
24908
 
24909
 
24910
 
24911
 
24912
 
24913
 
24914
 
24915
 
24916
 
24917
 
24918
 
24919
 
24920
 
24921
 
24922
 
24923
 
24924
 
24925
 
24926
 
24927
 
24928
 
24929
 
24930
 
24931
 
24932
 
24933
 
24934
 
24935
 
24936
 
24937
 
24938
 
24939
 
24940
 
24941
 
24942
 
24943
 
24944
 
24945
 
24946
 
24947
 
24948
 
24949
 
24950
 
24951
 
24952
 
24953
 
24954
 
24955
 
24956
 
24957
 
24958
 
24959
 
24960
 
24961
 
24962
 
24963
 
24964
 
24965
 
24966
 
24967
 
24968
 
24969
 
24970
 
24971
 
24972
 
24973
 
24974
 
24975
 
24976
 
24977
 
24978
 
24979
 
24980
 
24981
 
24982
 
24983
 
24984
 
24985
 
24986
 
24987
 
24988
 
24989
 
24990
 
24991
 
24992
 
24993
 
24994
 
24995
 
24996
 
24997
 
24998
 
24999
 
25000
 
25001
 
25002
 
25003
 
25004
 
25005
 
25006
 
25007
 
25008
 
25009
 
25010
 
25011
 
25012
 
25013
 
25014
 
25015
 
25016
 
25017
 
25018
 
25019
 
25020
 
25021
 
25022
 
25023
 
25024
 
25025
 
25026
 
25027
 
25028
 
25029
 
25030
 
25031
 
25032
 
25033
 
25034
 
25035
 
25036
 
25037
 
25038
 
25039
 
25040
 
25041
 
25042
 
25043
 
25044
 
25045
 
25046
 
25047
 
25048
 
25049
 
25050
 
25051
 
25052
 
25053
 
25054
 
25055
 
25056
 
25057
 
25058
 
25059
 
25060
 
25061
 
25062
 
25063
 
25064
 
25065
 
25066
 
25067
 
25068
 
25069
 
25070
 
25071
 
25072
 
25073
 
25074
 
25075
 
25076
 
25077
 
25078
 
25079
 
25080
 
25081
 
25082
 
25083
 
25084
 
25085
 
25086
 
25087
 
25088
 
25089
 
25090
 
25091
 
25092
 
25093
 
25094
 
25095
 
25096
 
25097
 
25098
 
25099
 
25100
 
25101
 
25102
 
25103
 
25104
 
25105
 
25106
 
25107
 
25108
 
25109
 
25110
 
25111
 
25112
 
25113
 
25114
 
25115
 
25116
 
25117
 
25118
 
25119
 
25120
 
25121
 
25122
 
25123
 
25124
 
25125
 
25126
 
25127
 
25128
 
25129
 
25130
 
25131
 
25132
 
25133
 
25134
 
25135
 
25136
 
25137
 
25138
 
25139
 
25140
 
25141
 
25142
 
25143
 
25144
 
25145
 
25146
 
25147
 
25148
 
25149
 
25150
 
25151
 
25152
 
25153
 
25154
 
25155
 
25156
 
25157
 
25158
 
25159
 
25160
 
25161
 
25162
 
25163
 
25164
 
25165
 
25166
 
25167
 
25168
 
25169
 
25170
 
25171
 
25172
 
25173
 
25174
 
25175
 
25176
 
25177
 
25178
 
25179
 
25180
 
25181
 
25182
 
25183
 
25184
 
25185
 
25186
 
25187
 
25188
 
25189
 
25190
 
25191
 
25192
 
25193
 
25194
 
25195
 
25196
 
25197
 
25198
 
25199
 
25200
 
25201
 
25202
 
25203
 
25204
 
25205
 
25206
 
25207
 
25208
 
25209
 
25210
 
25211
 
25212
 
25213
 
25214
 
25215
 
25216
 
25217
 
25218
 
25219
 
25220
 
25221
 
25222
 
25223
 
25224
 
25225
 
25226
 
25227
 
25228
 
25229
 
25230
 
25231
 
25232
 
25233
 
25234
 
25235
 
25236
 
25237
 
25238
 
25239
 
25240
 
25241
 
25242
 
25243
 
25244
 
25245
 
25246
 
25247
 
25248
 
25249
 
25250
 
25251
 
25252
 
25253
 
25254
 
25255
 
25256
 
25257
 
25258
 
25259
 
25260
 
25261
 
25262
 
25263
 
25264
 
25265
 
25266
 
25267
 
25268
 
25269
 
25270
 
25271
 
25272
 
25273
 
25274
 
25275
 
25276
 
25277
 
25278
 
25279
 
25280
 
25281
 
25282
 
25283
 
25284
 
25285
 
25286
 
25287
 
25288
 
25289
 
25290
 
25291
 
25292
 
25293
 
25294
 
25295
 
25296
 
25297
 
25298
 
25299
 
25300
 
25301
 
25302
 
25303
 
25304
 
25305
 
25306
 
25307
 
25308
 
25309
 
25310
 
25311
 
25312
 
25313
 
25314
 
25315
 
25316
 
25317
 
25318
 
25319
 
25320
 
25321
 
25322
 
25323
 
25324
 
25325
 
25326
 
25327
 
25328
 
25329
 
25330
 
25331
 
25332
 
25333
 
25334
 
25335
 
25336
 
25337
 
25338
 
25339
 
25340
 
25341
 
25342
 
25343
 
25344
 
25345
 
25346
 
25347
 
25348
 
25349
 
25350
 
25351
 
25352
 
25353
 
25354
 
25355
 
25356
 
25357
 
25358
 
25359
 
25360
 
25361
 
25362
 
25363
 
25364
 
25365
 
25366
 
25367
 
25368
 
25369
 
25370
 
25371
 
25372
 
25373
 
25374
 
25375
 
25376
 
25377
 
25378
 
25379
 
25380
 
25381
 
25382
 
25383
 
25384
 
25385
 
25386
 
25387
 
25388
 
25389
 
25390
 
25391
 
25392
 
25393
 
25394
 
25395
 
25396
 
25397
 
25398
 
25399
 
25400
 
25401
 
25402
 
25403
 
25404
 
25405
 
25406
 
25407
 
25408
 
25409
 
25410
 
25411
 
25412
 
25413
 
25414
 
25415
 
25416
 
25417
 
25418
 
25419
 
25420
 
25421
 
25422
 
25423
 
25424
 
25425
 
25426
 
25427
 
25428
 
25429
 
25430
 
25431
 
25432
 
25433
 
25434
 
25435
 
25436
 
25437
 
25438
 
25439
 
25440
 
25441
 
25442
 
25443
 
25444
 
25445
 
25446
 
25447
 
25448
 
25449
 
25450
 
25451
 
25452
 
25453
 
25454
 
25455
 
25456
 
25457
 
25458
 
25459
 
25460
 
25461
 
25462
 
25463
 
25464
 
25465
 
25466
 
25467
 
25468
 
25469
 
25470
 
25471
 
25472
 
25473
 
25474
 
25475
 
25476
 
25477
 
25478
 
25479
 
25480
 
25481
 
25482
 
25483
 
25484
 
25485
 
25486
 
25487
 
25488
 
25489
 
25490
 
25491
 
25492
 
25493
 
25494
 
25495
 
25496
 
25497
 
25498
 
25499
 
25500
 
25501
 
25502
 
25503
 
25504
 
25505
 
25506
 
25507
 
25508
 
25509
 
25510
 
25511
 
25512
 
25513
 
25514
 
25515
 
25516
 
25517
 
25518
 
25519
 
25520
 
25521
 
25522
 
25523
 
25524
 
25525
 
25526
 
25527
 
25528
 
25529
 
25530
 
25531
 
25532
 
25533
 
25534
 
25535
 
25536
 
25537
 
25538
 
25539
 
25540
 
25541
 
25542
 
25543
 
25544
 
25545
 
25546
 
25547
 
25548
 
25549
 
25550
 
25551
 
25552
 
25553
 
25554
 
25555
 
25556
 
25557
 
25558
 
25559
 
25560
 
25561
 
25562
 
25563
 
25564
 
25565
 
25566
 
25567
 
25568
 
25569
 
25570
 
25571
 
25572
 
25573
 
25574
 
25575
 
25576
 
25577
 
25578
 
25579
 
25580
 
25581
 
25582
 
25583
 
25584
 
25585
 
25586
 
25587
 
25588
 
25589
 
25590
 
25591
 
25592
 
25593
 
25594
 
25595
 
25596
 
25597
 
25598
 
25599
 
25600
 
25601
 
25602
 
25603
 
25604
 
25605
 
25606
 
25607
 
25608
 
25609
 
25610
 
25611
 
25612
 
25613
 
25614
 
25615
 
25616
 
25617
 
25618
 
25619
 
25620
 
25621
 
25622
 
25623
 
25624
 
25625
 
25626
 
25627
 
25628
 
25629
 
25630
 
25631
 
25632
 
25633
 
25634
 
25635
 
25636
 
25637
 
25638
 
25639
 
25640
 
25641
 
25642
 
25643
 
25644
 
25645
 
25646
 
25647
 
25648
 
25649
 
25650
 
25651
 
25652
 
25653
 
25654
 
25655
 
25656
 
25657
 
25658
 
25659
 
25660
 
25661
 
25662
 
25663
 
25664
 
25665
 
25666
 
25667
 
25668
 
25669
 
25670
 
25671
 
25672
 
25673
 
25674
 
25675
 
25676
 
25677
 
25678
 
25679
 
25680
 
25681
 
25682
 
25683
 
25684
 
25685
 
25686
 
25687
 
25688
 
25689
 
25690
 
25691
 
25692
 
25693
 
25694
 
25695
 
25696
 
25697
 
25698
 
25699
 
25700
 
25701
 
25702
 
25703
 
25704
 
25705
 
25706
 
25707
 
25708
 
25709
 
25710
 
25711
 
25712
 
25713
 
25714
 
25715
 
25716
 
25717
 
25718
 
25719
 
25720
 
25721
 
25722
 
25723
 
25724
 
25725
 
25726
 
25727
 
25728
 
25729
 
25730
 
25731
 
25732
 
25733
 
25734
 
25735
 
25736
 
25737
 
25738
 
25739
 
25740
 
25741
 
25742
 
25743
 
25744
 
25745
 
25746
 
25747
 
25748
 
25749
 
25750
 
25751
 
25752
 
25753
 
25754
 
25755
 
25756
 
25757
 
25758
 
25759
 
25760
 
25761
 
25762
 
25763
 
25764
 
25765
 
25766
 
25767
 
25768
 
25769
 
25770
 
25771
 
25772
 
25773
 
25774
 
25775
 
25776
 
25777
 
25778
 
25779
 
25780
 
25781
 
25782
 
25783
 
25784
 
25785
 
25786
 
25787
 
25788
 
25789
 
25790
 
25791
 
25792
 
25793
 
25794
 
25795
 
25796
 
25797
 
25798
 
25799
 
25800
 
25801
 
25802
 
25803
 
25804
 
25805
 
25806
 
25807
 
25808
 
25809
 
25810
 
25811
 
25812
 
25813
 
25814
 
25815
 
25816
 
25817
 
25818
 
25819
 
25820
 
25821
 
25822
 
25823
 
25824
 
25825
 
25826
 
25827
 
25828
 
25829
 
25830
 
25831
 
25832
 
25833
 
25834
 
25835
 
25836
 
25837
 
25838
 
25839
 
25840
 
25841
 
25842
 
25843
 
25844
 
25845
 
25846
 
25847
 
25848
 
25849
 
25850
 
25851
 
25852
 
25853
 
25854
 
25855
 
25856
 
25857
 
25858
 
25859
 
25860
 
25861
 
25862
 
25863
 
25864
 
25865
 
25866
 
25867
 
25868
 
25869
 
25870
 
25871
 
25872
 
25873
 
25874
 
25875
 
25876
 
25877
 
25878
 
25879
 
25880
 
25881
 
25882
 
25883
 
25884
 
25885
 
25886
 
25887
 
25888
 
25889
 
25890
 
25891
 
25892
 
25893
 
25894
 
25895
 
25896
 
25897
 
25898
 
25899
 
25900
 
25901
 
25902
 
25903
 
25904
 
25905
 
25906
 
25907
 
25908
 
25909
 
25910
 
25911
 
25912
 
25913
 
25914
 
25915
 
25916
 
25917
 
25918
 
25919
 
25920
 
25921
 
25922
 
25923
 
25924
 
25925
 
25926
 
25927
 
25928
 
25929
 
25930
 
25931
 
25932
 
25933
 
25934
 
25935
 
25936
 
25937
 
25938
 
25939
 
25940
 
25941
 
25942
 
25943
 
25944
 
25945
 
25946
 
25947
 
25948
 
25949
 
25950
 
25951
 
25952
 
25953
 
25954
 
25955
 
25956
 
25957
 
25958
 
25959
 
25960
 
25961
 
25962
 
25963
 
25964
 
25965
 
25966
 
25967
 
25968
 
25969
 
25970
 
25971
 
25972
 
25973
 
25974
 
25975
 
25976
 
25977
 
25978
 
25979
 
25980
 
25981
 
25982
 
25983
 
25984
 
25985
 
25986
 
25987
 
25988
 
25989
 
25990
 
25991
 
25992
 
25993
 
25994
 
25995
 
25996
 
25997
 
25998
 
25999
 
26000
 
26001
 
26002
 
26003
 
26004
 
26005
 
26006
 
26007
 
26008
 
26009
 
26010
 
26011
 
26012
 
26013
 
26014
 
26015
 
26016
 
26017
 
26018
 
26019
 
26020
 
26021
 
26022
 
26023
 
26024
 
26025
 
26026
 
26027
 
26028
 
26029
 
26030
 
26031
 
26032
 
26033
 
26034
 
26035
 
26036
 
26037
 
26038
 
26039
 
26040
 
26041
 
26042
 
26043
 
26044
 
26045
 
26046
 
26047
 
26048
 
26049
 
26050
 
26051
 
26052
 
26053
 
26054
 
26055
 
26056
 
26057
 
26058
 
26059
 
26060
 
26061
 
26062
 
26063
 
26064
 
26065
 
26066
 
26067
 
26068
 
26069
 
26070
 
26071
 
26072
 
26073
 
26074
 
26075
 
26076
 
26077
 
26078
 
26079
 
26080
 
26081
 
26082
 
26083
 
26084
 
26085
 
26086
 
26087
 
26088
 
26089
 
26090
 
26091
 
26092
 
26093
 
26094
 
26095
 
26096
 
26097
 
26098
 
26099
 
26100
 
26101
 
26102
 
26103
 
26104
 
26105
 
26106
 
26107
 
26108
 
26109
 
26110
 
26111
 
26112
 
26113
 
26114
 
26115
 
26116
 
26117
 
26118
 
26119
 
26120
 
26121
 
26122
 
26123
 
26124
 
26125
 
26126
 
26127
 
26128
 
26129
 
26130
 
26131
 
26132
 
26133
 
26134
 
26135
 
26136
 
26137
 
26138
 
26139
 
26140
 
26141
 
26142
 
26143
 
26144
 
26145
 
26146
 
26147
 
26148
 
26149
 
26150
 
26151
 
26152
 
26153
 
26154
 
26155
 
26156
 
26157
 
26158
 
26159
 
26160
 
26161
 
26162
 
26163
 
26164
 
26165
 
26166
 
26167
 
26168
 
26169
 
26170
 
26171
 
26172
 
26173
 
26174
 
26175
 
26176
 
26177
 
26178
 
26179
 
26180
 
26181
 
26182
 
26183
 
26184
 
26185
 
26186
 
26187
 
26188
 
26189
 
26190
 
26191
 
26192
 
26193
 
26194
 
26195
 
26196
 
26197
 
26198
 
26199
 
26200
 
26201
 
26202
 
26203
 
26204
 
26205
 
26206
 
26207
 
26208
 
26209
 
26210
 
26211
 
26212
 
26213
 
26214
 
26215
 
26216
 
26217
 
26218
 
26219
 
26220
 
26221
 
26222
 
26223
 
26224
 
26225
 
26226
 
26227
 
26228
 
26229
 
26230
 
26231
 
26232
 
26233
 
26234
 
26235
 
26236
 
26237
 
26238
 
26239
 
26240
 
26241
 
26242
 
26243
 
26244
 
26245
 
26246
 
26247
 
26248
 
26249
 
26250
 
26251
 
26252
 
26253
 
26254
 
26255
 
26256
 
26257
 
26258
 
26259
 
26260
 
26261
 
26262
 
26263
 
26264
 
26265
 
26266
 
26267
 
26268
 
26269
 
26270
 
26271
 
26272
 
26273
 
26274
 
26275
 
26276
 
26277
 
26278
 
26279
 
26280
 
26281
 
26282
 
26283
 
26284
 
26285
 
26286
 
26287
 
26288
 
26289
 
26290
 
26291
 
26292
 
26293
 
26294
 
26295
 
26296
 
26297
 
26298
 
26299
 
26300
 
26301
 
26302
 
26303
 
26304
 
26305
 
26306
 
26307
 
26308
 
26309
 
26310
 
26311
 
26312
 
26313
 
26314
 
26315
 
26316
 
26317
 
26318
 
26319
 
26320
 
26321
 
26322
 
26323
 
26324
 
26325
 
26326
 
26327
 
26328
 
26329
 
26330
 
26331
 
26332
 
26333
 
26334
 
26335
 
26336
 
26337
 
26338
 
26339
 
26340
 
26341
 
26342
 
26343
 
26344
 
26345
 
26346
 
26347
 
26348
 
26349
 
26350
 
26351
 
26352
 
26353
 
26354
 
26355
 
26356
 
26357
 
26358
 
26359
 
26360
 
26361
 
26362
 
26363
 
26364
 
26365
 
26366
 
26367
 
26368
 
26369
 
26370
 
26371
 
26372
 
26373
 
26374
 
26375
 
26376
 
26377
 
26378
 
26379
 
26380
 
26381
 
26382
 
26383
 
26384
 
26385
 
26386
 
26387
 
26388
 
26389
 
26390
 
26391
 
26392
 
26393
 
26394
 
26395
 
26396
 
26397
 
26398
 
26399
 
26400
 
26401
 
26402
 
26403
 
26404
 
26405
 
26406
 
26407
 
26408
 
26409
 
26410
 
26411
 
26412
 
26413
 
26414
 
26415
 
26416
 
26417
 
26418
 
26419
 
26420
 
26421
 
26422
 
26423
 
26424
 
26425
 
26426
 
26427
 
26428
 
26429
 
26430
 
26431
 
26432
 
26433
 
26434
 
26435
 
26436
 
26437
 
26438
 
26439
 
26440
 
26441
 
26442
 
26443
 
26444
 
26445
 
26446
 
26447
 
26448
 
26449
 
26450
 
26451
 
26452
 
26453
 
26454
 
26455
 
26456
 
26457
 
26458
 
26459
 
26460
 
26461
 
26462
 
26463
 
26464
 
26465
 
26466
 
26467
 
26468
 
26469
 
26470
 
26471
 
26472
 
26473
 
26474
 
26475
 
26476
 
26477
 
26478
 
26479
 
26480
 
26481
 
26482
 
26483
 
26484
 
26485
 
26486
 
26487
 
26488
 
26489
 
26490
 
26491
 
26492
 
26493
 
26494
 
26495
 
26496
 
26497
 
26498
 
26499
 
26500
 
26501
 
26502
 
26503
 
26504
 
26505
 
26506
 
26507
 
26508
 
26509
 
26510
 
26511
 
26512
 
26513
 
26514
 
26515
 
26516
 
26517
 
26518
 
26519
 
26520
 
26521
 
26522
 
26523
 
26524
 
26525
 
26526
 
26527
 
26528
 
26529
 
26530
 
26531
 
26532
 
26533
 
26534
 
26535
 
26536
 
26537
 
26538
 
26539
 
26540
 
26541
 
26542
 
26543
 
26544
 
26545
 
26546
 
26547
 
26548
 
26549
 
26550
 
26551
 
26552
 
26553
 
26554
 
26555
 
26556
 
26557
 
26558
 
26559
 
26560
 
26561
 
26562
 
26563
 
26564
 
26565
 
26566
 
26567
 
26568
 
26569
 
26570
 
26571
 
26572
 
26573
 
26574
 
26575
 
26576
 
26577
 
26578
 
26579
 
26580
 
26581
 
26582
 
26583
 
26584
 
26585
 
26586
 
26587
 
26588
 
26589
 
26590
 
26591
 
26592
 
26593
 
26594
 
26595
 
26596
 
26597
 
26598
 
26599
 
26600
 
26601
 
26602
 
26603
 
26604
 
26605
 
26606
 
26607
 
26608
 
26609
 
26610
 
26611
 
26612
 
26613
 
26614
 
26615
 
26616
 
26617
 
26618
 
26619
 
26620
 
26621
 
26622
 
26623
 
26624
 
26625
 
26626
 
26627
 
26628
 
26629
 
26630
 
26631
 
26632
 
26633
 
26634
 
26635
 
26636
 
26637
 
26638
 
26639
 
26640
 
26641
 
26642
 
26643
 
26644
 
26645
 
26646
 
26647
 
26648
 
26649
 
26650
 
26651
 
26652
 
26653
 
26654
 
26655
 
26656
 
26657
 
26658
 
26659
 
26660
 
26661
 
26662
 
26663
 
26664
 
26665
 
26666
 
26667
 
26668
 
26669
 
26670
 
26671
 
26672
 
26673
 
26674
 
26675
 
26676
 
26677
 
26678
 
26679
 
26680
 
26681
 
26682
 
26683
 
26684
 
26685
 
26686
 
26687
 
26688
 
26689
 
26690
 
26691
 
26692
 
26693
 
26694
 
26695
 
26696
 
26697
 
26698
 
26699
 
26700
 
26701
 
26702
 
26703
 
26704
 
26705
 
26706
 
26707
 
26708
 
26709
 
26710
 
26711
 
26712
 
26713
 
26714
 
26715
 
26716
 
26717
 
26718
 
26719
 
26720
 
26721
 
26722
 
26723
 
26724
 
26725
 
26726
 
26727
 
26728
 
26729
 
26730
 
26731
 
26732
 
26733
 
26734
 
26735
 
26736
 
26737
 
26738
 
26739
 
26740
 
26741
 
26742
 
26743
 
26744
 
26745
 
26746
 
26747
 
26748
 
26749
 
26750
 
26751
 
26752
 
26753
 
26754
 
26755
 
26756
 
26757
 
26758
 
26759
 
26760
 
26761
 
26762
 
26763
 
26764
 
26765
 
26766
 
26767
 
26768
 
26769
 
26770
 
26771
 
26772
 
26773
 
26774
 
26775
 
26776
 
26777
 
26778
 
26779
 
26780
 
26781
 
26782
 
26783
 
26784
 
26785
 
26786
 
26787
 
26788
 
26789
 
26790
 
26791
 
26792
 
26793
 
26794
 
26795
 
26796
 
26797
 
26798
 
26799
 
26800
 
26801
 
26802
 
26803
 
26804
 
26805
 
26806
 
26807
 
26808
 
26809
 
26810
 
26811
 
26812
 
26813
 
26814
 
26815
 
26816
 
26817
 
26818
 
26819
 
26820
 
26821
 
26822
 
26823
 
26824
 
26825
 
26826
 
26827
 
26828
 
26829
 
26830
 
26831
 
26832
 
26833
 
26834
 
26835
 
26836
 
26837
 
26838
 
26839
 
26840
 
26841
 
26842
 
26843
 
26844
 
26845
 
26846
 
26847
 
26848
 
26849
 
26850
 
26851
 
26852
 
26853
 
26854
 
26855
 
26856
 
26857
 
26858
 
26859
 
26860
 
26861
 
26862
 
26863
 
26864
 
26865
 
26866
 
26867
 
26868
 
26869
 
26870
 
26871
 
26872
 
26873
 
26874
 
26875
 
26876
 
26877
 
26878
 
26879
 
26880
 
26881
 
26882
 
26883
 
26884
 
26885
 
26886
 
26887
 
26888
 
26889
 
26890
 
26891
 
26892
 
26893
 
26894
 
26895
 
26896
 
26897
 
26898
 
26899
 
26900
 
26901
 
26902
 
26903
 
26904
 
26905
 
26906
 
26907
 
26908
 
26909
 
26910
 
26911
 
26912
 
26913
 
26914
 
26915
 
26916
 
26917
 
26918
 
26919
 
26920
 
26921
 
26922
 
26923
 
26924
 
26925
 
26926
 
26927
 
26928
 
26929
 
26930
 
26931
 
26932
 
26933
 
26934
 
26935
 
26936
 
26937
 
26938
 
26939
 
26940
 
26941
 
26942
 
26943
 
26944
 
26945
 
26946
 
26947
 
26948
 
26949
 
26950
 
26951
 
26952
 
26953
 
26954
 
26955
 
26956
 
26957
 
26958
 
26959
 
26960
 
26961
 
26962
 
26963
 
26964
 
26965
 
26966
 
26967
 
26968
 
26969
 
26970
 
26971
 
26972
 
26973
 
26974
 
26975
 
26976
 
26977
 
26978
 
26979
 
26980
 
26981
 
26982
 
26983
 
26984
 
26985
 
26986
 
26987
 
26988
 
26989
 
26990
 
26991
 
26992
 
26993
 
26994
 
26995
 
26996
 
26997
 
26998
 
26999
 
27000
 
27001
 
27002
 
27003
 
27004
 
27005
 
27006
 
27007
 
27008
 
27009
 
27010
 
27011
 
27012
 
27013
 
27014
 
27015
 
27016
 
27017
 
27018
 
27019
 
27020
 
27021
 
27022
 
27023
 
27024
 
27025
 
27026
 
27027
 
27028
 
27029
 
27030
 
27031
 
27032
 
27033
 
27034
 
27035
 
27036
 
27037
 
27038
 
27039
 
27040
 
27041
 
27042
 
27043
 
27044
 
27045
 
27046
 
27047
 
27048
 
27049
 
27050
 
27051
 
27052
 
27053
 
27054
 
27055
 
27056
 
27057
 
27058
 
27059
 
27060
 
27061
 
27062
 
27063
 
27064
 
27065
 
27066
 
27067
 
27068
 
27069
 
27070
 
27071
 
27072
 
27073
 
27074
 
27075
 
27076
 
27077
 
27078
 
27079
 
27080
 
27081
 
27082
 
27083
 
27084
 
27085
 
27086
 
27087
 
27088
 
27089
 
27090
 
27091
 
27092
 
27093
 
27094
 
27095
 
27096
 
27097
 
27098
 
27099
 
27100
 
27101
 
27102
 
27103
 
27104
 
27105
 
27106
 
27107
 
27108
 
27109
 
27110
 
27111
 
27112
 
27113
 
27114
 
27115
 
27116
 
27117
 
27118
 
27119
 
27120
 
27121
 
27122
 
27123
 
27124
 
27125
 
27126
 
27127
 
27128
 
27129
 
27130
 
27131
 
27132
 
27133
 
27134
 
27135
 
27136
 
27137
 
27138
 
27139
 
27140
 
27141
 
27142
 
27143
 
27144
 
27145
 
27146
 
27147
 
27148
 
27149
 
27150
 
27151
 
27152
 
27153
 
27154
 
27155
 
27156
 
27157
 
27158
 
27159
 
27160
 
27161
 
27162
 
27163
 
27164
 
27165
 
27166
 
27167
 
27168
 
27169
 
27170
 
27171
 
27172
 
27173
 
27174
 
27175
 
27176
 
27177
 
27178
 
27179
 
27180
 
27181
 
27182
 
27183
 
27184
 
27185
 
27186
 
27187
 
27188
 
27189
 
27190
 
27191
 
27192
 
27193
 
27194
 
27195
 
27196
 
27197
 
27198
 
27199
 
27200
 
27201
 
27202
 
27203
 
27204
 
27205
 
27206
 
27207
 
27208
 
27209
 
27210
 
27211
 
27212
 
27213
 
27214
 
27215
 
27216
 
27217
 
27218
 
27219
 
27220
 
27221
 
27222
 
27223
 
27224
 
27225
 
27226
 
27227
 
27228
 
27229
 
27230
 
27231
 
27232
 
27233
 
27234
 
27235
 
27236
 
27237
 
27238
 
27239
 
27240
 
27241
 
27242
 
27243
 
27244
 
27245
 
27246
 
27247
 
27248
 
27249
 
27250
 
27251
 
27252
 
27253
 
27254
 
27255
 
27256
 
27257
 
27258
 
27259
 
27260
 
27261
 
27262
 
27263
 
27264
 
27265
 
27266
 
27267
 
27268
 
27269
 
27270
 
27271
 
27272
 
27273
 
27274
 
27275
 
27276
 
27277
 
27278
 
27279
 
27280
 
27281
 
27282
 
27283
 
27284
 
27285
 
27286
 
27287
 
27288
 
27289
 
27290
 
27291
 
27292
 
27293
 
27294
 
27295
 
27296
 
27297
 
27298
 
27299
 
27300
 
27301
 
27302
 
27303
 
27304
 
27305
 
27306
 
27307
 
27308
 
27309
 
27310
 
27311
 
27312
 
27313
 
27314
 
27315
 
27316
 
27317
 
27318
 
27319
 
27320
 
27321
 
27322
 
27323
 
27324
 
27325
 
27326
 
27327
 
27328
 
27329
 
27330
 
27331
 
27332
 
27333
 
27334
 
27335
 
27336
 
27337
 
27338
 
27339
 
27340
 
27341
 
27342
 
27343
 
27344
 
27345
 
27346
 
27347
 
27348
 
27349
 
27350
 
27351
 
27352
 
27353
 
27354
 
27355
 
27356
 
27357
 
27358
 
27359
 
27360
 
27361
 
27362
 
27363
 
27364
 
27365
 
27366
 
27367
 
27368
 
27369
 
27370
 
27371
 
27372
 
27373
 
27374
 
27375
 
27376
 
27377
 
27378
 
27379
 
27380
 
27381
 
27382
 
27383
 
27384
 
27385
 
27386
 
27387
 
27388
 
27389
 
27390
 
27391
 
27392
 
27393
 
27394
 
27395
 
27396
 
27397
 
27398
 
27399
 
27400
 
27401
 
27402
 
27403
 
27404
 
27405
 
27406
 
27407
 
27408
 
27409
 
27410
 
27411
 
27412
 
27413
 
27414
 
27415
 
27416
 
27417
 
27418
 
27419
 
27420
 
27421
 
27422
 
27423
 
27424
 
27425
 
27426
 
27427
 
27428
 
27429
 
27430
 
27431
 
27432
 
27433
 
27434
 
27435
 
27436
 
27437
 
27438
 
27439
 
27440
 
27441
 
27442
 
27443
 
27444
 
27445
 
27446
 
27447
 
27448
 
27449
 
27450
 
27451
 
27452
 
27453
 
27454
 
27455
 
27456
 
27457
 
27458
 
27459
 
27460
 
27461
 
27462
 
27463
 
27464
 
27465
 
27466
 
27467
 
27468
 
27469
 
27470
 
27471
 
27472
 
27473
 
27474
 
27475
 
27476
 
27477
 
27478
 
27479
 
27480
 
27481
 
27482
 
27483
 
27484
 
27485
 
27486
 
27487
 
27488
 
27489
 
27490
 
27491
 
27492
 
27493
 
27494
 
27495
 
27496
 
27497
 
27498
 
27499
 
27500
 
27501
 
27502
 
27503
 
27504
 
27505
 
27506
 
27507
 
27508
 
27509
 
27510
 
27511
 
27512
 
27513
 
27514
 
27515
 
27516
 
27517
 
27518
 
27519
 
27520
 
27521
 
27522
 
27523
 
27524
 
27525
 
27526
 
27527
 
27528
 
27529
 
27530
 
27531
 
27532
 
27533
 
27534
 
27535
 
27536
 
27537
 
27538
 
27539
 
27540
 
27541
 
27542
 
27543
 
27544
 
27545
 
27546
 
27547
 
27548
 
27549
 
27550
 
27551
 
27552
 
27553
 
27554
 
27555
 
27556
 
27557
 
27558
 
27559
 
27560
 
27561
 
27562
 
27563
 
27564
 
27565
 
27566
 
27567
 
27568
 
27569
 
27570
 
27571
 
27572
 
27573
 
27574
 
27575
 
27576
 
27577
 
27578
 
27579
 
27580
 
27581
 
27582
 
27583
 
27584
 
27585
 
27586
 
27587
 
27588
 
27589
 
27590
 
27591
 
27592
 
27593
 
27594
 
27595
 
27596
 
27597
 
27598
 
27599
 
27600
 
27601
 
27602
 
27603
 
27604
 
27605
 
27606
 
27607
 
27608
 
27609
 
27610
 
27611
 
27612
 
27613
 
27614
 
27615
 
27616
 
27617
 
27618
 
27619
 
27620
 
27621
 
27622
 
27623
 
27624
 
27625
 
27626
 
27627
 
27628
 
27629
 
27630
 
27631
 
27632
 
27633
 
27634
 
27635
 
27636
 
27637
 
27638
 
27639
 
27640
 
27641
 
27642
 
27643
 
27644
 
27645
 
27646
 
27647
 
27648
 
27649
 
27650
 
27651
 
27652
 
27653
 
27654
 
27655
 
27656
 
27657
 
27658
 
27659
 
27660
 
27661
 
27662
 
27663
 
27664
 
27665
 
27666
 
27667
 
27668
 
27669
 
27670
 
27671
 
27672
 
27673
 
27674
 
27675
 
27676
 
27677
 
27678
 
27679
 
27680
 
27681
 
27682
 
27683
 
27684
 
27685
 
27686
 
27687
 
27688
 
27689
 
27690
 
27691
 
27692
 
27693
 
27694
 
27695
 
27696
 
27697
 
27698
 
27699
 
27700
 
27701
 
27702
 
27703
 
27704
 
27705
 
27706
 
27707
 
27708
 
27709
 
27710
 
27711
 
27712
 
27713
 
27714
 
27715
 
27716
 
27717
 
27718
 
27719
 
27720
 
27721
 
27722
 
27723
 
27724
 
27725
 
27726
 
27727
 
27728
 
27729
 
27730
 
27731
 
27732
 
27733
 
27734
 
27735
 
27736
 
27737
 
27738
 
27739
 
27740
 
27741
 
27742
 
27743
 
27744
 
27745
 
27746
 
27747
 
27748
 
27749
 
27750
 
27751
 
27752
 
27753
 
27754
 
27755
 
27756
 
27757
 
27758
 
27759
 
27760
 
27761
 
27762
 
27763
 
27764
 
27765
 
27766
 
27767
 
27768
 
27769
 
27770
 
27771
 
27772
 
27773
 
27774
 
27775
 
27776
 
27777
 
27778
 
27779
 
27780
 
27781
 
27782
 
27783
 
27784
 
27785
 
27786
 
27787
 
27788
 
27789
 
27790
 
27791
 
27792
 
27793
 
27794
 
27795
 
27796
 
27797
 
27798
 
27799
 
27800
 
27801
 
27802
 
27803
 
27804
 
27805
 
27806
 
27807
 
27808
 
27809
 
27810
 
27811
 
27812
 
27813
 
27814
 
27815
 
27816
 
27817
 
27818
 
27819
 
27820
 
27821
 
27822
 
27823
 
27824
 
27825
 
27826
 
27827
 
27828
 
27829
 
27830
 
27831
 
27832
 
27833
 
27834
 
27835
 
27836
 
27837
 
27838
 
27839
 
27840
 
27841
 
27842
 
27843
 
27844
 
27845
 
27846
 
27847
 
27848
 
27849
 
27850
 
27851
 
27852
 
27853
 
27854
 
27855
 
27856
 
27857
 
27858
 
27859
 
27860
 
27861
 
27862
 
27863
 
27864
 
27865
 
27866
 
27867
 
27868
 
27869
 
27870
 
27871
 
27872
 
27873
 
27874
 
27875
 
27876
 
27877
 
27878
 
27879
 
27880
 
27881
 
27882
 
27883
 
27884
 
27885
 
27886
 
27887
 
27888
 
27889
 
27890
 
27891
 
27892
 
27893
 
27894
 
27895
 
27896
 
27897
 
27898
 
27899
 
27900
 
27901
 
27902
 
27903
 
27904
 
27905
 
27906
 
27907
 
27908
 
27909
 
27910
 
27911
 
27912
 
27913
 
27914
 
27915
 
27916
 
27917
 
27918
 
27919
 
27920
 
27921
 
27922
 
27923
 
27924
 
27925
 
27926
 
27927
 
27928
 
27929
 
27930
 
27931
 
27932
 
27933
 
27934
 
27935
 
27936
 
27937
 
27938
 
27939
 
27940
 
27941
 
27942
 
27943
 
27944
 
27945
 
27946
 
27947
 
27948
 
27949
 
27950
 
27951
 
27952
 
27953
 
27954
 
27955
 
27956
 
27957
 
27958
 
27959
 
27960
 
27961
 
27962
 
27963
 
27964
 
27965
 
27966
 
27967
 
27968
 
27969
 
27970
 
27971
 
27972
 
27973
 
27974
 
27975
 
27976
 
27977
 
27978
 
27979
 
27980
 
27981
 
27982
 
27983
 
27984
 
27985
 
27986
 
27987
 
27988
 
27989
 
27990
 
27991
 
27992
 
27993
 
27994
 
27995
 
27996
 
27997
 
27998
 
27999
 
28000
 
28001
 
28002
 
28003
 
28004
 
28005
 
28006
 
28007
 
28008
 
28009
 
28010
 
28011
 
28012
 
28013
 
28014
 
28015
 
28016
 
28017
 
28018
 
28019
 
28020
 
28021
 
28022
 
28023
 
28024
 
28025
 
28026
 
28027
 
28028
 
28029
 
28030
 
28031
 
28032
 
28033
 
28034
 
28035
 
28036
 
28037
 
28038
 
28039
 
28040
 
28041
 
28042
 
28043
 
28044
 
28045
 
28046
 
28047
 
28048
 
28049
 
28050
 
28051
 
28052
 
28053
 
28054
 
28055
 
28056
 
28057
 
28058
 
28059
 
28060
 
28061
 
28062
 
28063
 
28064
 
28065
 
28066
 
28067
 
28068
 
28069
 
28070
 
28071
 
28072
 
28073
 
28074
 
28075
 
28076
 
28077
 
28078
 
28079
 
28080
 
28081
 
28082
 
28083
 
28084
 
28085
 
28086
 
28087
 
28088
 
28089
 
28090
 
28091
 
28092
 
28093
 
28094
 
28095
 
28096
 
28097
 
28098
 
28099
 
28100
 
28101
 
28102
 
28103
 
28104
 
28105
 
28106
 
28107
 
28108
 
28109
 
28110
 
28111
 
28112
 
28113
 
28114
 
28115
 
28116
 
28117
 
28118
 
28119
 
28120
 
28121
 
28122
 
28123
 
28124
 
28125
 
28126
 
28127
 
28128
 
28129
 
28130
 
28131
 
28132
 
28133
 
28134
 
28135
 
28136
 
28137
 
28138
 
28139
 
28140
 
28141
 
28142
 
28143
 
28144
 
28145
 
28146
 
28147
 
28148
 
28149
 
28150
 
28151
 
28152
 
28153
 
28154
 
28155
 
28156
 
28157
 
28158
 
28159
 
28160
 
28161
 
28162
 
28163
 
28164
 
28165
 
28166
 
28167
 
28168
 
28169
 
28170
 
28171
 
28172
 
28173
 
28174
 
28175
 
28176
 
28177
 
28178
 
28179
 
28180
 
28181
 
28182
 
28183
 
28184
 
28185
 
28186
 
28187
 
28188
 
28189
 
28190
 
28191
 
28192
 
28193
 
28194
 
28195
 
28196
 
28197
 
28198
 
28199
 
28200
 
28201
 
28202
 
28203
 
28204
 
28205
 
28206
 
28207
 
28208
 
28209
 
28210
 
28211
 
28212
 
28213
 
28214
 
28215
 
28216
 
28217
 
28218
 
28219
 
28220
 
28221
 
28222
 
28223
 
28224
 
28225
 
28226
 
28227
 
28228
 
28229
 
28230
 
28231
 
28232
 
28233
 
28234
 
28235
 
28236
 
28237
 
28238
 
28239
 
28240
 
28241
 
28242
 
28243
 
28244
 
28245
 
28246
 
28247
 
28248
 
28249
 
28250
 
28251
 
28252
 
28253
 
28254
 
28255
 
28256
 
28257
 
28258
 
28259
 
28260
 
28261
 
28262
 
28263
 
28264
 
28265
 
28266
 
28267
 
28268
 
28269
 
28270
 
28271
 
28272
 
28273
 
28274
 
28275
 
28276
 
28277
 
28278
 
28279
 
28280
 
28281
 
28282
 
28283
 
28284
 
28285
 
28286
 
28287
 
28288
 
28289
 
28290
 
28291
 
28292
 
28293
 
28294
 
28295
 
28296
 
28297
 
28298
 
28299
 
28300
 
28301
 
28302
 
28303
 
28304
 
28305
 
28306
 
28307
 
28308
 
28309
 
28310
 
28311
 
28312
 
28313
 
28314
 
28315
 
28316
 
28317
 
28318
 
28319
 
28320
 
28321
 
28322
 
28323
 
28324
 
28325
 
28326
 
28327
 
28328
 
28329
 
28330
 
28331
 
28332
 
28333
 
28334
 
28335
 
28336
 
28337
 
28338
 
28339
 
28340
 
28341
 
28342
 
28343
 
28344
 
28345
 
28346
 
28347
 
28348
 
28349
 
28350
 
28351
 
28352
 
28353
 
28354
 
28355
 
28356
 
28357
 
28358
 
28359
 
28360
 
28361
 
28362
 
28363
 
28364
 
28365
 
28366
 
28367
 
28368
 
28369
 
28370
 
28371
 
28372
 
28373
 
28374
 
28375
 
28376
 
28377
 
28378
 
28379
 
28380
 
28381
 
28382
 
28383
 
28384
 
28385
 
28386
 
28387
 
28388
 
28389
 
28390
 
28391
 
28392
 
28393
 
28394
 
28395
 
28396
 
28397
 
28398
 
28399
 
28400
 
28401
 
28402
 
28403
 
28404
 
28405
 
28406
 
28407
 
28408
 
28409
 
28410
 
28411
 
28412
 
28413
 
28414
 
28415
 
28416
 
28417
 
28418
 
28419
 
28420
 
28421
 
28422
 
28423
 
28424
 
28425
 
28426
 
28427
 
28428
 
28429
 
28430
 
28431
 
28432
 
28433
 
28434
 
28435
 
28436
 
28437
 
28438
 
28439
 
28440
 
28441
 
28442
 
28443
 
28444
 
28445
 
28446
 
28447
 
28448
 
28449
 
28450
 
28451
 
28452
 
28453
 
28454
 
28455
 
28456
 
28457
 
28458
 
28459
 
28460
 
28461
 
28462
 
28463
 
28464
 
28465
 
28466
 
28467
 
28468
 
28469
 
28470
 
28471
 
28472
 
28473
 
28474
 
28475
 
28476
 
28477
 
28478
 
28479
 
28480
 
28481
 
28482
 
28483
 
28484
 
28485
 
28486
 
28487
 
28488
 
28489
 
28490
 
28491
 
28492
 
28493
 
28494
 
28495
 
28496
 
28497
 
28498
 
28499
 
28500
 
28501
 
28502
 
28503
 
28504
 
28505
 
28506
 
28507
 
28508
 
28509
 
28510
 
28511
 
28512
 
28513
 
28514
 
28515
 
28516
 
28517
 
28518
 
28519
 
28520
 
28521
 
28522
 
28523
 
28524
 
28525
 
28526
 
28527
 
28528
 
28529
 
28530
 
28531
 
28532
 
28533
 
28534
 
28535
 
28536
 
28537
 
28538
 
28539
 
28540
 
28541
 
28542
 
28543
 
28544
 
28545
 
28546
 
28547
 
28548
 
28549
 
28550
 
28551
 
28552
 
28553
 
28554
 
28555
 
28556
 
28557
 
28558
 
28559
 
28560
 
28561
 
28562
 
28563
 
28564
 
28565
 
28566
 
28567
 
28568
 
28569
 
28570
 
28571
 
28572
 
28573
 
28574
 
28575
 
28576
 
28577
 
28578
 
28579
 
28580
 
28581
 
28582
 
28583
 
28584
 
28585
 
28586
 
28587
 
28588
 
28589
 
28590
 
28591
 
28592
 
28593
 
28594
 
28595
 
28596
 
28597
 
28598
 
28599
 
28600
 
28601
 
28602
 
28603
 
28604
 
28605
 
28606
 
28607
 
28608
 
28609
 
28610
 
28611
 
28612
 
28613
 
28614
 
28615
 
28616
 
28617
 
28618
 
28619
 
28620
 
28621
 
28622
 
28623
 
28624
 
28625
 
28626
 
28627
 
28628
 
28629
 
28630
 
28631
 
28632
 
28633
 
28634
 
28635
 
28636
 
28637
 
28638
 
28639
 
28640
 
28641
 
28642
 
28643
 
28644
 
28645
 
28646
 
28647
 
28648
 
28649
 
28650
 
28651
 
28652
 
28653
 
28654
 
28655
 
28656
 
28657
 
28658
 
28659
 
28660
 
28661
 
28662
 
28663
 
28664
 
28665
 
28666
 
28667
 
28668
 
28669
 
28670
 
28671
 
28672
 
28673
 
28674
 
28675
 
28676
 
28677
 
28678
 
28679
 
28680
 
28681
 
28682
 
28683
 
28684
 
28685
 
28686
 
28687
 
28688
 
28689
 
28690
 
28691
 
28692
 
28693
 
28694
 
28695
 
28696
 
28697
 
28698
 
28699
 
28700
 
28701
 
28702
 
28703
 
28704
 
28705
 
28706
 
28707
 
28708
 
28709
 
28710
 
28711
 
28712
 
28713
 
28714
 
28715
 
28716
 
28717
 
28718
 
28719
 
28720
 
28721
 
28722
 
28723
 
28724
 
28725
 
28726
 
28727
 
28728
 
28729
 
28730
 
28731
 
28732
 
28733
 
28734
 
28735
 
28736
 
28737
 
28738
 
28739
 
28740
 
28741
 
28742
 
28743
 
28744
 
28745
 
28746
 
28747
 
28748
 
28749
 
28750
 
28751
 
28752
 
28753
 
28754
 
28755
 
28756
 
28757
 
28758
 
28759
 
28760
 
28761
 
28762
 
28763
 
28764
 
28765
 
28766
 
28767
 
28768
 
28769
 
28770
 
28771
 
28772
 
28773
 
28774
 
28775
 
28776
 
28777
 
28778
 
28779
 
28780
 
28781
 
28782
 
28783
 
28784
 
28785
 
28786
 
28787
 
28788
 
28789
 
28790
 
28791
 
28792
 
28793
 
28794
 
28795
 
28796
 
28797
 
28798
 
28799
 
28800
 
28801
 
28802
 
28803
 
28804
 
28805
 
28806
 
28807
 
28808
 
28809
 
28810
 
28811
 
28812
 
28813
 
28814
 
28815
 
28816
 
28817
 
28818
 
28819
 
28820
 
28821
 
28822
 
28823
 
28824
 
28825
 
28826
 
28827
 
28828
 
28829
 
28830
 
28831
 
28832
 
28833
 
28834
 
28835
 
28836
 
28837
 
28838
 
28839
 
28840
 
28841
 
28842
 
28843
 
28844
 
28845
 
28846
 
28847
 
28848
 
28849
 
28850
 
28851
 
28852
 
28853
 
28854
 
28855
 
28856
 
28857
 
28858
 
28859
 
28860
 
28861
 
28862
 
28863
 
28864
 
28865
 
28866
 
28867
 
28868
 
28869
 
28870
 
28871
 
28872
 
28873
 
28874
 
28875
 
28876
 
28877
 
28878
 
28879
 
28880
 
28881
 
28882
 
28883
 
28884
 
28885
 
28886
 
28887
 
28888
 
28889
 
28890
 
28891
 
28892
 
28893
 
28894
 
28895
 
28896
 
28897
 
28898
 
28899
 
28900
 
28901
 
28902
 
28903
 
28904
 
28905
 
28906
 
28907
 
28908
 
28909
 
28910
 
28911
 
28912
 
28913
 
28914
 
28915
 
28916
 
28917
 
28918
 
28919
 
28920
 
28921
 
28922
 
28923
 
28924
 
28925
 
28926
 
28927
 
28928
 
28929
 
28930
 
28931
 
28932
 
28933
 
28934
 
28935
 
28936
 
28937
 
28938
 
28939
 
28940
 
28941
 
28942
 
28943
 
28944
 
28945
 
28946
 
28947
 
28948
 
28949
 
28950
 
28951
 
28952
 
28953
 
28954
 
28955
 
28956
 
28957
 
28958
 
28959
 
28960
 
28961
 
28962
 
28963
 
28964
 
28965
 
28966
 
28967
 
28968
 
28969
 
28970
 
28971
 
28972
 
28973
 
28974
 
28975
 
28976
 
28977
 
28978
 
28979
 
28980
 
28981
 
28982
 
28983
 
28984
 
28985
 
28986
 
28987
 
28988
 
28989
 
28990
 
28991
 
28992
 
28993
 
28994
 
28995
 
28996
 
28997
 
28998
 
28999
 
29000
 
29001
 
29002
 
29003
 
29004
 
29005
 
29006
 
29007
 
29008
 
29009
 
29010
 
29011
 
29012
 
29013
 
29014
 
29015
 
29016
 
29017
 
29018
 
29019
 
29020
 
29021
 
29022
 
29023
 
29024
 
29025
 
29026
 
29027
 
29028
 
29029
 
29030
 
29031
 
29032
 
29033
 
29034
 
29035
 
29036
 
29037
 
29038
 
29039
 
29040
 
29041
 
29042
 
29043
 
29044
 
29045
 
29046
 
29047
 
29048
 
29049
 
29050
 
29051
 
29052
 
29053
 
29054
 
29055
 
29056
 
29057
 
29058
 
29059
 
29060
 
29061
 
29062
 
29063
 
29064
 
29065
 
29066
 
29067
 
29068
 
29069
 
29070
 
29071
 
29072
 
29073
 
29074
 
29075
 
29076
 
29077
 
29078
 
29079
 
29080
 
29081
 
29082
 
29083
 
29084
 
29085
 
29086
 
29087
 
29088
 
29089
 
29090
 
29091
 
29092
 
29093
 
29094
 
29095
 
29096
 
29097
 
29098
 
29099
 
29100
 
29101
 
29102
 
29103
 
29104
 
29105
 
29106
 
29107
 
29108
 
29109
 
29110
 
29111
 
29112
 
29113
 
29114
 
29115
 
29116
 
29117
 
29118
 
29119
 
29120
 
29121
 
29122
 
29123
 
29124
 
29125
 
29126
 
29127
 
29128
 
29129
 
29130
 
29131
 
29132
 
29133
 
29134
 
29135
 
29136
 
29137
 
29138
 
29139
 
29140
 
29141
 
29142
 
29143
 
29144
 
29145
 
29146
 
29147
 
29148
 
29149
 
29150
 
29151
 
29152
 
29153
 
29154
 
29155
 
29156
 
29157
 
29158
 
29159
 
29160
 
29161
 
29162
 
29163
 
29164
 
29165
 
29166
 
29167
 
29168
 
29169
 
29170
 
29171
 
29172
 
29173
 
29174
 
29175
 
29176
 
29177
 
29178
 
29179
 
29180
 
29181
 
29182
 
29183
 
29184
 
29185
 
29186
 
29187
 
29188
 
29189
 
29190
 
29191
 
29192
 
29193
 
29194
 
29195
 
29196
 
29197
 
29198
 
29199
 
29200
 
29201
 
29202
 
29203
 
29204
 
29205
 
29206
 
29207
 
29208
 
29209
 
29210
 
29211
 
29212
 
29213
 
29214
 
29215
 
29216
 
29217
 
29218
 
29219
 
29220
 
29221
 
29222
 
29223
 
29224
 
29225
 
29226
 
29227
 
29228
 
29229
 
29230
 
29231
 
29232
 
29233
 
29234
 
29235
 
29236
 
29237
 
29238
 
29239
 
29240
 
29241
 
29242
 
29243
 
29244
 
29245
 
29246
 
29247
 
29248
 
29249
 
29250
 
29251
 
29252
 
29253
 
29254
 
29255
 
29256
 
29257
 
29258
 
29259
 
29260
 
29261
 
29262
 
29263
 
29264
 
29265
 
29266
 
29267
 
29268
 
29269
 
29270
 
29271
 
29272
 
29273
 
29274
 
29275
 
29276
 
29277
 
29278
 
29279
 
29280
 
29281
 
29282
 
29283
 
29284
 
29285
 
29286
 
29287
 
29288
 
29289
 
29290
 
29291
 
29292
 
29293
 
29294
 
29295
 
29296
 
29297
 
29298
 
29299
 
29300
 
29301
 
29302
 
29303
 
29304
 
29305
 
29306
 
29307
 
29308
 
29309
 
29310
 
29311
 
29312
 
29313
 
29314
 
29315
 
29316
 
29317
 
29318
 
29319
 
29320
 
29321
 
29322
 
29323
 
29324
 
29325
 
29326
 
29327
 
29328
 
29329
 
29330
 
29331
 
29332
 
29333
 
29334
 
29335
 
29336
 
29337
 
29338
 
29339
 
29340
 
29341
 
29342
 
29343
 
29344
 
29345
 
29346
 
29347
 
29348
 
29349
 
29350
 
29351
 
29352
 
29353
 
29354
 
29355
 
29356
 
29357
 
29358
 
29359
 
29360
 
29361
 
29362
 
29363
 
29364
 
29365
 
29366
 
29367
 
29368
 
29369
 
29370
 
29371
 
29372
 
29373
 
29374
 
29375
 
29376
 
29377
 
29378
 
29379
 
29380
 
29381
 
29382
 
29383
 
29384
 
29385
 
29386
 
29387
 
29388
 
29389
 
29390
 
29391
 
29392
 
29393
 
29394
 
29395
 
29396
 
29397
 
29398
 
29399
 
29400
 
29401
 
29402
 
29403
 
29404
 
29405
 
29406
 
29407
 
29408
 
29409
 
29410
 
29411
 
29412
 
29413
 
29414
 
29415
 
29416
 
29417
 
29418
 
29419
 
29420
 
29421
 
29422
 
29423
 
29424
 
29425
 
29426
 
29427
 
29428
 
29429
 
29430
 
29431
 
29432
 
29433
 
29434
 
29435
 
29436
 
29437
 
29438
 
29439
 
29440
 
29441
 
29442
 
29443
 
29444
 
29445
 
29446
 
29447
 
29448
 
29449
 
29450
 
29451
 
29452
 
29453
 
29454
 
29455
 
29456
 
29457
 
29458
 
29459
 
29460
 
29461
 
29462
 
29463
 
29464
 
29465
 
29466
 
29467
 
29468
 
29469
 
29470
 
29471
 
29472
 
29473
 
29474
 
29475
 
29476
 
29477
 
29478
 
29479
 
29480
 
29481
 
29482
 
29483
 
29484
 
29485
 
29486
 
29487
 
29488
 
29489
 
29490
 
29491
 
29492
 
29493
 
29494
 
29495
 
29496
 
29497
 
29498
 
29499
 
29500
 
29501
 
29502
 
29503
 
29504
 
29505
 
29506
 
29507
 
29508
 
29509
 
29510
 
29511
 
29512
 
29513
 
29514
 
29515
 
29516
 
29517
 
29518
 
29519
 
29520
 
29521
 
29522
 
29523
 
29524
 
29525
 
29526
 
29527
 
29528
 
29529
 
29530
 
29531
 
29532
 
29533
 
29534
 
29535
 
29536
 
29537
 
29538
 
29539
 
29540
 
29541
 
29542
 
29543
 
29544
 
29545
 
29546
 
29547
 
29548
 
29549
 
29550
 
29551
 
29552
 
29553
 
29554
 
29555
 
29556
 
29557
 
29558
 
29559
 
29560
 
29561
 
29562
 
29563
 
29564
 
29565
 
29566
 
29567
 
29568
 
29569
 
29570
 
29571
 
29572
 
29573
 
29574
 
29575
 
29576
 
29577
 
29578
 
29579
 
29580
 
29581
 
29582
 
29583
 
29584
 
29585
 
29586
 
29587
 
29588
 
29589
 
29590
 
29591
 
29592
 
29593
 
29594
 
29595
 
29596
 
29597
 
29598
 
29599
 
29600
 
29601
 
29602
 
29603
 
29604
 
29605
 
29606
 
29607
 
29608
 
29609
 
29610
 
29611
 
29612
 
29613
 
29614
 
29615
 
29616
 
29617
 
29618
 
29619
 
29620
 
29621
 
29622
 
29623
 
29624
 
29625
 
29626
 
29627
 
29628
 
29629
 
29630
 
29631
 
29632
 
29633
 
29634
 
29635
 
29636
 
29637
 
29638
 
29639
 
29640
 
29641
 
29642
 
29643
 
29644
 
29645
 
29646
 
29647
 
29648
 
29649
 
29650
 
29651
 
29652
 
29653
 
29654
 
29655
 
29656
 
29657
 
29658
 
29659
 
29660
 
29661
 
29662
 
29663
 
29664
 
29665
 
29666
 
29667
 
29668
 
29669
 
29670
 
29671
 
29672
 
29673
 
29674
 
29675
 
29676
 
29677
 
29678
 
29679
 
29680
 
29681
 
29682
 
29683
 
29684
 
29685
 
29686
 
29687
 
29688
 
29689
 
29690
 
29691
 
29692
 
29693
 
29694
 
29695
 
29696
 
29697
 
29698
 
29699
 
29700
 
29701
 
29702
 
29703
 
29704
 
29705
 
29706
 
29707
 
29708
 
29709
 
29710
 
29711
 
29712
 
29713
 
29714
 
29715
 
29716
 
29717
 
29718
 
29719
 
29720
 
29721
 
29722
 
29723
 
29724
 
29725
 
29726
 
29727
 
29728
 
29729
 
29730
 
29731
 
29732
 
29733
 
29734
 
29735
 
29736
 
29737
 
29738
 
29739
 
29740
 
29741
 
29742
 
29743
 
29744
 
29745
 
29746
 
29747
 
29748
 
29749
 
29750
 
29751
 
29752
 
29753
 
29754
 
29755
 
29756
 
29757
 
29758
 
29759
 
29760
 
29761
 
29762
 
29763
 
29764
 
29765
 
29766
 
29767
 
29768
 
29769
 
29770
 
29771
 
29772
 
29773
 
29774
 
29775
 
29776
 
29777
 
29778
 
29779
 
29780
 
29781
 
29782
 
29783
 
29784
 
29785
 
29786
 
29787
 
29788
 
29789
 
29790
 
29791
 
29792
 
29793
 
29794
 
29795
 
29796
 
29797
 
29798
 
29799
 
29800
 
29801
 
29802
 
29803
 
29804
 
29805
 
29806
 
29807
 
29808
 
29809
 
29810
 
29811
 
29812
 
29813
 
29814
 
29815
 
29816
 
29817
 
29818
 
29819
 
29820
 
29821
 
29822
 
29823
 
29824
 
29825
 
29826
 
29827
 
29828
 
29829
 
29830
 
29831
 
29832
 
29833
 
29834
 
29835
 
29836
 
29837
 
29838
 
29839
 
29840
 
29841
 
29842
 
29843
 
29844
 
29845
 
29846
 
29847
 
29848
 
29849
 
29850
 
29851
 
29852
 
29853
 
29854
 
29855
 
29856
 
29857
 
29858
 
29859
 
29860
 
29861
 
29862
 
29863
 
29864
 
29865
 
29866
 
29867
 
29868
 
29869
 
29870
 
29871
 
29872
 
29873
 
29874
 
29875
 
29876
 
29877
 
29878
 
29879
 
29880
 
29881
 
29882
 
29883
 
29884
 
29885
 
29886
 
29887
 
29888
 
29889
 
29890
 
29891
 
29892
 
29893
 
29894
 
29895
 
29896
 
29897
 
29898
 
29899
 
29900
 
29901
 
29902
 
29903
 
29904
 
29905
 
29906
 
29907
 
29908
 
29909
 
29910
 
29911
 
29912
 
29913
 
29914
 
29915
 
29916
 
29917
 
29918
 
29919
 
29920
 
29921
 
29922
 
29923
 
29924
 
29925
 
29926
 
29927
 
29928
 
29929
 
29930
 
29931
 
29932
 
29933
 
29934
 
29935
 
29936
 
29937
 
29938
 
29939
 
29940
 
29941
 
29942
 
29943
 
29944
 
29945
 
29946
 
29947
 
29948
 
29949
 
29950
 
29951
 
29952
 
29953
 
29954
 
29955
 
29956
 
29957
 
29958
 
29959
 
29960
 
29961
 
29962
 
29963
 
29964
 
29965
 
29966
 
29967
 
29968
 
29969
 
29970
 
29971
 
29972
 
29973
 
29974
 
29975
 
29976
 
29977
 
29978
 
29979
 
29980
 
29981
 
29982
 
29983
 
29984
 
29985
 
29986
 
29987
 
29988
 
29989
 
29990
 
29991
 
29992
 
29993
 
29994
 
29995
 
29996
 
29997
 
29998
 
29999
 
30000
 
30001
 
30002
 
30003
 
30004
 
30005
 
30006
 
30007
 
30008
 
30009
 
30010
 
30011
 
30012
 
30013
 
30014
 
30015
 
30016
 
30017
 
30018
 
30019
 
30020
 
30021
 
30022
 
30023
 
30024
 
30025
 
30026
 
30027
 
30028
 
30029
 
30030
 
30031
 
30032
 
30033
 
30034
 
30035
 
30036
 
30037
 
30038
 
30039
 
30040
 
30041
 
30042
 
30043
 
30044
 
30045
 
30046
 
30047
 
30048
 
30049
 
30050
 
30051
 
30052
 
30053
 
30054
 
30055
 
30056
 
30057
 
30058
 
30059
 
30060
 
30061
 
30062
 
30063
 
30064
 
30065
 
30066
 
30067
 
30068
 
30069
 
30070
 
30071
 
30072
 
30073
 
30074
 
30075
 
30076
 
30077
 
30078
 
30079
 
30080
 
30081
 
30082
 
30083
 
30084
 
30085
 
30086
 
30087
 
30088
 
30089
 
30090
 
30091
 
30092
 
30093
 
30094
 
30095
 
30096
 
30097
 
30098
 
30099
 
30100
 
30101
 
30102
 
30103
 
30104
 
30105
 
30106
 
30107
 
30108
 
30109
 
30110
 
30111
 
30112
 
30113
 
30114
 
30115
 
30116
 
30117
 
30118
 
30119
 
30120
 
30121
 
30122
 
30123
 
30124
 
30125
 
30126
 
30127
 
30128
 
30129
 
30130
 
30131
 
30132
 
30133
 
30134
 
30135
 
30136
 
30137
 
30138
 
30139
 
30140
 
30141
 
30142
 
30143
 
30144
 
30145
 
30146
 
30147
 
30148
 
30149
 
30150
 
30151
 
30152
 
30153
 
30154
 
30155
 
30156
 
30157
 
30158
 
30159
 
30160
 
30161
 
30162
 
30163
 
30164
 
30165
 
30166
 
30167
 
30168
 
30169
 
30170
 
30171
 
30172
 
30173
 
30174
 
30175
 
30176
 
30177
 
30178
 
30179
 
30180
 
30181
 
30182
 
30183
 
30184
 
30185
 
30186
 
30187
 
30188
 
30189
 
30190
 
30191
 
30192
 
30193
 
30194
 
30195
 
30196
 
30197
 
30198
 
30199
 
30200
 
30201
 
30202
 
30203
 
30204
 
30205
 
30206
 
30207
 
30208
 
30209
 
30210
 
30211
 
30212
 
30213
 
30214
 
30215
 
30216
 
30217
 
30218
 
30219
 
30220
 
30221
 
30222
 
30223
 
30224
 
30225
 
30226
 
30227
 
30228
 
30229
 
30230
 
30231
 
30232
 
30233
 
30234
 
30235
 
30236
 
30237
 
30238
 
30239
 
30240
 
30241
 
30242
 
30243
 
30244
 
30245
 
30246
 
30247
 
30248
 
30249
 
30250
 
30251
 
30252
 
30253
 
30254
 
30255
 
30256
 
30257
 
30258
 
30259
 
30260
 
30261
 
30262
 
30263
 
30264
 
30265
 
30266
 
30267
 
30268
 
30269
 
30270
 
30271
 
30272
 
30273
 
30274
 
30275
 
30276
 
30277
 
30278
 
30279
 
30280
 
30281
 
30282
 
30283
 
30284
 
30285
 
30286
 
30287
 
30288
 
30289
 
30290
 
30291
 
30292
 
30293
 
30294
 
30295
 
30296
 
30297
 
30298
 
30299
 
30300
 
30301
 
30302
 
30303
 
30304
 
30305
 
30306
 
30307
 
30308
 
30309
 
30310
 
30311
 
30312
 
30313
 
30314
 
30315
 
30316
 
30317
 
30318
 
30319
 
30320
 
30321
 
30322
 
30323
 
30324
 
30325
 
30326
 
30327
 
30328
 
30329
 
30330
 
30331
 
30332
 
30333
 
30334
 
30335
 
30336
 
30337
 
30338
 
30339
 
30340
 
30341
 
30342
 
30343
 
30344
 
30345
 
30346
 
30347
 
30348
 
30349
 
30350
 
30351
 
30352
 
30353
 
30354
 
30355
 
30356
 
30357
 
30358
 
30359
 
30360
 
30361
 
30362
 
30363
 
30364
 
30365
 
30366
 
30367
 
30368
 
30369
 
30370
 
30371
 
30372
 
30373
 
30374
 
30375
 
30376
 
30377
 
30378
 
30379
 
30380
 
30381
 
30382
 
30383
 
30384
 
30385
 
30386
 
30387
 
30388
 
30389
 
30390
 
30391
 
30392
 
30393
 
30394
 
30395
 
30396
 
30397
 
30398
 
30399
 
30400
 
30401
 
30402
 
30403
 
30404
 
30405
 
30406
 
30407
 
30408
 
30409
 
30410
 
30411
 
30412
 
30413
 
30414
 
30415
 
30416
 
30417
 
30418
 
30419
 
30420
 
30421
 
30422
 
30423
 
30424
 
30425
 
30426
 
30427
 
30428
 
30429
 
30430
 
30431
 
30432
 
30433
 
30434
 
30435
 
30436
 
30437
 
30438
 
30439
 
30440
 
30441
 
30442
 
30443
 
30444
 
30445
 
30446
 
30447
 
30448
 
30449
 
30450
 
30451
 
30452
 
30453
 
30454
 
30455
 
30456
 
30457
 
30458
 
30459
 
30460
 
30461
 
30462
 
30463
 
30464
 
30465
 
30466
 
30467
 
30468
 
30469
 
30470
 
30471
 
30472
 
30473
 
30474
 
30475
 
30476
 
30477
 
30478
 
30479
 
30480
 
30481
 
30482
 
30483
 
30484
 
30485
 
30486
 
30487
 
30488
 
30489
 
30490
 
30491
 
30492
 
30493
 
30494
 
30495
 
30496
 
30497
 
30498
 
30499
 
30500
 
30501
 
30502
 
30503
 
30504
 
30505
 
30506
 
30507
 
30508
 
30509
 
30510
 
30511
 
30512
 
30513
 
30514
 
30515
 
30516
 
30517
 
30518
 
30519
 
30520
 
30521
 
30522
 
30523
 
30524
 
30525
 
30526
 
30527
 
30528
 
30529
 
30530
 
30531
 
30532
 
30533
 
30534
 
30535
 
30536
 
30537
 
30538
 
30539
 
30540
 
30541
 
30542
 
30543
 
30544
 
30545
 
30546
 
30547
 
30548
 
30549
 
30550
 
30551
 
30552
 
30553
 
30554
 
30555
 
30556
 
30557
 
30558
 
30559
 
30560
 
30561
 
30562
 
30563
 
30564
 
30565
 
30566
 
30567
 
30568
 
30569
 
30570
 
30571
 
30572
 
30573
 
30574
 
30575
 
30576
 
30577
 
30578
 
30579
 
30580
 
30581
 
30582
 
30583
 
30584
 
30585
 
30586
 
30587
 
30588
 
30589
 
30590
 
30591
 
30592
 
30593
 
30594
 
30595
 
30596
 
30597
 
30598
 
30599
 
30600
 
30601
 
30602
 
30603
 
30604
 
30605
 
30606
 
30607
 
30608
 
30609
 
30610
 
30611
 
30612
 
30613
 
30614
 
30615
 
30616
 
30617
 
30618
 
30619
 
30620
 
30621
 
30622
 
30623
 
30624
 
30625
 
30626
 
30627
 
30628
 
30629
 
30630
 
30631
 
30632
 
30633
 
30634
 
30635
 
30636
 
30637
 
30638
 
30639
 
30640
 
30641
 
30642
 
30643
 
30644
 
30645
 
30646
 
30647
 
30648
 
30649
 
30650
 
30651
 
30652
 
30653
 
30654
 
30655
 
30656
 
30657
 
30658
 
30659
 
30660
 
30661
 
30662
 
30663
 
30664
 
30665
 
30666
 
30667
 
30668
 
30669
 
30670
 
30671
 
30672
 
30673
 
30674
 
30675
 
30676
 
30677
 
30678
 
30679
 
30680
 
30681
 
30682
 
30683
 
30684
 
30685
 
30686
 
30687
 
30688
 
30689
 
30690
 
30691
 
30692
 
30693
 
30694
 
30695
 
30696
 
30697
 
30698
 
30699
 
30700
 
30701
 
30702
 
30703
 
30704
 
30705
 
30706
 
30707
 
30708
 
30709
 
30710
 
30711
 
30712
 
30713
 
30714
 
30715
 
30716
 
30717
 
30718
 
30719
 
30720
 
30721
 
30722
 
30723
 
30724
 
30725
 
30726
 
30727
 
30728
 
30729
 
30730
 
30731
 
30732
 
30733
 
30734
 
30735
 
30736
 
30737
 
30738
 
30739
 
30740
 
30741
 
30742
 
30743
 
30744
 
30745
 
30746
 
30747
 
30748
 
30749
 
30750
 
30751
 
30752
 
30753
 
30754
 
30755
 
30756
 
30757
 
30758
 
30759
 
30760
 
30761
 
30762
 
30763
 
30764
 
30765
 
30766
 
30767
 
30768
 
30769
 
30770
 
30771
 
30772
 
30773
 
30774
 
30775
 
30776
 
30777
 
30778
 
30779
 
30780
 
30781
 
30782
 
30783
 
30784
 
30785
 
30786
 
30787
 
30788
 
30789
 
30790
 
30791
 
30792
 
30793
 
30794
 
30795
 
30796
 
30797
 
30798
 
30799
 
30800
 
30801
 
30802
 
30803
 
30804
 
30805
 
30806
 
30807
 
30808
 
30809
 
30810
 
30811
 
30812
 
30813
 
30814
 
30815
 
30816
 
30817
 
30818
 
30819
 
30820
 
30821
 
30822
 
30823
 
30824
 
30825
 
30826
 
30827
 
30828
 
30829
 
30830
 
30831
 
30832
 
30833
 
30834
 
30835
 
30836
 
30837
 
30838
 
30839
 
30840
 
30841
 
30842
 
30843
 
30844
 
30845
 
30846
 
30847
 
30848
 
30849
 
30850
 
30851
 
30852
 
30853
 
30854
 
30855
 
30856
 
30857
 
30858
 
30859
 
30860
 
30861
 
30862
 
30863
 
30864
 
30865
 
30866
 
30867
 
30868
 
30869
 
30870
 
30871
 
30872
 
30873
 
30874
 
30875
 
30876
 
30877
 
30878
 
30879
 
30880
 
30881
 
30882
 
30883
 
30884
 
30885
 
30886
 
30887
 
30888
 
30889
 
30890
 
30891
 
30892
 
30893
 
30894
 
30895
 
30896
 
30897
 
30898
 
30899
 
30900
 
30901
 
30902
 
30903
 
30904
 
30905
 
30906
 
30907
 
30908
 
30909
 
30910
 
30911
 
30912
 
30913
 
30914
 
30915
 
30916
 
30917
 
30918
 
30919
 
30920
 
30921
 
30922
 
30923
 
30924
 
30925
 
30926
 
30927
 
30928
 
30929
 
30930
 
30931
 
30932
 
30933
 
30934
 
30935
 
30936
 
30937
 
30938
 
30939
 
30940
 
30941
 
30942
 
30943
 
30944
 
30945
 
30946
 
30947
 
30948
 
30949
 
30950
 
30951
 
30952
 
30953
 
30954
 
30955
 
30956
 
30957
 
30958
 
30959
 
30960
 
30961
 
30962
 
30963
 
30964
 
30965
 
30966
 
30967
 
30968
 
30969
 
30970
 
30971
 
30972
 
30973
 
30974
 
30975
 
30976
 
30977
 
30978
 
30979
 
30980
 
30981
 
30982
 
30983
 
30984
 
30985
 
30986
 
30987
 
30988
 
30989
 
30990
 
30991
 
30992
 
30993
 
30994
 
30995
 
30996
 
30997
 
30998
 
30999
 
31000
 
31001
 
31002
 
31003
 
31004
 
31005
 
31006
 
31007
 
31008
 
31009
 
31010
 
31011
 
31012
 
31013
 
31014
 
31015
 
31016
 
31017
 
31018
 
31019
 
31020
 
31021
 
31022
 
31023
 
31024
 
31025
 
31026
 
31027
 
31028
 
31029
 
31030
 
31031
 
31032
 
31033
 
31034
 
31035
 
31036
 
31037
 
31038
 
31039
 
31040
 
31041
 
31042
 
31043
 
31044
 
31045
 
31046
 
31047
 
31048
 
31049
 
31050
 
31051
 
31052
 
31053
 
31054
 
31055
 
31056
 
31057
 
31058
 
31059
 
31060
 
31061
 
31062
 
31063
 
31064
 
31065
 
31066
 
31067
 
31068
 
31069
 
31070
 
31071
 
31072
 
31073
 
31074
 
31075
 
31076
 
31077
 
31078
 
31079
 
31080
 
31081
 
31082
 
31083
 
31084
 
31085
 
31086
 
31087
 
31088
 
31089
 
31090
 
31091
 
31092
 
31093
 
31094
 
31095
 
31096
 
31097
 
31098
 
31099
 
31100
 
31101
 
31102
 
31103
 
31104
 
31105
 
31106
 
31107
 
31108
 
31109
 
31110
 
31111
 
31112
 
31113
 
31114
 
31115
 
31116
 
31117
 
31118
 
31119
 
31120
 
31121
 
31122
 
31123
 
31124
 
31125
 
31126
 
31127
 
31128
 
31129
 
31130
 
31131
 
31132
 
31133
 
31134
 
31135
 
31136
 
31137
 
31138
 
31139
 
31140
 
31141
 
31142
 
31143
 
31144
 
31145
 
31146
 
31147
 
31148
 
31149
 
31150
 
31151
 
31152
 
31153
 
31154
 
31155
 
31156
 
31157
 
31158
 
31159
 
31160
 
31161
 
31162
 
31163
 
31164
 
31165
 
31166
 
31167
 
31168
 
31169
 
31170
 
31171
 
31172
 
31173
 
31174
 
31175
 
31176
 
31177
 
31178
 
31179
 
31180
 
31181
 
31182
 
31183
 
31184
 
31185
 
31186
 
31187
 
31188
 
31189
 
31190
 
31191
 
31192
 
31193
 
31194
 
31195
 
31196
 
31197
 
31198
 
31199
 
31200
 
31201
 
31202
 
31203
 
31204
 
31205
 
31206
 
31207
 
31208
 
31209
 
31210
 
31211
 
31212
 
31213
 
31214
 
31215
 
31216
 
31217
 
31218
 
31219
 
31220
 
31221
 
31222
 
31223
 
31224
 
31225
 
31226
 
31227
 
31228
 
31229
 
31230
 
31231
 
31232
 
31233
 
31234
 
31235
 
31236
 
31237
 
31238
 
31239
 
31240
 
31241
 
31242
 
31243
 
31244
 
31245
 
31246
 
31247
 
31248
 
31249
 
31250
 
31251
 
31252
 
31253
 
31254
 
31255
 
31256
 
31257
 
31258
 
31259
 
31260
 
31261
 
31262
 
31263
 
31264
 
31265
 
31266
 
31267
 
31268
 
31269
 
31270
 
31271
 
31272
 
31273
 
31274
 
31275
 
31276
 
31277
 
31278
 
31279
 
31280
 
31281
 
31282
 
31283
 
31284
 
31285
 
31286
 
31287
 
31288
 
31289
 
31290
 
31291
 
31292
 
31293
 
31294
 
31295
 
31296
 
31297
 
31298
 
31299
 
31300
 
31301
 
31302
 
31303
 
31304
 
31305
 
31306
 
31307
 
31308
 
31309
 
31310
 
31311
 
31312
 
31313
 
31314
 
31315
 
31316
 
31317
 
31318
 
31319
 
31320
 
31321
 
31322
 
31323
 
31324
 
31325
 
31326
 
31327
 
31328
 
31329
 
31330
 
31331
 
31332
 
31333
 
31334
 
31335
 
31336
 
31337
 
31338
 
31339
 
31340
 
31341
 
31342
 
31343
 
31344
 
31345
 
31346
 
31347
 
31348
 
31349
 
31350
 
31351
 
31352
 
31353
 
31354
 
31355
 
31356
 
31357
 
31358
 
31359
 
31360
 
31361
 
31362
 
31363
 
31364
 
31365
 
31366
 
31367
 
31368
 
31369
 
31370
 
31371
 
31372
 
31373
 
31374
 
31375
 
31376
 
31377
 
31378
 
31379
 
31380
 
31381
 
31382
 
31383
 
31384
 
31385
 
31386
 
31387
 
31388
 
31389
 
31390
 
31391
 
31392
 
31393
 
31394
 
31395
 
31396
 
31397
 
31398
 
31399
 
31400
 
31401
 
31402
 
31403
 
31404
 
31405
 
31406
 
31407
 
31408
 
31409
 
31410
 
31411
 
31412
 
31413
 
31414
 
31415
 
31416
 
31417
 
31418
 
31419
 
31420
 
31421
 
31422
 
31423
 
31424
 
31425
 
31426
 
31427
 
31428
 
31429
 
31430
 
31431
 
31432
 
31433
 
31434
 
31435
 
31436
 
31437
 
31438
 
31439
 
31440
 
31441
 
31442
 
31443
 
31444
 
31445
 
31446
 
31447
 
31448
 
31449
 
31450
 
31451
 
31452
 
31453
 
31454
 
31455
 
31456
 
31457
 
31458
 
31459
 
31460
 
31461
 
31462
 
31463
 
31464
 
31465
 
31466
 
31467
 
31468
 
31469
 
31470
 
31471
 
31472
 
31473
 
31474
 
31475
 
31476
 
31477
 
31478
 
31479
 
31480
 
31481
 
31482
 
31483
 
31484
 
31485
 
31486
 
31487
 
31488
 
31489
 
31490
 
31491
 
31492
 
31493
 
31494
 
31495
 
31496
 
31497
 
31498
 
31499
 
31500
 
31501
 
31502
 
31503
 
31504
 
31505
 
31506
 
31507
 
31508
 
31509
 
31510
 
31511
 
31512
 
31513
 
31514
 
31515
 
31516
 
31517
 
31518
 
31519
 
31520
 
31521
 
31522
 
31523
 
31524
 
31525
 
31526
 
31527
 
31528
 
31529
 
31530
 
31531
 
31532
 
31533
 
31534
 
31535
 
31536
 
31537
 
31538
 
31539
 
31540
 
31541
 
31542
 
31543
 
31544
 
31545
 
31546
 
31547
 
31548
 
31549
 
31550
 
31551
 
31552
 
31553
 
31554
 
31555
 
31556
 
31557
 
31558
 
31559
 
31560
 
31561
 
31562
 
31563
 
31564
 
31565
 
31566
 
31567
 
31568
 
31569
 
31570
 
31571
 
31572
 
31573
 
31574
 
31575
 
31576
 
31577
 
31578
 
31579
 
31580
 
31581
 
31582
 
31583
 
31584
 
31585
 
31586
 
31587
 
31588
 
31589
 
31590
 
31591
 
31592
 
31593
 
31594
 
31595
 
31596
 
31597
 
31598
 
31599
 
31600
 
31601
 
31602
 
31603
 
31604
 
31605
 
31606
 
31607
 
31608
 
31609
 
31610
 
31611
 
31612
 
31613
 
31614
 
31615
 
31616
 
31617
 
31618
 
31619
 
31620
 
31621
 
31622
 
31623
 
31624
 
31625
 
31626
 
31627
 
31628
 
31629
 
31630
 
31631
 
31632
 
31633
 
31634
 
31635
 
31636
 
31637
 
31638
 
31639
 
31640
 
31641
 
31642
 
31643
 
31644
 
31645
 
31646
 
31647
 
31648
 
31649
 
31650
 
31651
 
31652
 
31653
 
31654
 
31655
 
31656
 
31657
 
31658
 
31659
 
31660
 
31661
 
31662
 
31663
 
31664
 
31665
 
31666
 
31667
 
31668
 
31669
 
31670
 
31671
 
31672
 
31673
 
31674
 
31675
 
31676
 
31677
 
31678
 
31679
 
31680
 
31681
 
31682
 
31683
 
31684
 
31685
 
31686
 
31687
 
31688
 
31689
 
31690
 
31691
 
31692
 
31693
 
31694
 
31695
 
31696
 
31697
 
31698
 
31699
 
31700
 
31701
 
31702
 
31703
 
31704
 
31705
 
31706
 
31707
 
31708
 
31709
 
31710
 
31711
 
31712
 
31713
 
31714
 
31715
 
31716
 
31717
 
31718
 
31719
 
31720
 
31721
 
31722
 
31723
 
31724
 
31725
 
31726
 
31727
 
31728
 
31729
 
31730
 
31731
 
31732
 
31733
 
31734
 
31735
 
31736
 
31737
 
31738
 
31739
 
31740
 
31741
 
31742
 
31743
 
31744
 
31745
 
31746
 
31747
 
31748
 
31749
 
31750
 
31751
 
31752
 
31753
 
31754
 
31755
 
31756
 
31757
 
31758
 
31759
 
31760
 
31761
 
31762
 
31763
 
31764
 
31765
 
31766
 
31767
 
31768
 
31769
 
31770
 
31771
 
31772
 
31773
 
31774
 
31775
 
31776
 
31777
 
31778
 
31779
 
31780
 
31781
 
31782
 
31783
 
31784
 
31785
 
31786
 
31787
 
31788
 
31789
 
31790
 
31791
 
31792
 
31793
 
31794
 
31795
 
31796
 
31797
 
31798
 
31799
 
31800
 
31801
 
31802
 
31803
 
31804
 
31805
 
31806
 
31807
 
31808
 
31809
 
31810
 
31811
 
31812
 
31813
 
31814
 
31815
 
31816
 
31817
 
31818
 
31819
 
31820
 
31821
 
31822
 
31823
 
31824
 
31825
 
31826
 
31827
 
31828
 
31829
 
31830
 
31831
 
31832
 
31833
 
31834
 
31835
 
31836
 
31837
 
31838
 
31839
 
31840
 
31841
 
31842
 
31843
 
31844
 
31845
 
31846
 
31847
 
31848
 
31849
 
31850
 
31851
 
31852
 
31853
 
31854
 
31855
 
31856
 
31857
 
31858
 
31859
 
31860
 
31861
 
31862
 
31863
 
31864
 
31865
 
31866
 
31867
 
31868
 
31869
 
31870
 
31871
 
31872
 
31873
 
31874
 
31875
 
31876
 
31877
 
31878
 
31879
 
31880
 
31881
 
31882
 
31883
 
31884
 
31885
 
31886
 
31887
 
31888
 
31889
 
31890
 
31891
 
31892
 
31893
 
31894
 
31895
 
31896
 
31897
 
31898
 
31899
 
31900
 
31901
 
31902
 
31903
 
31904
 
31905
 
31906
 
31907
 
31908
 
31909
 
31910
 
31911
 
31912
 
31913
 
31914
 
31915
 
31916
 
31917
 
31918
 
31919
 
31920
 
31921
 
31922
 
31923
 
31924
 
31925
 
31926
 
31927
 
31928
 
31929
 
31930
 
31931
 
31932
 
31933
 
31934
 
31935
 
31936
 
31937
 
31938
 
31939
 
31940
 
31941
 
31942
 
31943
 
31944
 
31945
 
31946
 
31947
 
31948
 
31949
 
31950
 
31951
 
31952
 
31953
 
31954
 
31955
 
31956
 
31957
 
31958
 
31959
 
31960
 
31961
 
31962
 
31963
 
31964
 
31965
 
31966
 
31967
 
31968
 
31969
 
31970
 
31971
 
31972
 
31973
 
31974
 
31975
 
31976
 
31977
 
31978
 
31979
 
31980
 
31981
 
31982
 
31983
 
31984
 
31985
 
31986
 
31987
 
31988
 
31989
 
31990
 
31991
 
31992
 
31993
 
31994
 
31995
 
31996
 
31997
 
31998
 
31999
 
32000
 
32001
 
32002
 
32003
 
32004
 
32005
 
32006
 
32007
 
32008
 
32009
 
32010
 
32011
 
32012
 
32013
 
32014
 
32015
 
32016
 
32017
 
32018
 
32019
 
32020
 
32021
 
32022
 
32023
 
32024
 
32025
 
32026
 
32027
 
32028
 
32029
 
32030
 
32031
 
32032
 
32033
 
32034
 
32035
 
32036
 
32037
 
32038
 
32039
 
32040
 
32041
 
32042
 
32043
 
32044
 
32045
 
32046
 
32047
 
32048
 
32049
 
32050
 
32051
 
32052
 
32053
 
32054
 
32055
 
32056
 
32057
 
32058
 
32059
 
32060
 
32061
 
32062
 
32063
 
32064
 
32065
 
32066
 
32067
 
32068
 
32069
 
32070
 
32071
 
32072
 
32073
 
32074
 
32075
 
32076
 
32077
 
32078
 
32079
 
32080
 
32081
 
32082
 
32083
 
32084
 
32085
 
32086
 
32087
 
32088
 
32089
 
32090
 
32091
 
32092
 
32093
 
32094
 
32095
 
32096
 
32097
 
32098
 
32099
 
32100
 
32101
 
32102
 
32103
 
32104
 
32105
 
32106
 
32107
 
32108
 
32109
 
32110
 
32111
 
32112
 
32113
 
32114
 
32115
 
32116
 
32117
 
32118
 
32119
 
32120
 
32121
 
32122
 
32123
 
32124
 
32125
 
32126
 
32127
 
32128
 
32129
 
32130
 
32131
 
32132
 
32133
 
32134
 
32135
 
32136
 
32137
 
32138
 
32139
 
32140
 
32141
 
32142
 
32143
 
32144
 
32145
 
32146
 
32147
 
32148
 
32149
 
32150
 
32151
 
32152
 
32153
 
32154
 
32155
 
32156
 
32157
 
32158
 
32159
 
32160
 
32161
 
32162
 
32163
 
32164
 
32165
 
32166
 
32167
 
32168
 
32169
 
32170
 
32171
 
32172
 
32173
 
32174
 
32175
 
32176
 
32177
 
32178
 
32179
 
32180
 
32181
 
32182
 
32183
 
32184
 
32185
 
32186
 
32187
 
32188
 
32189
 
32190
 
32191
 
32192
 
32193
 
32194
 
32195
 
32196
 
32197
 
32198
 
32199
 
32200
 
32201
 
32202
 
32203
 
32204
 
32205
 
32206
 
32207
 
32208
 
32209
 
32210
 
32211
 
32212
 
32213
 
32214
 
32215
 
32216
 
32217
 
32218
 
32219
 
32220
 
32221
 
32222
 
32223
 
32224
 
32225
 
32226
 
32227
 
32228
 
32229
 
32230
 
32231
 
32232
 
32233
 
32234
 
32235
 
32236
 
32237
 
32238
 
32239
 
32240
 
32241
 
32242
 
32243
 
32244
 
32245
 
32246
 
32247
 
32248
 
32249
 
32250
 
32251
 
32252
 
32253
 
32254
 
32255
 
32256
 
32257
 
32258
 
32259
 
32260
 
32261
 
32262
 
32263
 
32264
 
32265
 
32266
 
32267
 
32268
 
32269
 
32270
 
32271
 
32272
 
32273
 
32274
 
32275
 
32276
 
32277
 
32278
 
32279
 
32280
 
32281
 
32282
 
32283
 
32284
 
32285
 
32286
 
32287
 
32288
 
32289
 
32290
 
32291
 
32292
 
32293
 
32294
 
32295
 
32296
 
32297
 
32298
 
32299
 
32300
 
32301
 
32302
 
32303
 
32304
 
32305
 
32306
 
32307
 
32308
 
32309
 
32310
 
32311
 
32312
 
32313
 
32314
 
32315
 
32316
 
32317
 
32318
 
32319
 
32320
 
32321
 
32322
 
32323
 
32324
 
32325
 
32326
 
32327
 
32328
 
32329
 
32330
 
32331
 
32332
 
32333
 
32334
 
32335
 
32336
 
32337
 
32338
 
32339
 
32340
 
32341
 
32342
 
32343
 
32344
 
32345
 
32346
 
32347
 
32348
 
32349
 
32350
 
32351
 
32352
 
32353
 
32354
 
32355
 
32356
 
32357
 
32358
 
32359
 
32360
 
32361
 
32362
 
32363
 
32364
 
32365
 
32366
 
32367
 
32368
 
32369
 
32370
 
32371
 
32372
 
32373
 
32374
 
32375
 
32376
 
32377
 
32378
 
32379
 
32380
 
32381
 
32382
 
32383
 
32384
 
32385
 
32386
 
32387
 
32388
 
32389
 
32390
 
32391
 
32392
 
32393
 
32394
 
32395
 
32396
 
32397
 
32398
 
32399
 
32400
 
32401
 
32402
 
32403
 
32404
 
32405
 
32406
 
32407
 
32408
 
32409
 
32410
 
32411
 
32412
 
32413
 
32414
 
32415
 
32416
 
32417
 
32418
 
32419
 
32420
 
32421
 
32422
 
32423
 
32424
 
32425
 
32426
 
32427
 
32428
 
32429
 
32430
 
32431
 
32432
 
32433
 
32434
 
32435
 
32436
 
32437
 
32438
 
32439
 
32440
 
32441
 
32442
 
32443
 
32444
 
32445
 
32446
 
32447
 
32448
 
32449
 
32450
 
32451
 
32452
 
32453
 
32454
 
32455
 
32456
 
32457
 
32458
 
32459
 
32460
 
32461
 
32462
 
32463
 
32464
 
32465
 
32466
 
32467
 
32468
 
32469
 
32470
 
32471
 
32472
 
32473
 
32474
 
32475
 
32476
 
32477
 
32478
 
32479
 
32480
 
32481
 
32482
 
32483
 
32484
 
32485
 
32486
 
32487
 
32488
 
32489
 
32490
 
32491
 
32492
 
32493
 
32494
 
32495
 
32496
 
32497
 
32498
 
32499
 
32500
 
32501
 
32502
 
32503
 
32504
 
32505
 
32506
 
32507
 
32508
 
32509
 
32510
 
32511
 
32512
 
32513
 
32514
 
32515
 
32516
 
32517
 
32518
 
32519
 
32520
 
32521
 
32522
 
32523
 
32524
 
32525
 
32526
 
32527
 
32528
 
32529
 
32530
 
32531
 
32532
 
32533
 
32534
 
32535
 
32536
 
32537
 
32538
 
32539
 
32540
 
32541
 
32542
 
32543
 
32544
 
32545
 
32546
 
32547
 
32548
 
32549
 
32550
 
32551
 
32552
 
32553
 
32554
 
32555
 
32556
 
32557
 
32558
 
32559
 
32560
 
32561
 
32562
 
32563
 
32564
 
32565
 
32566
 
32567
 
32568
 
32569
 
32570
 
32571
 
32572
 
32573
 
32574
 
32575
 
32576
 
32577
 
32578
 
32579
 
32580
 
32581
 
32582
 
32583
 
32584
 
32585
 
32586
 
32587
 
32588
 
32589
 
32590
 
32591
 
32592
 
32593
 
32594
 
32595
 
32596
 
32597
 
32598
 
32599
 
32600
 
32601
 
32602
 
32603
 
32604
 
32605
 
32606
 
32607
 
32608
 
32609
 
32610
 
32611
 
32612
 
32613
 
32614
 
32615
 
32616
 
32617
 
32618
 
32619
 
32620
 
32621
 
32622
 
32623
 
32624
 
32625
 
32626
 
32627
 
32628
 
32629
 
32630
 
32631
 
32632
 
32633
 
32634
 
32635
 
32636
 
32637
 
32638
 
32639
 
32640
 
32641
 
32642
 
32643
 
32644
 
32645
 
32646
 
32647
 
32648
 
32649
 
32650
 
32651
 
32652
 
32653
 
32654
 
32655
 
32656
 
32657
 
32658
 
32659
 
32660
 
32661
 
32662
 
32663
 
32664
 
32665
 
32666
 
32667
 
32668
 
32669
 
32670
 
32671
 
32672
 
32673
 
32674
 
32675
 
32676
 
32677
 
32678
 
32679
 
32680
 
32681
 
32682
 
32683
 
32684
 
32685
 
32686
 
32687
 
32688
 
32689
 
32690
 
32691
 
32692
 
32693
 
32694
 
32695
 
32696
 
32697
 
32698
 
32699
 
32700
 
32701
 
32702
 
32703
 
32704
 
32705
 
32706
 
32707
 
32708
 
32709
 
32710
 
32711
 
32712
 
32713
 
32714
 
32715
 
32716
 
32717
 
32718
 
32719
 
32720
 
32721
 
32722
 
32723
 
32724
 
32725
 
32726
 
32727
 
32728
 
32729
 
32730
 
32731
 
32732
 
32733
 
32734
 
32735
 
32736
 
32737
 
32738
 
32739
 
32740
 
32741
 
32742
 
32743
 
32744
 
32745
 
32746
 
32747
 
32748
 
32749
 
32750
 
32751
 
32752
 
32753
 
32754
 
32755
 
32756
 
32757
 
32758
 
32759
 
32760
 
32761
 
32762
 
32763
 
32764
 
32765
 
32766
 
32767
 
32768
 
32769
 
32770
 
32771
 
32772
 
32773
 
32774
 
32775
 
32776
 
32777
 
32778
 
32779
 
32780
 
32781
 
32782
 
32783
 
32784
 
32785
 
32786
 
32787
 
32788
 
32789
 
32790
 
32791
 
32792
 
32793
 
32794
 
32795
 
32796
 
32797
 
32798
 
32799
 
32800
 
32801
 
32802
 
32803
 
32804
 
32805
 
32806
 
32807
 
32808
 
32809
 
32810
 
32811
 
32812
 
32813
 
32814
 
32815
 
32816
 
32817
 
32818
 
32819
 
32820
 
32821
 
32822
 
32823
 
32824
 
32825
 
32826
 
32827
 
32828
 
32829
 
32830
 
32831
 
32832
 
32833
 
32834
 
32835
 
32836
 
32837
 
32838
 
32839
 
32840
 
32841
 
32842
 
32843
 
32844
 
32845
 
32846
 
32847
 
32848
 
32849
 
32850
 
32851
 
32852
 
32853
 
32854
 
32855
 
32856
 
32857
 
32858
 
32859
 
32860
 
32861
 
32862
 
32863
 
32864
 
32865
 
32866
 
32867
 
32868
 
32869
 
32870
 
32871
 
32872
 
32873
 
32874
 
32875
 
32876
 
32877
 
32878
 
32879
 
32880
 
32881
 
32882
 
32883
 
32884
 
32885
 
32886
 
32887
 
32888
 
32889
 
32890
 
32891
 
32892
 
32893
 
32894
 
32895
 
32896
 
32897
 
32898
 
32899
 
32900
 
32901
 
32902
 
32903
 
32904
 
32905
 
32906
 
32907
 
32908
 
32909
 
32910
 
32911
 
32912
 
32913
 
32914
 
32915
 
32916
 
32917
 
32918
 
32919
 
32920
 
32921
 
32922
 
32923
 
32924
 
32925
 
32926
 
32927
 
32928
 
32929
 
32930
 
32931
 
32932
 
32933
 
32934
 
32935
 
32936
 
32937
 
32938
 
32939
 
32940
 
32941
 
32942
 
32943
 
32944
 
32945
 
32946
 
32947
 
32948
 
32949
 
32950
 
32951
 
32952
 
32953
 
32954
 
32955
 
32956
 
32957
 
32958
 
32959
 
32960
 
32961
 
32962
 
32963
 
32964
 
32965
 
32966
 
32967
 
32968
 
32969
 
32970
 
32971
 
32972
 
32973
 
32974
 
32975
 
32976
 
32977
 
32978
 
32979
 
32980
 
32981
 
32982
 
32983
 
32984
 
32985
 
32986
 
32987
 
32988
 
32989
 
32990
 
32991
 
32992
 
32993
 
32994
 
32995
 
32996
 
32997
 
32998
 
32999
 
33000
 
33001
 
33002
 
33003
 
33004
 
33005
 
33006
 
33007
 
33008
 
33009
 
33010
 
33011
 
33012
 
33013
 
33014
 
33015
 
33016
 
33017
 
33018
 
33019
 
33020
 
33021
 
33022
 
33023
 
33024
 
33025
 
33026
 
33027
 
33028
 
33029
 
33030
 
33031
 
33032
 
33033
 
33034
 
33035
 
33036
 
33037
 
33038
 
33039
 
33040
 
33041
 
33042
 
33043
 
33044
 
33045
 
33046
 
33047
 
33048
 
33049
 
33050
 
33051
 
33052
 
33053
 
33054
 
33055
 
33056
 
33057
 
33058
 
33059
 
33060
 
33061
 
33062
 
33063
 
33064
 
33065
 
33066
 
33067
 
33068
 
33069
 
33070
 
33071
 
33072
 
33073
 
33074
 
33075
 
33076
 
33077
 
33078
 
33079
 
33080
 
33081
 
33082
 
33083
 
33084
 
33085
 
33086
 
33087
 
33088
 
33089
 
33090
 
33091
 
33092
 
33093
 
33094
 
33095
 
33096
 
33097
 
33098
 
33099
 
33100
 
33101
 
33102
 
33103
 
33104
 
33105
 
33106
 
33107
 
33108
 
33109
 
33110
 
33111
 
33112
 
33113
 
33114
 
33115
 
33116
 
33117
 
33118
 
33119
 
33120
 
33121
 
33122
 
33123
 
33124
 
33125
 
33126
 
33127
 
33128
 
33129
 
33130
 
33131
 
33132
 
33133
 
33134
 
33135
 
33136
 
33137
 
33138
 
33139
 
33140
 
33141
 
33142
 
33143
 
33144
 
33145
 
33146
 
33147
 
33148
 
33149
 
33150
 
33151
 
33152
 
33153
 
33154
 
33155
 
33156
 
33157
 
33158
 
33159
 
33160
 
33161
 
33162
 
33163
 
33164
 
33165
 
33166
 
33167
 
33168
 
33169
 
33170
 
33171
 
33172
 
33173
 
33174
 
33175
 
33176
 
33177
 
33178
 
33179
 
33180
 
33181
 
33182
 
33183
 
33184
 
33185
 
33186
 
33187
 
33188
 
33189
 
33190
 
33191
 
33192
 
33193
 
33194
 
33195
 
33196
 
33197
 
33198
 
33199
 
33200
 
33201
 
33202
 
33203
 
33204
 
33205
 
33206
 
33207
 
33208
 
33209
 
33210
 
33211
 
33212
 
33213
 
33214
 
33215
 
33216
 
33217
 
33218
 
33219
 
33220
 
33221
 
33222
 
33223
 
33224
 
33225
 
33226
 
33227
 
33228
 
33229
 
33230
 
33231
 
33232
 
33233
 
33234
 
33235
 
33236
 
33237
 
33238
 
33239
 
33240
 
33241
 
33242
 
33243
 
33244
 
33245
 
33246
 
33247
 
33248
 
33249
 
33250
 
33251
 
33252
 
33253
 
33254
 
33255
 
33256
 
33257
 
33258
 
33259
 
33260
 
33261
 
33262
 
33263
 
33264
 
33265
 
33266
 
33267
 
33268
 
33269
 
33270
 
33271
 
33272
 
33273
 
33274
 
33275
 
33276
 
33277
 
33278
 
33279
 
33280
 
33281
 
33282
 
33283
 
33284
 
33285
 
33286
 
33287
 
33288
 
33289
 
33290
 
33291
 
33292
 
33293
 
33294
 
33295
 
33296
 
33297
 
33298
 
33299
 
33300
 
33301
 
33302
 
33303
 
33304
 
33305
 
33306
 
33307
 
33308
 
33309
 
33310
 
33311
 
33312
 
33313
 
33314
 
33315
 
33316
 
33317
 
33318
 
33319
 
33320
 
33321
 
33322
 
33323
 
33324
 
33325
 
33326
 
33327
 
33328
 
33329
 
33330
 
33331
 
33332
 
33333
 
33334
 
33335
 
33336
 
33337
 
33338
 
33339
 
33340
 
33341
 
33342
 
33343
 
33344
 
33345
 
33346
 
33347
 
33348
 
33349
 
33350
 
33351
 
33352
 
33353
 
33354
 
33355
 
33356
 
33357
 
33358
 
33359
 
33360
 
33361
 
33362
 
33363
 
33364
 
33365
 
33366
 
33367
 
33368
 
33369
 
33370
 
33371
 
33372
 
33373
 
33374
 
33375
 
33376
 
33377
 
33378
 
33379
 
33380
 
33381
 
33382
 
33383
 
33384
 
33385
 
33386
 
33387
 
33388
 
33389
 
33390
 
33391
 
33392
 
33393
 
33394
 
33395
 
33396
 
33397
 
33398
 
33399
 
33400
 
33401
 
33402
 
33403
 
33404
 
33405
 
33406
 
33407
 
33408
 
33409
 
33410
 
33411
 
33412
 
33413
 
33414
 
33415
 
33416
 
33417
 
33418
 
33419
 
33420
 
33421
 
33422
 
33423
 
33424
 
33425
 
33426
 
33427
 
33428
 
33429
 
33430
 
33431
 
33432
 
33433
 
33434
 
33435
 
33436
 
33437
 
33438
 
33439
 
33440
 
33441
 
33442
 
33443
 
33444
 
33445
 
33446
 
33447
 
33448
 
33449
 
33450
 
33451
 
33452
 
33453
 
33454
 
33455
 
33456
 
33457
 
33458
 
33459
 
33460
 
33461
 
33462
 
33463
 
33464
 
33465
 
33466
 
33467
 
33468
 
33469
 
33470
 
33471
 
33472
 
33473
 
33474
 
33475
 
33476
 
33477
 
33478
 
33479
 
33480
 
33481
 
33482
 
33483
 
33484
 
33485
 
33486
 
33487
 
33488
 
33489
 
33490
 
33491
 
33492
 
33493
 
33494
 
33495
 
33496
 
33497
 
33498
 
33499
 
33500
 
33501
 
33502
 
33503
 
33504
 
33505
 
33506
 
33507
 
33508
 
33509
 
33510
 
33511
 
33512
 
33513
 
33514
 
33515
 
33516
 
33517
 
33518
 
33519
 
33520
 
33521
 
33522
 
33523
 
33524
 
33525
 
33526
 
33527
 
33528
 
33529
 
33530
 
33531
 
33532
 
33533
 
33534
 
33535
 
33536
 
33537
 
33538
 
33539
 
33540
 
33541
 
33542
 
33543
 
33544
 
33545
 
33546
 
33547
 
33548
 
33549
 
33550
 
33551
 
33552
 
33553
 
33554
 
33555
 
33556
 
33557
 
33558
 
33559
 
33560
 
33561
 
33562
 
33563
 
33564
 
33565
 
33566
 
33567
 
33568
 
33569
 
33570
 
33571
 
33572
 
33573
 
33574
 
33575
 
33576
 
33577
 
33578
 
33579
 
33580
 
33581
 
33582
 
33583
 
33584
 
33585
 
33586
 
33587
 
33588
 
33589
 
33590
 
33591
 
33592
 
33593
 
33594
 
33595
 
33596
 
33597
 
33598
 
33599
 
33600
 
33601
 
33602
 
33603
 
33604
 
33605
 
33606
 
33607
 
33608
 
33609
 
33610
 
33611
 
33612
 
33613
 
33614
 
33615
 
33616
 
33617
 
33618
 
33619
 
33620
 
33621
 
33622
 
33623
 
33624
 
33625
 
33626
 
33627
 
33628
 
33629
 
33630
 
33631
 
33632
 
33633
 
33634
 
33635
 
33636
 
33637
 
33638
 
33639
 
33640
 
33641
 
33642
 
33643
 
33644
 
33645
 
33646
 
33647
 
33648
 
33649
 
33650
 
33651
 
33652
 
33653
 
33654
 
33655
 
33656
 
33657
 
33658
 
33659
 
33660
 
33661
 
33662
 
33663
 
33664
 
33665
 
33666
 
33667
 
33668
 
33669
 
33670
 
33671
 
33672
 
33673
 
33674
 
33675
 
33676
 
33677
 
33678
 
33679
 
33680
 
33681
 
33682
 
33683
 
33684
 
33685
 
33686
 
33687
 
33688
 
33689
 
33690
 
33691
 
33692
 
33693
 
33694
 
33695
 
33696
 
33697
 
33698
 
33699
 
33700
 
33701
 
33702
 
33703
 
33704
 
33705
 
33706
 
33707
 
33708
 
33709
 
33710
 
33711
 
33712
 
33713
 
33714
 
33715
 
33716
 
33717
 
33718
 
33719
 
33720
 
33721
 
33722
 
33723
 
33724
 
33725
 
33726
 
33727
 
33728
 
33729
 
33730
 
33731
 
33732
 
33733
 
33734
 
33735
 
33736
 
33737
 
33738
 
33739
 
33740
 
33741
 
33742
 
33743
 
33744
 
33745
 
33746
 
33747
 
33748
 
33749
 
33750
 
33751
 
33752
 
33753
 
33754
 
33755
 
33756
 
33757
 
33758
 
33759
 
33760
 
33761
 
33762
 
33763
 
33764
 
33765
 
33766
 
33767
 
33768
 
33769
 
33770
 
33771
 
33772
 
33773
 
33774
 
33775
 
33776
 
33777
 
33778
 
33779
 
33780
 
33781
 
33782
 
33783
 
33784
 
33785
 
33786
 
33787
 
33788
 
33789
 
33790
 
33791
 
33792
 
33793
 
33794
 
33795
 
33796
 
33797
 
33798
 
33799
 
33800
 
33801
 
33802
 
33803
 
33804
 
33805
 
33806
 
33807
 
33808
 
33809
 
33810
 
33811
 
33812
 
33813
 
33814
 
33815
 
33816
 
33817
 
33818
 
33819
 
33820
 
33821
 
33822
 
33823
 
33824
 
33825
 
33826
 
33827
 
33828
 
33829
 
33830
 
33831
 
33832
 
33833
 
33834
 
33835
 
33836
 
33837
 
33838
 
33839
 
33840
 
33841
 
33842
 
33843
 
33844
 
33845
 
33846
 
33847
 
33848
 
33849
 
33850
 
33851
 
33852
 
33853
 
33854
 
33855
 
33856
 
33857
 
33858
 
33859
 
33860
 
33861
 
33862
 
33863
 
33864
 
33865
 
33866
 
33867
 
33868
 
33869
 
33870
 
33871
 
33872
 
33873
 
33874
 
33875
 
33876
 
33877
 
33878
 
33879
 
33880
 
33881
 
33882
 
33883
 
33884
 
33885
 
33886
 
33887
 
33888
 
33889
 
33890
 
33891
 
33892
 
33893
 
33894
 
33895
 
33896
 
33897
 
33898
 
33899
 
33900
 
33901
 
33902
 
33903
 
33904
 
33905
 
33906
 
33907
 
33908
 
33909
 
33910
 
33911
 
33912
 
33913
 
33914
 
33915
 
33916
 
33917
 
33918
 
33919
 
33920
 
33921
 
33922
 
33923
 
33924
 
33925
 
33926
 
33927
 
33928
 
33929
 
33930
 
33931
 
33932
 
33933
 
33934
 
33935
 
33936
 
33937
 
33938
 
33939
 
33940
 
33941
 
33942
 
33943
 
33944
 
33945
 
33946
 
33947
 
33948
 
33949
 
33950
 
33951
 
33952
 
33953
 
33954
 
33955
 
33956
 
33957
 
33958
 
33959
 
33960
 
33961
 
33962
 
33963
 
33964
 
33965
 
33966
 
33967
 
33968
 
33969
 
33970
 
33971
 
33972
 
33973
 
33974
 
33975
 
33976
 
33977
 
33978
 
33979
 
33980
 
33981
 
33982
 
33983
 
33984
 
33985
 
33986
 
33987
 
33988
 
33989
 
33990
 
33991
 
33992
 
33993
 
33994
 
33995
 
33996
 
33997
 
33998
 
33999
 
34000
 
34001
 
34002
 
34003
 
34004
 
34005
 
34006
 
34007
 
34008
 
34009
 
34010
 
34011
 
34012
 
34013
 
34014
 
34015
 
34016
 
34017
 
34018
 
34019
 
34020
 
34021
 
34022
 
34023
 
34024
 
34025
 
34026
 
34027
 
34028
 
34029
 
34030
 
34031
 
34032
 
34033
 
34034
 
34035
 
34036
 
34037
 
34038
 
34039
 
34040
 
34041
 
34042
 
34043
 
34044
 
34045
 
34046
 
34047
 
34048
 
34049
 
34050
 
34051
 
34052
 
34053
 
34054
 
34055
 
34056
 
34057
 
34058
 
34059
 
34060
 
34061
 
34062
 
34063
 
34064
 
34065
 
34066
 
34067
 
34068
 
34069
 
34070
 
34071
 
34072
 
34073
 
34074
 
34075
 
34076
 
34077
 
34078
 
34079
 
34080
 
34081
 
34082
 
34083
 
34084
 
34085
 
34086
 
34087
 
34088
 
34089
 
34090
 
34091
 
34092
 
34093
 
34094
 
34095
 
34096
 
34097
 
34098
 
34099
 
34100
 
34101
 
34102
 
34103
 
34104
 
34105
 
34106
 
34107
 
34108
 
34109
 
34110
 
34111
 
34112
 
34113
 
34114
 
34115
 
34116
 
34117
 
34118
 
34119
 
34120
 
34121
 
34122
 
34123
 
34124
 
34125
 
34126
 
34127
 
34128
 
34129
 
34130
 
34131
 
34132
 
34133
 
34134
 
34135
 
34136
 
34137
 
34138
 
34139
 
34140
 
34141
 
34142
 
34143
 
34144
 
34145
 
34146
 
34147
 
34148
 
34149
 
34150
 
34151
 
34152
 
34153
 
34154
 
34155
 
34156
 
34157
 
34158
 
34159
 
34160
 
34161
 
34162
 
34163
 
34164
 
34165
 
34166
 
34167
 
34168
 
34169
 
34170
 
34171
 
34172
 
34173
 
34174
 
34175
 
34176
 
34177
 
34178
 
34179
 
34180
 
34181
 
34182
 
34183
 
34184
 
34185
 
34186
 
34187
 
34188
 
34189
 
34190
 
34191
 
34192
 
34193
 
34194
 
34195
 
34196
 
34197
 
34198
 
34199
 
34200
 
34201
 
34202
 
34203
 
34204
 
34205
 
34206
 
34207
 
34208
 
34209
 
34210
 
34211
 
34212
 
34213
 
34214
 
34215
 
34216
 
34217
 
34218
 
34219
 
34220
 
34221
 
34222
 
34223
 
34224
 
34225
 
34226
 
34227
 
34228
 
34229
 
34230
 
34231
 
34232
 
34233
 
34234
 
34235
 
34236
 
34237
 
34238
 
34239
 
34240
 
34241
 
34242
 
34243
 
34244
 
34245
 
34246
 
34247
 
34248
 
34249
 
34250
 
34251
 
34252
 
34253
 
34254
 
34255
 
34256
 
34257
 
34258
 
34259
 
34260
 
34261
 
34262
 
34263
 
34264
 
34265
 
34266
 
34267
 
34268
 
34269
 
34270
 
34271
 
34272
 
34273
 
34274
 
34275
 
34276
 
34277
 
34278
 
34279
 
34280
 
34281
 
34282
 
34283
 
34284
 
34285
 
34286
 
34287
 
34288
 
34289
 
34290
 
34291
 
34292
 
34293
 
34294
 
34295
 
34296
 
34297
 
34298
 
34299
 
34300
 
34301
 
34302
 
34303
 
34304
 
34305
 
34306
 
34307
 
34308
 
34309
 
34310
 
34311
 
34312
 
34313
 
34314
 
34315
 
34316
 
34317
 
34318
 
34319
 
34320
 
34321
 
34322
 
34323
 
34324
 
34325
 
34326
 
34327
 
34328
 
34329
 
34330
 
34331
 
34332
 
34333
 
34334
 
34335
 
34336
 
34337
 
34338
 
34339
 
34340
 
34341
 
34342
 
34343
 
34344
 
34345
 
34346
 
34347
 
34348
 
34349
 
34350
 
34351
 
34352
 
34353
 
34354
 
34355
 
34356
 
34357
 
34358
 
34359
 
34360
 
34361
 
34362
 
34363
 
34364
 
34365
 
34366
 
34367
 
34368
 
34369
 
34370
 
34371
 
34372
 
34373
 
34374
 
34375
 
34376
 
34377
 
34378
 
34379
 
34380
 
34381
 
34382
 
34383
 
34384
 
34385
 
34386
 
34387
 
34388
 
34389
 
34390
 
34391
 
34392
 
34393
 
34394
 
34395
 
34396
 
34397
 
34398
 
34399
 
34400
 
34401
 
34402
 
34403
 
34404
 
34405
 
34406
 
34407
 
34408
 
34409
 
34410
 
34411
 
34412
 
34413
 
34414
 
34415
 
34416
 
34417
 
34418
 
34419
 
34420
 
34421
 
34422
 
34423
 
34424
 
34425
 
34426
 
34427
 
34428
 
34429
 
34430
 
34431
 
34432
 
34433
 
34434
 
34435
 
34436
 
34437
 
34438
 
34439
 
34440
 
34441
 
34442
 
34443
 
34444
 
34445
 
34446
 
34447
 
34448
 
34449
 
34450
 
34451
 
34452
 
34453
 
34454
 
34455
 
34456
 
34457
 
34458
 
34459
 
34460
 
34461
 
34462
 
34463
 
34464
 
34465
 
34466
 
34467
 
34468
 
34469
 
34470
 
34471
 
34472
 
34473
 
34474
 
34475
 
34476
 
34477
 
34478
 
34479
 
34480
 
34481
 
34482
 
34483
 
34484
 
34485
 
34486
 
34487
 
34488
 
34489
 
34490
 
34491
 
34492
 
34493
 
34494
 
34495
 
34496
 
34497
 
34498
 
34499
 
34500
 
34501
 
34502
 
34503
 
34504
 
34505
 
34506
 
34507
 
34508
 
34509
 
34510
 
34511
 
34512
 
34513
 
34514
 
34515
 
34516
 
34517
 
34518
 
34519
 
34520
 
34521
 
34522
 
34523
 
34524
 
34525
 
34526
 
34527
 
34528
 
34529
 
34530
 
34531
 
34532
 
34533
 
34534
 
34535
 
34536
 
34537
 
34538
 
34539
 
34540
 
34541
 
34542
 
34543
 
34544
 
34545
 
34546
 
34547
 
34548
 
34549
 
34550
 
34551
 
34552
 
34553
 
34554
 
34555
 
34556
 
34557
 
34558
 
34559
 
34560
 
34561
 
34562
 
34563
 
34564
 
34565
 
34566
 
34567
 
34568
 
34569
 
34570
 
34571
 
34572
 
34573
 
34574
 
34575
 
34576
 
34577
 
34578
 
34579
 
34580
 
34581
 
34582
 
34583
 
34584
 
34585
 
34586
 
34587
 
34588
 
34589
 
34590
 
34591
 
34592
 
34593
 
34594
 
34595
 
34596
 
34597
 
34598
 
34599
 
34600
 
34601
 
34602
 
34603
 
34604
 
34605
 
34606
 
34607
 
34608
 
34609
 
34610
 
34611
 
34612
 
34613
 
34614
 
34615
 
34616
 
34617
 
34618
 
34619
 
34620
 
34621
 
34622
 
34623
 
34624
 
34625
 
34626
 
34627
 
34628
 
34629
 
34630
 
34631
 
34632
 
34633
 
34634
 
34635
 
34636
 
34637
 
34638
 
34639
 
34640
 
34641
 
34642
 
34643
 
34644
 
34645
 
34646
 
34647
 
34648
 
34649
 
34650
 
34651
 
34652
 
34653
 
34654
 
34655
 
34656
 
34657
 
34658
 
34659
 
34660
 
34661
 
34662
 
34663
 
34664
 
34665
 
34666
 
34667
 
34668
 
34669
 
34670
 
34671
 
34672
 
34673
 
34674
 
34675
 
34676
 
34677
 
34678
 
34679
 
34680
 
34681
 
34682
 
34683
 
34684
 
34685
 
34686
 
34687
 
34688
 
34689
 
34690
 
34691
 
34692
 
34693
 
34694
 
34695
 
34696
 
34697
 
34698
 
34699
 
34700
 
34701
 
34702
 
34703
 
34704
 
34705
 
34706
 
34707
 
34708
 
34709
 
34710
 
34711
 
34712
 
34713
 
34714
 
34715
 
34716
 
34717
 
34718
 
34719
 
34720
 
34721
 
34722
 
34723
 
34724
 
34725
 
34726
 
34727
 
34728
 
34729
 
34730
 
34731
 
34732
 
34733
 
34734
 
34735
 
34736
 
34737
 
34738
 
34739
 
34740
 
34741
 
34742
 
34743
 
34744
 
34745
 
34746
 
34747
 
34748
 
34749
 
34750
 
34751
 
34752
 
34753
 
34754
 
34755
 
34756
 
34757
 
34758
 
34759
 
34760
 
34761
 
34762
 
34763
 
34764
 
34765
 
34766
 
34767
 
34768
 
34769
 
34770
 
34771
 
34772
 
34773
 
34774
 
34775
 
34776
 
34777
 
34778
 
34779
 
34780
 
34781
 
34782
 
34783
 
34784
 
34785
 
34786
 
34787
 
34788
 
34789
 
34790
 
34791
 
34792
 
34793
 
34794
 
34795
 
34796
 
34797
 
34798
 
34799
 
34800
 
34801
 
34802
 
34803
 
34804
 
34805
 
34806
 
34807
 
34808
 
34809
 
34810
 
34811
 
34812
 
34813
 
34814
 
34815
 
34816
 
34817
 
34818
 
34819
 
34820
 
34821
 
34822
 
34823
 
34824
 
34825
 
34826
 
34827
 
34828
 
34829
 
34830
 
34831
 
34832
 
34833
 
34834
 
34835
 
34836
 
34837
 
34838
 
34839
 
34840
 
34841
 
34842
 
34843
 
34844
 
34845
 
34846
 
34847
 
34848
 
34849
 
34850
 
34851
 
34852
 
34853
 
34854
 
34855
 
34856
 
34857
 
34858
 
34859
 
34860
 
34861
 
34862
 
34863
 
34864
 
34865
 
34866
 
34867
 
34868
 
34869
 
34870
 
34871
 
34872
 
34873
 
34874
 
34875
 
34876
 
34877
 
34878
 
34879
 
34880
 
34881
 
34882
 
34883
 
34884
 
34885
 
34886
 
34887
 
34888
 
34889
 
34890
 
34891
 
34892
 
34893
 
34894
 
34895
 
34896
 
34897
 
34898
 
34899
 
34900
 
34901
 
34902
 
34903
 
34904
 
34905
 
34906
 
34907
 
34908
 
34909
 
34910
 
34911
 
34912
 
34913
 
34914
 
34915
 
34916
 
34917
 
34918
 
34919
 
34920
 
34921
 
34922
 
34923
 
34924
 
34925
 
34926
 
34927
 
34928
 
34929
 
34930
 
34931
 
34932
 
34933
 
34934
 
34935
 
34936
 
34937
 
34938
 
34939
 
34940
 
34941
 
34942
 
34943
 
34944
 
34945
 
34946
 
34947
 
34948
 
34949
 
34950
 
34951
 
34952
 
34953
 
34954
 
34955
 
34956
 
34957
 
34958
 
34959
 
34960
 
34961
 
34962
 
34963
 
34964
 
34965
 
34966
 
34967
 
34968
 
34969
 
34970
 
34971
 
34972
 
34973
 
34974
 
34975
 
34976
 
34977
 
34978
 
34979
 
34980
 
34981
 
34982
 
34983
 
34984
 
34985
 
34986
 
34987
 
34988
 
34989
 
34990
 
34991
 
34992
 
34993
 
34994
 
34995
 
34996
 
34997
 
34998
 
34999
 
35000
 
35001
 
35002
 
35003
 
35004
 
35005
 
35006
 
35007
 
35008
 
35009
 
35010
 
35011
 
35012
 
35013
 
35014
 
35015
 
35016
 
35017
 
35018
 
35019
 
35020
 
35021
 
35022
 
35023
 
35024
 
35025
 
35026
 
35027
 
35028
 
35029
 
35030
 
35031
 
35032
 
35033
 
35034
 
35035
 
35036
 
35037
 
35038
 
35039
 
35040
 
35041
 
35042
 
35043
 
35044
 
35045
 
35046
 
35047
 
35048
 
35049
 
35050
 
35051
 
35052
 
35053
 
35054
 
35055
 
35056
 
35057
 
35058
 
35059
 
35060
 
35061
 
35062
 
35063
 
35064
 
35065
 
35066
 
35067
 
35068
 
35069
 
35070
 
35071
 
35072
 
35073
 
35074
 
35075
 
35076
 
35077
 
35078
 
35079
 
35080
 
35081
 
35082
 
35083
 
35084
 
35085
 
35086
 
35087
 
35088
 
35089
 
35090
 
35091
 
35092
 
35093
 
35094
 
35095
 
35096
 
35097
 
35098
 
35099
 
35100
 
35101
 
35102
 
35103
 
35104
 
35105
 
35106
 
35107
 
35108
 
35109
 
35110
 
35111
 
35112
 
35113
 
35114
 
35115
 
35116
 
35117
 
35118
 
35119
 
35120
 
35121
 
35122
 
35123
 
35124
 
35125
 
35126
 
35127
 
35128
 
35129
 
35130
 
35131
 
35132
 
35133
 
35134
 
35135
 
35136
 
35137
 
35138
 
35139
 
35140
 
35141
 
35142
 
35143
 
35144
 
35145
 
35146
 
35147
 
35148
 
35149
 
35150
 
35151
 
35152
 
35153
 
35154
 
35155
 
35156
 
35157
 
35158
 
35159
 
35160
 
35161
 
35162
 
35163
 
35164
 
35165
 
35166
 
35167
 
35168
 
35169
 
35170
 
35171
 
35172
 
35173
 
35174
 
35175
 
35176
 
35177
 
35178
 
35179
 
35180
 
35181
 
35182
 
35183
 
35184
 
35185
 
35186
 
35187
 
35188
 
35189
 
35190
 
35191
 
35192
 
35193
 
35194
 
35195
 
35196
 
35197
 
35198
 
35199
 
35200
 
35201
 
35202
 
35203
 
35204
 
35205
 
35206
 
35207
 
35208
 
35209
 
35210
 
35211
 
35212
 
35213
 
35214
 
35215
 
35216
 
35217
 
35218
 
35219
 
35220
 
35221
 
35222
 
35223
 
35224
 
35225
 
35226
 
35227
 
35228
 
35229
 
35230
 
35231
 
35232
 
35233
 
35234
 
35235
 
35236
 
35237
 
35238
 
35239
 
35240
 
35241
 
35242
 
35243
 
35244
 
35245
 
35246
 
35247
 
35248
 
35249
 
35250
 
35251
 
35252
 
35253
 
35254
 
35255
 
35256
 
35257
 
35258
 
35259
 
35260
 
35261
 
35262
 
35263
 
35264
 
35265
 
35266
 
35267
 
35268
 
35269
 
35270
 
35271
 
35272
 
35273
 
35274
 
35275
 
35276
 
35277
 
35278
 
35279
 
35280
 
35281
 
35282
 
35283
 
35284
 
35285
 
35286
 
35287
 
35288
 
35289
 
35290
 
35291
 
35292
 
35293
 
35294
 
35295
 
35296
 
35297
 
35298
 
35299
 
35300
 
35301
 
35302
 
35303
 
35304
 
35305
 
35306
 
35307
 
35308
 
35309
 
35310
 
35311
 
35312
 
35313
 
35314
 
35315
 
35316
 
35317
 
35318
 
35319
 
35320
 
35321
 
35322
 
35323
 
35324
 
35325
 
35326
 
35327
 
35328
 
35329
 
35330
 
35331
 
35332
 
35333
 
35334
 
35335
 
35336
 
35337
 
35338
 
35339
 
35340
 
35341
 
35342
 
35343
 
35344
 
35345
 
35346
 
35347
 
35348
 
35349
 
35350
 
35351
 
35352
 
35353
 
35354
 
35355
 
35356
 
35357
 
35358
 
35359
 
35360
 
35361
 
35362
 
35363
 
35364
 
35365
 
35366
 
35367
 
35368
 
35369
 
35370
 
35371
 
35372
 
35373
 
35374
 
35375
 
35376
 
35377
 
35378
 
35379
 
35380
 
35381
 
35382
 
35383
 
35384
 
35385
 
35386
 
35387
 
35388
 
35389
 
35390
 
35391
 
35392
 
35393
 
35394
 
35395
 
35396
 
35397
 
35398
 
35399
 
35400
 
35401
 
35402
 
35403
 
35404
 
35405
 
35406
 
35407
 
35408
 
35409
 
35410
 
35411
 
35412
 
35413
 
35414
 
35415
 
35416
 
35417
 
35418
 
35419
 
35420
 
35421
 
35422
 
35423
 
35424
 
35425
 
35426
 
35427
 
35428
 
35429
 
35430
 
35431
 
35432
 
35433
 
35434
 
35435
 
35436
 
35437
 
35438
 
35439
 
35440
 
35441
 
35442
 
35443
 
35444
 
35445
 
35446
 
35447
 
35448
 
35449
 
35450
 
35451
 
35452
 
35453
 
35454
 
35455
 
35456
 
35457
 
35458
 
35459
 
35460
 
35461
 
35462
 
35463
 
35464
 
35465
 
35466
 
35467
 
35468
 
35469
 
35470
 
35471
 
35472
 
35473
 
35474
 
35475
 
35476
 
35477
 
35478
 
35479
 
35480
 
35481
 
35482
 
35483
 
35484
 
35485
 
35486
 
35487
 
35488
 
35489
 
35490
 
35491
 
35492
 
35493
 
35494
 
35495
 
35496
 
35497
 
35498
 
35499
 
35500
 
35501
 
35502
 
35503
 
35504
 
35505
 
35506
 
35507
 
35508
 
35509
 
35510
 
35511
 
35512
 
35513
 
35514
 
35515
 
35516
 
35517
 
35518
 
35519
 
35520
 
35521
 
35522
 
35523
 
35524
 
35525
 
35526
 
35527
 
35528
 
35529
 
35530
 
35531
 
35532
 
35533
 
35534
 
35535
 
35536
 
35537
 
35538
 
35539
 
35540
 
35541
 
35542
 
35543
 
35544
 
35545
 
35546
 
35547
 
35548
 
35549
 
35550
 
35551
 
35552
 
35553
 
35554
 
35555
 
35556
 
35557
 
35558
 
35559
 
35560
 
35561
 
35562
 
35563
 
35564
 
35565
 
35566
 
35567
 
35568
 
35569
 
35570
 
35571
 
35572
 
35573
 
35574
 
35575
 
35576
 
35577
 
35578
 
35579
 
35580
 
35581
 
35582
 
35583
 
35584
 
35585
 
35586
 
35587
 
35588
 
35589
 
35590
 
35591
 
35592
 
35593
 
35594
 
35595
 
35596
 
35597
 
35598
 
35599
 
35600
 
35601
 
35602
 
35603
 
35604
 
35605
 
35606
 
35607
 
35608
 
35609
 
35610
 
35611
 
35612
 
35613
 
35614
 
35615
 
35616
 
35617
 
35618
 
35619
 
35620
 
35621
 
35622
 
35623
 
35624
 
35625
 
35626
 
35627
 
35628
 
35629
 
35630
 
35631
 
35632
 
35633
 
35634
 
35635
 
35636
 
35637
 
35638
 
35639
 
35640
 
35641
 
35642
 
35643
 
35644
 
35645
 
35646
 
35647
 
35648
 
35649
 
35650
 
35651
 
35652
 
35653
 
35654
 
35655
 
35656
 
35657
 
35658
 
35659
 
35660
 
35661
 
35662
 
35663
 
35664
 
35665
 
35666
 
35667
 
35668
 
35669
 
35670
 
35671
 
35672
 
35673
 
35674
 
35675
 
35676
 
35677
 
35678
 
35679
 
35680
 
35681
 
35682
 
35683
 
35684
 
35685
 
35686
 
35687
 
35688
 
35689
 
35690
 
35691
 
35692
 
35693
 
35694
 
35695
 
35696
 
35697
 
35698
 
35699
 
35700
 
35701
 
35702
 
35703
 
35704
 
35705
 
35706
 
35707
 
35708
 
35709
 
35710
 
35711
 
35712
 
35713
 
35714
 
35715
 
35716
 
35717
 
35718
 
35719
 
35720
 
35721
 
35722
 
35723
 
35724
 
35725
 
35726
 
35727
 
35728
 
35729
 
35730
 
35731
 
35732
 
35733
 
35734
 
35735
 
35736
 
35737
 
35738
 
35739
 
35740
 
35741
 
35742
 
35743
 
35744
 
35745
 
35746
 
35747
 
35748
 
35749
 
35750
 
35751
 
35752
 
35753
 
35754
 
35755
 
35756
 
35757
 
35758
 
35759
 
35760
 
35761
 
35762
 
35763
 
35764
 
35765
 
35766
 
35767
 
35768
 
35769
 
35770
 
35771
 
35772
 
35773
 
35774
 
35775
 
35776
 
35777
 
35778
 
35779
 
35780
 
35781
 
35782
 
35783
 
35784
 
35785
 
35786
 
35787
 
35788
 
35789
 
35790
 
35791
 
35792
 
35793
 
35794
 
35795
 
35796
 
35797
 
35798
 
35799
 
35800
 
35801
 
35802
 
35803
 
35804
 
35805
 
35806
 
35807
 
35808
 
35809
 
35810
 
35811
 
35812
 
35813
 
35814
 
35815
 
35816
 
35817
 
35818
 
35819
 
35820
 
35821
 
35822
 
35823
 
35824
 
35825
 
35826
 
35827
 
35828
 
35829
 
35830
 
35831
 
35832
 
35833
 
35834
 
35835
 
35836
 
35837
 
35838
 
35839
 
35840
 
35841
 
35842
 
35843
 
35844
 
35845
 
35846
 
35847
 
35848
 
35849
 
35850
 
35851
 
35852
 
35853
 
35854
 
35855
 
35856
 
35857
 
35858
 
35859
 
35860
 
35861
 
35862
 
35863
 
35864
 
35865
 
35866
 
35867
 
35868
 
35869
 
35870
 
35871
 
35872
 
35873
 
35874
 
35875
 
35876
 
35877
 
35878
 
35879
 
35880
 
35881
 
35882
 
35883
 
35884
 
35885
 
35886
 
35887
 
35888
 
35889
 
35890
 
35891
 
35892
 
35893
 
35894
 
35895
 
35896
 
35897
 
35898
 
35899
 
35900
 
35901
 
35902
 
35903
 
35904
 
35905
 
35906
 
35907
 
35908
 
35909
 
35910
 
35911
 
35912
 
35913
 
35914
 
35915
 
35916
 
35917
 
35918
 
35919
 
35920
 
35921
 
35922
 
35923
 
35924
 
35925
 
35926
 
35927
 
35928
 
35929
 
35930
 
35931
 
35932
 
35933
 
35934
 
35935
 
35936
 
35937
 
35938
 
35939
 
35940
 
35941
 
35942
 
35943
 
35944
 
35945
 
35946
 
35947
 
35948
 
35949
 
35950
 
35951
 
35952
 
35953
 
35954
 
35955
 
35956
 
35957
 
35958
 
35959
 
35960
 
35961
 
35962
 
35963
 
35964
 
35965
 
35966
 
35967
 
35968
 
35969
 
35970
 
35971
 
35972
 
35973
 
35974
 
35975
 
35976
 
35977
 
35978
 
35979
 
35980
 
35981
 
35982
 
35983
 
35984
 
35985
 
35986
 
35987
 
35988
 
35989
 
35990
 
35991
 
35992
 
35993
 
35994
 
35995
 
35996
 
35997
 
35998
 
35999
 
36000
 
36001
 
36002
 
36003
 
36004
 
36005
 
36006
 
36007
 
36008
 
36009
 
36010
 
36011
 
36012
 
36013
 
36014
 
36015
 
36016
 
36017
 
36018
 
36019
 
36020
 
36021
 
36022
 
36023
 
36024
 
36025
 
36026
 
36027
 
36028
 
36029
 
36030
 
36031
 
36032
 
36033
 
36034
 
36035
 
36036
 
36037
 
36038
 
36039
 
36040
 
36041
 
36042
 
36043
 
36044
 
36045
 
36046
 
36047
 
36048
 
36049
 
36050
 
36051
 
36052
 
36053
 
36054
 
36055
 
36056
 
36057
 
36058
 
36059
 
36060
 
36061
 
36062
 
36063
 
36064
 
36065
 
36066
 
36067
 
36068
 
36069
 
36070
 
36071
 
36072
 
36073
 
36074
 
36075
 
36076
 
36077
 
36078
 
36079
 
36080
 
36081
 
36082
 
36083
 
36084
 
36085
 
36086
 
36087
 
36088
 
36089
 
36090
 
36091
 
36092
 
36093
 
36094
 
36095
 
36096
 
36097
 
36098
 
36099
 
36100
 
36101
 
36102
 
36103
 
36104
 
36105
 
36106
 
36107
 
36108
 
36109
 
36110
 
36111
 
36112
 
36113
 
36114
 
36115
 
36116
 
36117
 
36118
 
36119
 
36120
 
36121
 
36122
 
36123
 
36124
 
36125
 
36126
 
36127
 
36128
 
36129
 
36130
 
36131
 
36132
 
36133
 
36134
 
36135
 
36136
 
36137
 
36138
 
36139
 
36140
 
36141
 
36142
 
36143
 
36144
 
36145
 
36146
 
36147
 
36148
 
36149
 
36150
 
36151
 
36152
 
36153
 
36154
 
36155
 
36156
 
36157
 
36158
 
36159
 
36160
 
36161
 
36162
 
36163
 
36164
 
36165
 
36166
 
36167
 
36168
 
36169
 
36170
 
36171
 
36172
 
36173
 
36174
 
36175
 
36176
 
36177
 
36178
 
36179
 
36180
 
36181
 
36182
 
36183
 
36184
 
36185
 
36186
 
36187
 
36188
 
36189
 
36190
 
36191
 
36192
 
36193
 
36194
 
36195
 
36196
 
36197
 
36198
 
36199
 
36200
 
36201
 
36202
 
36203
 
36204
 
36205
 
36206
 
36207
 
36208
 
36209
 
36210
 
36211
 
36212
 
36213
 
36214
 
36215
 
36216
 
36217
 
36218
 
36219
 
36220
 
36221
 
36222
 
36223
 
36224
 
36225
 
36226
 
36227
 
36228
 
36229
 
36230
 
36231
 
36232
 
36233
 
36234
 
36235
 
36236
 
36237
 
36238
 
36239
 
36240
 
36241
 
36242
 
36243
 
36244
 
36245
 
36246
 
36247
 
36248
 
36249
 
36250
 
36251
 
36252
 
36253
 
36254
 
36255
 
36256
 
36257
 
36258
 
36259
 
36260
 
36261
 
36262
 
36263
 
36264
 
36265
 
36266
 
36267
 
36268
 
36269
 
36270
 
36271
 
36272
 
36273
 
36274
 
36275
 
36276
 
36277
 
36278
 
36279
 
36280
 
36281
 
36282
 
36283
 
36284
 
36285
 
36286
 
36287
 
36288
 
36289
 
36290
 
36291
 
36292
 
36293
 
36294
 
36295
 
36296
 
36297
 
36298
 
36299
 
36300
 
36301
 
36302
 
36303
 
36304
 
36305
 
36306
 
36307
 
36308
 
36309
 
36310
 
36311
 
36312
 
36313
 
36314
 
36315
 
36316
 
36317
 
36318
 
36319
 
36320
 
36321
 
36322
 
36323
 
36324
 
36325
 
36326
 
36327
 
36328
 
36329
 
36330
 
36331
 
36332
 
36333
 
36334
 
36335
 
36336
 
36337
 
36338
 
36339
 
36340
 
36341
 
36342
 
36343
 
36344
 
36345
 
36346
 
36347
 
36348
 
36349
 
36350
 
36351
 
36352
 
36353
 
36354
 
36355
 
36356
 
36357
 
36358
 
36359
 
36360
 
36361
 
36362
 
36363
 
36364
 
36365
 
36366
 
36367
 
36368
 
36369
 
36370
 
36371
 
36372
 
36373
 
36374
 
36375
 
36376
 
36377
 
36378
 
36379
 
36380
 
36381
 
36382
 
36383
 
36384
 
36385
 
36386
 
36387
 
36388
 
36389
 
36390
 
36391
 
36392
 
36393
 
36394
 
36395
 
36396
 
36397
 
36398
 
36399
 
36400
 
36401
 
36402
 
36403
 
36404
 
36405
 
36406
 
36407
 
36408
 
36409
 
36410
 
36411
 
36412
 
36413
 
36414
 
36415
 
36416
 
36417
 
36418
 
36419
 
36420
 
36421
 
36422
 
36423
 
36424
 
36425
 
36426
 
36427
 
36428
 
36429
 
36430
 
36431
 
36432
 
36433
 
36434
 
36435
 
36436
 
36437
 
36438
 
36439
 
36440
 
36441
 
36442
 
36443
 
36444
 
36445
 
36446
 
36447
 
36448
 
36449
 
36450
 
36451
 
36452
 
36453
 
36454
 
36455
 
36456
 
36457
 
36458
 
36459
 
36460
 
36461
 
36462
 
36463
 
36464
 
36465
 
36466
 
36467
 
36468
 
36469
 
36470
 
36471
 
36472
 
36473
 
36474
 
36475
 
36476
 
36477
 
36478
 
36479
 
36480
 
36481
 
36482
 
36483
 
36484
 
36485
 
36486
 
36487
 
36488
 
36489
 
36490
 
36491
 
36492
 
36493
 
36494
 
36495
 
36496
 
36497
 
36498
 
36499
 
36500
 
36501
 
36502
 
36503
 
36504
 
36505
 
36506
 
36507
 
36508
 
36509
 
36510
 
36511
 
36512
 
36513
 
36514
 
36515
 
36516
 
36517
 
36518
 
36519
 
36520
 
36521
 
36522
 
36523
 
36524
 
36525
 
36526
 
36527
 
36528
 
36529
 
36530
 
36531
 
36532
 
36533
 
36534
 
36535
 
36536
 
36537
 
36538
 
36539
 
36540
 
36541
 
36542
 
36543
 
36544
 
36545
 
36546
 
36547
 
36548
 
36549
 
36550
 
36551
 
36552
 
36553
 
36554
 
36555
 
36556
 
36557
 
36558
 
36559
 
36560
 
36561
 
36562
 
36563
 
36564
 
36565
 
36566
 
36567
 
36568
 
36569
 
36570
 
36571
 
36572
 
36573
 
36574
 
36575
 
36576
 
36577
 
36578
 
36579
 
36580
 
36581
 
36582
 
36583
 
36584
 
36585
 
36586
 
36587
 
36588
 
36589
 
36590
 
36591
 
36592
 
36593
 
36594
 
36595
 
36596
 
36597
 
36598
 
36599
 
36600
 
36601
 
36602
 
36603
 
36604
 
36605
 
36606
 
36607
 
36608
 
36609
 
36610
 
36611
 
36612
 
36613
 
36614
 
36615
 
36616
 
36617
 
36618
 
36619
 
36620
 
36621
 
36622
 
36623
 
36624
 
36625
 
36626
 
36627
 
36628
 
36629
 
36630
 
36631
 
36632
 
36633
 
36634
 
36635
 
36636
 
36637
 
36638
 
36639
 
36640
 
36641
 
36642
 
36643
 
36644
 
36645
 
36646
 
36647
 
36648
 
36649
 
36650
 
36651
 
36652
 
36653
 
36654
 
36655
 
36656
 
36657
 
36658
 
36659
 
36660
 
36661
 
36662
 
36663
 
36664
 
36665
 
36666
 
36667
 
36668
 
36669
 
36670
 
36671
 
36672
 
36673
 
36674
 
36675
 
36676
 
36677
 
36678
 
36679
 
36680
 
36681
 
36682
 
36683
 
36684
 
36685
 
36686
 
36687
 
36688
 
36689
 
36690
 
36691
 
36692
 
36693
 
36694
 
36695
 
36696
 
36697
 
36698
 
36699
 
36700
 
36701
 
36702
 
36703
 
36704
 
36705
 
36706
 
36707
 
36708
 
36709
 
36710
 
36711
 
36712
 
36713
 
36714
 
36715
 
36716
 
36717
 
36718
 
36719
 
36720
 
36721
 
36722
 
36723
 
36724
 
36725
 
36726
 
36727
 
36728
 
36729
 
36730
 
36731
 
36732
 
36733
 
36734
 
36735
 
36736
 
36737
 
36738
 
36739
 
36740
 
36741
 
36742
 
36743
 
36744
 
36745
 
36746
 
36747
 
36748
 
36749
 
36750
 
36751
 
36752
 
36753
 
36754
 
36755
 
36756
 
36757
 
36758
 
36759
 
36760
 
36761
 
36762
 
36763
 
36764
 
36765
 
36766
 
36767
 
36768
 
36769
 
36770
 
36771
 
36772
 
36773
 
36774
 
36775
 
36776
 
36777
 
36778
 
36779
 
36780
 
36781
 
36782
 
36783
 
36784
 
36785
 
36786
 
36787
 
36788
 
36789
 
36790
 
36791
 
36792
 
36793
 
36794
 
36795
 
36796
 
36797
 
36798
 
36799
 
36800
 
36801
 
36802
 
36803
 
36804
 
36805
 
36806
 
36807
 
36808
 
36809
 
36810
 
36811
 
36812
 
36813
 
36814
 
36815
 
36816
 
36817
 
36818
 
36819
 
36820
 
36821
 
36822
 
36823
 
36824
 
36825
 
36826
 
36827
 
36828
 
36829
 
36830
 
36831
 
36832
 
36833
 
36834
 
36835
 
36836
 
36837
 
36838
 
36839
 
36840
 
36841
 
36842
 
36843
 
36844
 
36845
 
36846
 
36847
 
36848
 
36849
 
36850
 
36851
 
36852
 
36853
 
36854
 
36855
 
36856
 
36857
 
36858
 
36859
 
36860
 
36861
 
36862
 
36863
 
36864
 
36865
 
36866
 
36867
 
36868
 
36869
 
36870
 
36871
 
36872
 
36873
 
36874
 
36875
 
36876
 
36877
 
36878
 
36879
 
36880
 
36881
 
36882
 
36883
 
36884
 
36885
 
36886
 
36887
 
36888
 
36889
 
36890
 
36891
 
36892
 
36893
 
36894
 
36895
 
36896
 
36897
 
36898
 
36899
 
36900
 
36901
 
36902
 
36903
 
36904
 
36905
 
36906
 
36907
 
36908
 
36909
 
36910
 
36911
 
36912
 
36913
 
36914
 
36915
 
36916
 
36917
 
36918
 
36919
 
36920
 
36921
 
36922
 
36923
 
36924
 
36925
 
36926
 
36927
 
36928
 
36929
 
36930
 
36931
 
36932
 
36933
 
36934
 
36935
 
36936
 
36937
 
36938
 
36939
 
36940
 
36941
 
36942
 
36943
 
36944
 
36945
 
36946
 
36947
 
36948
 
36949
 
36950
 
36951
 
36952
 
36953
 
36954
 
36955
 
36956
 
36957
 
36958
 
36959
 
36960
 
36961
 
36962
 
36963
 
36964
 
36965
 
36966
 
36967
 
36968
 
36969
 
36970
 
36971
 
36972
 
36973
 
36974
 
36975
 
36976
 
36977
 
36978
 
36979
 
36980
 
36981
 
36982
 
36983
 
36984
 
36985
 
36986
 
36987
 
36988
 
36989
 
36990
 
36991
 
36992
 
36993
 
36994
 
36995
 
36996
 
36997
 
36998
 
36999
 
37000
 
37001
 
37002
 
37003
 
37004
 
37005
 
37006
 
37007
 
37008
 
37009
 
37010
 
37011
 
37012
 
37013
 
37014
 
37015
 
37016
 
37017
 
37018
 
37019
 
37020
 
37021
 
37022
 
37023
 
37024
 
37025
 
37026
 
37027
 
37028
 
37029
 
37030
 
37031
 
37032
 
37033
 
37034
 
37035
 
37036
 
37037
 
37038
 
37039
 
37040
 
37041
 
37042
 
37043
 
37044
 
37045
 
37046
 
37047
 
37048
 
37049
 
37050
 
37051
 
37052
 
37053
 
37054
 
37055
 
37056
 
37057
 
37058
 
37059
 
37060
 
37061
 
37062
 
37063
 
37064
 
37065
 
37066
 
37067
 
37068
 
37069
 
37070
 
37071
 
37072
 
37073
 
37074
 
37075
 
37076
 
37077
 
37078
 
37079
 
37080
 
37081
 
37082
 
37083
 
37084
 
37085
 
37086
 
37087
 
37088
 
37089
 
37090
 
37091
 
37092
 
37093
 
37094
 
37095
 
37096
 
37097
 
37098
 
37099
 
37100
 
37101
 
37102
 
37103
 
37104
 
37105
 
37106
 
37107
 
37108
 
37109
 
37110
 
37111
 
37112
 
37113
 
37114
 
37115
 
37116
 
37117
 
37118
 
37119
 
37120
 
37121
 
37122
 
37123
 
37124
 
37125
 
37126
 
37127
 
37128
 
37129
 
37130
 
37131
 
37132
 
37133
 
37134
 
37135
 
37136
 
37137
 
37138
 
37139
 
37140
 
37141
 
37142
 
37143
 
37144
 
37145
 
37146
 
37147
 
37148
 
37149
 
37150
 
37151
 
37152
 
37153
 
37154
 
37155
 
37156
 
37157
 
37158
 
37159
 
37160
 
37161
 
37162
 
37163
 
37164
 
37165
 
37166
 
37167
 
37168
 
37169
 
37170
 
37171
 
37172
 
37173
 
37174
 
37175
 
37176
 
37177
 
37178
 
37179
 
37180
 
37181
 
37182
 
37183
 
37184
 
37185
 
37186
 
37187
 
37188
 
37189
 
37190
 
37191
 
37192
 
37193
 
37194
 
37195
 
37196
 
37197
 
37198
 
37199
 
37200
 
37201
 
37202
 
37203
 
37204
 
37205
 
37206
 
37207
 
37208
 
37209
 
37210
 
37211
 
37212
 
37213
 
37214
 
37215
 
37216
 
37217
 
37218
 
37219
 
37220
 
37221
 
37222
 
37223
 
37224
 
37225
 
37226
 
37227
 
37228
 
37229
 
37230
 
37231
 
37232
 
37233
 
37234
 
37235
 
37236
 
37237
 
37238
 
37239
 
37240
 
37241
 
37242
 
37243
 
37244
 
37245
 
37246
 
37247
 
37248
 
37249
 
37250
 
37251
 
37252
 
37253
 
37254
 
37255
 
37256
 
37257
 
37258
 
37259
 
37260
 
37261
 
37262
 
37263
 
37264
 
37265
 
37266
 
37267
 
37268
 
37269
 
37270
 
37271
 
37272
 
37273
 
37274
 
37275
 
37276
 
37277
 
37278
 
37279
 
37280
 
37281
 
37282
 
37283
 
37284
 
37285
 
37286
 
37287
 
37288
 
37289
 
37290
 
37291
 
37292
 
37293
 
37294
 
37295
 
37296
 
37297
 
37298
 
37299
 
37300
 
37301
 
37302
 
37303
 
37304
 
37305
 
37306
 
37307
 
37308
 
37309
 
37310
 
37311
 
37312
 
37313
 
37314
 
37315
 
37316
 
37317
 
37318
 
37319
 
37320
 
37321
 
37322
 
37323
 
37324
 
37325
 
37326
 
37327
 
37328
 
37329
 
37330
 
37331
 
37332
 
37333
 
37334
 
37335
 
37336
 
37337
 
37338
 
37339
 
37340
 
37341
 
37342
 
37343
 
37344
 
37345
 
37346
 
37347
 
37348
 
37349
 
37350
 
37351
 
37352
 
37353
 
37354
 
37355
 
37356
 
37357
 
37358
 
37359
 
37360
 
37361
 
37362
 
37363
 
37364
 
37365
 
37366
 
37367
 
37368
 
37369
 
37370
 
37371
 
37372
 
37373
 
37374
 
37375
 
37376
 
37377
 
37378
 
37379
 
37380
 
37381
 
37382
 
37383
 
37384
 
37385
 
37386
 
37387
 
37388
 
37389
 
37390
 
37391
 
37392
 
37393
 
37394
 
37395
 
37396
 
37397
 
37398
 
37399
 
37400
 
37401
 
37402
 
37403
 
37404
 
37405
 
37406
 
37407
 
37408
 
37409
 
37410
 
37411
 
37412
 
37413
 
37414
 
37415
 
37416
 
37417
 
37418
 
37419
 
37420
 
37421
 
37422
 
37423
 
37424
 
37425
 
37426
 
37427
 
37428
 
37429
 
37430
 
37431
 
37432
 
37433
 
37434
 
37435
 
37436
 
37437
 
37438
 
37439
 
37440
 
37441
 
37442
 
37443
 
37444
 
37445
 
37446
 
37447
 
37448
 
37449
 
37450
 
37451
 
37452
 
37453
 
37454
 
37455
 
37456
 
37457
 
37458
 
37459
 
37460
 
37461
 
37462
 
37463
 
37464
 
37465
 
37466
 
37467
 
37468
 
37469
 
37470
 
37471
 
37472
 
37473
 
37474
 
37475
 
37476
 
37477
 
37478
 
37479
 
37480
 
37481
 
37482
 
37483
 
37484
 
37485
 
37486
 
37487
 
37488
 
37489
 
37490
 
37491
 
37492
 
37493
 
37494
 
37495
 
37496
 
37497
 
37498
 
37499
 
37500
 
37501
 
37502
 
37503
 
37504
 
37505
 
37506
 
37507
 
37508
 
37509
 
37510
 
37511
 
37512
 
37513
 
37514
 
37515
 
37516
 
37517
 
37518
 
37519
 
37520
 
37521
 
37522
 
37523
 
37524
 
37525
 
37526
 
37527
 
37528
 
37529
 
37530
 
37531
 
37532
 
37533
 
37534
 
37535
 
37536
 
37537
 
37538
 
37539
 
37540
 
37541
 
37542
 
37543
 
37544
 
37545
 
37546
 
37547
 
37548
 
37549
 
37550
 
37551
 
37552
 
37553
 
37554
 
37555
 
37556
 
37557
 
37558
 
37559
 
37560
 
37561
 
37562
 
37563
 
37564
 
37565
 
37566
 
37567
 
37568
 
37569
 
37570
 
37571
 
37572
 
37573
 
37574
 
37575
 
37576
 
37577
 
37578
 
37579
 
37580
 
37581
 
37582
 
37583
 
37584
 
37585
 
37586
 
37587
 
37588
 
37589
 
37590
 
37591
 
37592
 
37593
 
37594
 
37595
 
37596
 
37597
 
37598
 
37599
 
37600
 
37601
 
37602
 
37603
 
37604
 
37605
 
37606
 
37607
 
37608
 
37609
 
37610
 
37611
 
37612
 
37613
 
37614
 
37615
 
37616
 
37617
 
37618
 
37619
 
37620
 
37621
 
37622
 
37623
 
37624
 
37625
 
37626
 
37627
 
37628
 
37629
 
37630
 
37631
 
37632
 
37633
 
37634
 
37635
 
37636
 
37637
 
37638
 
37639
 
37640
 
37641
 
37642
 
37643
 
37644
 
37645
 
37646
 
37647
 
37648
 
37649
 
37650
 
37651
 
37652
 
37653
 
37654
 
37655
 
37656
 
37657
 
37658
 
37659
 
37660
 
37661
 
37662
 
37663
 
37664
 
37665
 
37666
 
37667
 
37668
 
37669
 
37670
 
37671
 
37672
 
37673
 
37674
 
37675
 
37676
 
37677
 
37678
 
37679
 
37680
 
37681
 
37682
 
37683
 
37684
 
37685
 
37686
 
37687
 
37688
 
37689
 
37690
 
37691
 
37692
 
37693
 
37694
 
37695
 
37696
 
37697
 
37698
 
37699
 
37700
 
37701
 
37702
 
37703
 
37704
 
37705
 
37706
 
37707
 
37708
 
37709
 
37710
 
37711
 
37712
 
37713
 
37714
 
37715
 
37716
 
37717
 
37718
 
37719
 
37720
 
37721
 
37722
 
37723
 
37724
 
37725
 
37726
 
37727
 
37728
 
37729
 
37730
 
37731
 
37732
 
37733
 
37734
 
37735
 
37736
 
37737
 
37738
 
37739
 
37740
 
37741
 
37742
 
37743
 
37744
 
37745
 
37746
 
37747
 
37748
 
37749
 
37750
 
37751
 
37752
 
37753
 
37754
 
37755
 
37756
 
37757
 
37758
 
37759
 
37760
 
37761
 
37762
 
37763
 
37764
 
37765
 
37766
 
37767
 
37768
 
37769
 
37770
 
37771
 
37772
 
37773
 
37774
 
37775
 
37776
 
37777
 
37778
 
37779
 
37780
 
37781
 
37782
 
37783
 
37784
 
37785
 
37786
 
37787
 
37788
 
37789
 
37790
 
37791
 
37792
 
37793
 
37794
 
37795
 
37796
 
37797
 
37798
 
37799
 
37800
 
37801
 
37802
 
37803
 
37804
 
37805
 
37806
 
37807
 
37808
 
37809
 
37810
 
37811
 
37812
 
37813
 
37814
 
37815
 
37816
 
37817
 
37818
 
37819
 
37820
 
37821
 
37822
 
37823
 
37824
 
37825
 
37826
 
37827
 
37828
 
37829
 
37830
 
37831
 
37832
 
37833
 
37834
 
37835
 
37836
 
37837
 
37838
 
37839
 
37840
 
37841
 
37842
 
37843
 
37844
 
37845
 
37846
 
37847
 
37848
 
37849
 
37850
 
37851
 
37852
 
37853
 
37854
 
37855
 
37856
 
37857
 
37858
 
37859
 
37860
 
37861
 
37862
 
37863
 
37864
 
37865
 
37866
 
37867
 
37868
 
37869
 
37870
 
37871
 
37872
 
37873
 
37874
 
37875
 
37876
 
37877
 
37878
 
37879
 
37880
 
37881
 
37882
 
37883
 
37884
 
37885
 
37886
 
37887
 
37888
 
37889
 
37890
 
37891
 
37892
 
37893
 
37894
 
37895
 
37896
 
37897
 
37898
 
37899
 
37900
 
37901
 
37902
 
37903
 
37904
 
37905
 
37906
 
37907
 
37908
 
37909
 
37910
 
37911
 
37912
 
37913
 
37914
 
37915
 
37916
 
37917
 
37918
 
37919
 
37920
 
37921
 
37922
 
37923
 
37924
 
37925
 
37926
 
37927
 
37928
 
37929
 
37930
 
37931
 
37932
 
37933
 
37934
 
37935
 
37936
 
37937
 
37938
 
37939
 
37940
 
37941
 
37942
 
37943
 
37944
 
37945
 
37946
 
37947
 
37948
 
37949
 
37950
 
37951
 
37952
 
37953
 
37954
 
37955
 
37956
 
37957
 
37958
 
37959
 
37960
 
37961
 
37962
 
37963
 
37964
 
37965
 
37966
 
37967
 
37968
 
37969
 
37970
 
37971
 
37972
 
37973
 
37974
 
37975
 
37976
 
37977
 
37978
 
37979
 
37980
 
37981
 
37982
 
37983
 
37984
 
37985
 
37986
 
37987
 
37988
 
37989
 
37990
 
37991
 
37992
 
37993
 
37994
 
37995
 
37996
 
37997
 
37998
 
37999
 
38000
 
38001
 
38002
 
38003
 
38004
 
38005
 
38006
 
38007
 
38008
 
38009
 
38010
 
38011
 
38012
 
38013
 
38014
 
38015
 
38016
 
38017
 
38018
 
38019
 
38020
 
38021
 
38022
 
38023
 
38024
 
38025
 
38026
 
38027
 
38028
 
38029
 
38030
 
38031
 
38032
 
38033
 
38034
 
38035
 
38036
 
38037
 
38038
 
38039
 
38040
 
38041
 
38042
 
38043
 
38044
 
38045
 
38046
 
38047
 
38048
 
38049
 
38050
 
38051
 
38052
 
38053
 
38054
 
38055
 
38056
 
38057
 
38058
 
38059
 
38060
 
38061
 
38062
 
38063
 
38064
 
38065
 
38066
 
38067
 
38068
 
38069
 
38070
 
38071
 
38072
 
38073
 
38074
 
38075
 
38076
 
38077
 
38078
 
38079
 
38080
 
38081
 
38082
 
38083
 
38084
 
38085
 
38086
 
38087
 
38088
 
38089
 
38090
 
38091
 
38092
 
38093
 
38094
 
38095
 
38096
 
38097
 
38098
 
38099
 
38100
 
38101
 
38102
 
38103
 
38104
 
38105
 
38106
 
38107
 
38108
 
38109
 
38110
 
38111
 
38112
 
38113
 
38114
 
38115
 
38116
 
38117
 
38118
 
38119
 
38120
 
38121
 
38122
 
38123
 
38124
 
38125
 
38126
 
38127
 
38128
 
38129
 
38130
 
38131
 
38132
 
38133
 
38134
 
38135
 
38136
 
38137
 
38138
 
38139
 
38140
 
38141
 
38142
 
38143
 
38144
 
38145
 
38146
 
38147
 
38148
 
38149
 
38150
 
38151
 
38152
 
38153
 
38154
 
38155
 
38156
 
38157
 
38158
 
38159
 
38160
 
38161
 
38162
 
38163
 
38164
 
38165
 
38166
 
38167
 
38168
 
38169
 
38170
 
38171
 
38172
 
38173
 
38174
 
38175
 
38176
 
38177
 
38178
 
38179
 
38180
 
38181
 
38182
 
38183
 
38184
 
38185
 
38186
 
38187
 
38188
 
38189
 
38190
 
38191
 
38192
 
38193
 
38194
 
38195
 
38196
 
38197
 
38198
 
38199
 
38200
 
38201
 
38202
 
38203
 
38204
 
38205
 
38206
 
38207
 
38208
 
38209
 
38210
 
38211
 
38212
 
38213
 
38214
 
38215
 
38216
 
38217
 
38218
 
38219
 
38220
 
38221
 
38222
 
38223
 
38224
 
38225
 
38226
 
38227
 
38228
 
38229
 
38230
 
38231
 
38232
 
38233
 
38234
 
38235
 
38236
 
38237
 
38238
 
38239
 
38240
 
38241
 
38242
 
38243
 
38244
 
38245
 
38246
 
38247
 
38248
 
38249
 
38250
 
38251
 
38252
 
38253
 
38254
 
38255
 
38256
 
38257
 
38258
 
38259
 
38260
 
38261
 
38262
 
38263
 
38264
 
38265
 
38266
 
38267
 
38268
 
38269
 
38270
 
38271
 
38272
 
38273
 
38274
 
38275
 
38276
 
38277
 
38278
 
38279
 
38280
 
38281
 
38282
 
38283
 
38284
 
38285
 
38286
 
38287
 
38288
 
38289
 
38290
 
38291
 
38292
 
38293
 
38294
 
38295
 
38296
 
38297
 
38298
 
38299
 
38300
 
38301
 
38302
 
38303
 
38304
 
38305
 
38306
 
38307
 
38308
 
38309
 
38310
 
38311
 
38312
 
38313
 
38314
 
38315
 
38316
 
38317
 
38318
 
38319
 
38320
 
38321
 
38322
 
38323
 
38324
 
38325
 
38326
 
38327
 
38328
 
38329
 
38330
 
38331
 
38332
 
38333
 
38334
 
38335
 
38336
 
38337
 
38338
 
38339
 
38340
 
38341
 
38342
 
38343
 
38344
 
38345
 
38346
 
38347
 
38348
 
38349
 
38350
 
38351
 
38352
 
38353
 
38354
 
38355
 
38356
 
38357
 
38358
 
38359
 
38360
 
38361
 
38362
 
38363
 
38364
 
38365
 
38366
 
38367
 
38368
 
38369
 
38370
 
38371
 
38372
 
38373
 
38374
 
38375
 
38376
 
38377
 
38378
 
38379
 
38380
 
38381
 
38382
 
38383
 
38384
 
38385
 
38386
 
38387
 
38388
 
38389
 
38390
 
38391
 
38392
 
38393
 
38394
 
38395
 
38396
 
38397
 
38398
 
38399
 
38400
 
38401
 
38402
 
38403
 
38404
 
38405
 
38406
 
38407
 
38408
 
38409
 
38410
 
38411
 
38412
 
38413
 
38414
 
38415
 
38416
 
38417
 
38418
 
38419
 
38420
 
38421
 
38422
 
38423
 
38424
 
38425
 
38426
 
38427
 
38428
 
38429
 
38430
 
38431
 
38432
 
38433
 
38434
 
38435
 
38436
 
38437
 
38438
 
38439
 
38440
 
38441
 
38442
 
38443
 
38444
 
38445
 
38446
 
38447
 
38448
 
38449
 
38450
 
38451
 
38452
 
38453
 
38454
 
38455
 
38456
 
38457
 
38458
 
38459
 
38460
 
38461
 
38462
 
38463
 
38464
 
38465
 
38466
 
38467
 
38468
 
38469
 
38470
 
38471
 
38472
 
38473
 
38474
 
38475
 
38476
 
38477
 
38478
 
38479
 
38480
 
38481
 
38482
 
38483
 
38484
 
38485
 
38486
 
38487
 
38488
 
38489
 
38490
 
38491
 
38492
 
38493
 
38494
 
38495
 
38496
 
38497
 
38498
 
38499
 
38500
 
38501
 
38502
 
38503
 
38504
 
38505
 
38506
 
38507
 
38508
 
38509
 
38510
 
38511
 
38512
 
38513
 
38514
 
38515
 
38516
 
38517
 
38518
 
38519
 
38520
 
38521
 
38522
 
38523
 
38524
 
38525
 
38526
 
38527
 
38528
 
38529
 
38530
 
38531
 
38532
 
38533
 
38534
 
38535
 
38536
 
38537
 
38538
 
38539
 
38540
 
38541
 
38542
 
38543
 
38544
 
38545
 
38546
 
38547
 
38548
 
38549
 
38550
 
38551
 
38552
 
38553
 
38554
 
38555
 
38556
 
38557
 
38558
 
38559
 
38560
 
38561
 
38562
 
38563
 
38564
 
38565
 
38566
 
38567
 
38568
 
38569
 
38570
 
38571
 
38572
 
38573
 
38574
 
38575
 
38576
 
38577
 
38578
 
38579
 
38580
 
38581
 
38582
 
38583
 
38584
 
38585
 
38586
 
38587
 
38588
 
38589
 
38590
 
38591
 
38592
 
38593
 
38594
 
38595
 
38596
 
38597
 
38598
 
38599
 
38600
 
38601
 
38602
 
38603
 
38604
 
38605
 
38606
 
38607
 
38608
 
38609
 
38610
 
38611
 
38612
 
38613
 
38614
 
38615
 
38616
 
38617
 
38618
 
38619
 
38620
 
38621
 
38622
 
38623
 
38624
 
38625
 
38626
 
38627
 
38628
 
38629
 
38630
 
38631
 
38632
 
38633
 
38634
 
38635
 
38636
 
38637
 
38638
 
38639
 
38640
 
38641
 
38642
 
38643
 
38644
 
38645
 
38646
 
38647
 
38648
 
38649
 
38650
 
38651
 
38652
 
38653
 
38654
 
38655
 
38656
 
38657
 
38658
 
38659
 
38660
 
38661
 
38662
 
38663
 
38664
 
38665
 
38666
 
38667
 
38668
 
38669
 
38670
 
38671
 
38672
 
38673
 
38674
 
38675
 
38676
 
38677
 
38678
 
38679
 
38680
 
38681
 
38682
 
38683
 
38684
 
38685
 
38686
 
38687
 
38688
 
38689
 
38690
 
38691
 
38692
 
38693
 
38694
 
38695
 
38696
 
38697
 
38698
 
38699
 
38700
 
38701
 
38702
 
38703
 
38704
 
38705
 
38706
 
38707
 
38708
 
38709
 
38710
 
38711
 
38712
 
38713
 
38714
 
38715
 
38716
 
38717
 
38718
 
38719
 
38720
 
38721
 
38722
 
38723
 
38724
 
38725
 
38726
 
38727
 
38728
 
38729
 
38730
 
38731
 
38732
 
38733
 
38734
 
38735
 
38736
 
38737
 
38738
 
38739
 
38740
 
38741
 
38742
 
38743
 
38744
 
38745
 
38746
 
38747
 
38748
 
38749
 
38750
 
38751
 
38752
 
38753
 
38754
 
38755
 
38756
 
38757
 
38758
 
38759
 
38760
 
38761
 
38762
 
38763
 
38764
 
38765
 
38766
 
38767
 
38768
 
38769
 
38770
 
38771
 
38772
 
38773
 
38774
 
38775
 
38776
 
38777
 
38778
 
38779
 
38780
 
38781
 
38782
 
38783
 
38784
 
38785
 
38786
 
38787
 
38788
 
38789
 
38790
 
38791
 
38792
 
38793
 
38794
 
38795
 
38796
 
38797
 
38798
 
38799
 
38800
 
38801
 
38802
 
38803
 
38804
 
38805
 
38806
 
38807
 
38808
 
38809
 
38810
 
38811
 
38812
 
38813
 
38814
 
38815
 
38816
 
38817
 
38818
 
38819
 
38820
 
38821
 
38822
 
38823
 
38824
 
38825
 
38826
 
38827
 
38828
 
38829
 
38830
 
38831
 
38832
 
38833
 
38834
 
38835
 
38836
 
38837
 
38838
 
38839
 
38840
 
38841
 
38842
 
38843
 
38844
 
38845
 
38846
 
38847
 
38848
 
38849
 
38850
 
38851
 
38852
 
38853
 
38854
 
38855
 
38856
 
38857
 
38858
 
38859
 
38860
 
38861
 
38862
 
38863
 
38864
 
38865
 
38866
 
38867
 
38868
 
38869
 
38870
 
38871
 
38872
 
38873
 
38874
 
38875
 
38876
 
38877
 
38878
 
38879
 
38880
 
38881
 
38882
 
38883
 
38884
 
38885
 
38886
 
38887
 
38888
 
38889
 
38890
 
38891
 
38892
 
38893
 
38894
 
38895
 
38896
 
38897
 
38898
 
38899
 
38900
 
38901
 
38902
 
38903
 
38904
 
38905
 
38906
 
38907
 
38908
 
38909
 
38910
 
38911
 
38912
 
38913
 
38914
 
38915
 
38916
 
38917
 
38918
 
38919
 
38920
 
38921
 
38922
 
38923
 
38924
 
38925
 
38926
 
38927
 
38928
 
38929
 
38930
 
38931
 
38932
 
38933
 
38934
 
38935
 
38936
 
38937
 
38938
 
38939
 
38940
 
38941
 
38942
 
38943
 
38944
 
38945
 
38946
 
38947
 
38948
 
38949
 
38950
 
38951
 
38952
 
38953
 
38954
 
38955
 
38956
 
38957
 
38958
 
38959
 
38960
 
38961
 
38962
 
38963
 
38964
 
38965
 
38966
 
38967
 
38968
 
38969
 
38970
 
38971
 
38972
 
38973
 
38974
 
38975
 
38976
 
38977
 
38978
 
38979
 
38980
 
38981
 
38982
 
38983
 
38984
 
38985
 
38986
 
38987
 
38988
 
38989
 
38990
 
38991
 
38992
 
38993
 
38994
 
38995
 
38996
 
38997
 
38998
 
38999
 
39000
 
39001
 
39002
 
39003
 
39004
 
39005
 
39006
 
39007
 
39008
 
39009
 
39010
 
39011
 
39012
 
39013
 
39014
 
39015
 
39016
 
39017
 
39018
 
39019
 
39020
 
39021
 
39022
 
39023
 
39024
 
39025
 
39026
 
39027
 
39028
 
39029
 
39030
 
39031
 
39032
 
39033
 
39034
 
39035
 
39036
 
39037
 
39038
 
39039
 
39040
 
39041
 
39042
 
39043
 
39044
 
39045
 
39046
 
39047
 
39048
 
39049
 
39050
 
39051
 
39052
 
39053
 
39054
 
39055
 
39056
 
39057
 
39058
 
39059
 
39060
 
39061
 
39062
 
39063
 
39064
 
39065
 
39066
 
39067
 
39068
 
39069
 
39070
 
39071
 
39072
 
39073
 
39074
 
39075
 
39076
 
39077
 
39078
 
39079
 
39080
 
39081
 
39082
 
39083
 
39084
 
39085
 
39086
 
39087
 
39088
 
39089
 
39090
 
39091
 
39092
 
39093
 
39094
 
39095
 
39096
 
39097
 
39098
 
39099
 
39100
 
39101
 
39102
 
39103
 
39104
 
39105
 
39106
 
39107
 
39108
 
39109
 
39110
 
39111
 
39112
 
39113
 
39114
 
39115
 
39116
 
39117
 
39118
 
39119
 
39120
 
39121
 
39122
 
39123
 
39124
 
39125
 
39126
 
39127
 
39128
 
39129
 
39130
 
39131
 
39132
 
39133
 
39134
 
39135
 
39136
 
39137
 
39138
 
39139
 
39140
 
39141
 
39142
 
39143
 
39144
 
39145
 
39146
 
39147
 
39148
 
39149
 
39150
 
39151
 
39152
 
39153
 
39154
 
39155
 
39156
 
39157
 
39158
 
39159
 
39160
 
39161
 
39162
 
39163
 
39164
 
39165
 
39166
 
39167
 
39168
 
39169
 
39170
 
39171
 
39172
 
39173
 
39174
 
39175
 
39176
 
39177
 
39178
 
39179
 
39180
 
39181
 
39182
 
39183
 
39184
 
39185
 
39186
 
39187
 
39188
 
39189
 
39190
 
39191
 
39192
 
39193
 
39194
 
39195
 
39196
 
39197
 
39198
 
39199
 
39200
 
39201
 
39202
 
39203
 
39204
 
39205
 
39206
 
39207
 
39208
 
39209
 
39210
 
39211
 
39212
 
39213
 
39214
 
39215
 
39216
 
39217
 
39218
 
39219
 
39220
 
39221
 
39222
 
39223
 
39224
 
39225
 
39226
 
39227
 
39228
 
39229
 
39230
 
39231
 
39232
 
39233
 
39234
 
39235
 
39236
 
39237
 
39238
 
39239
 
39240
 
39241
 
39242
 
39243
 
39244
 
39245
 
39246
 
39247
 
39248
 
39249
 
39250
 
39251
 
39252
 
39253
 
39254
 
39255
 
39256
 
39257
 
39258
 
39259
 
39260
 
39261
 
39262
 
39263
 
39264
 
39265
 
39266
 
39267
 
39268
 
39269
 
39270
 
39271
 
39272
 
39273
 
39274
 
39275
 
39276
 
39277
 
39278
 
39279
 
39280
 
39281
 
39282
 
39283
 
39284
 
39285
 
39286
 
39287
 
39288
 
39289
 
39290
 
39291
 
39292
 
39293
 
39294
 
39295
 
39296
 
39297
 
39298
 
39299
 
39300
 
39301
 
39302
 
39303
 
39304
 
39305
 
39306
 
39307
 
39308
 
39309
 
39310
 
39311
 
39312
 
39313
 
39314
 
39315
 
39316
 
39317
 
39318
 
39319
 
39320
 
39321
 
39322
 
39323
 
39324
 
39325
 
39326
 
39327
 
39328
 
39329
 
39330
 
39331
 
39332
 
39333
 
39334
 
39335
 
39336
 
39337
 
39338
 
39339
 
39340
 
39341
 
39342
 
39343
 
39344
 
39345
 
39346
 
39347
 
39348
 
39349
 
39350
 
39351
 
39352
 
39353
 
39354
 
39355
 
39356
 
39357
 
39358
 
39359
 
39360
 
39361
 
39362
 
39363
 
39364
 
39365
 
39366
 
39367
 
39368
 
39369
 
39370
 
39371
 
39372
 
39373
 
39374
 
39375
 
39376
 
39377
 
39378
 
39379
 
39380
 
39381
 
39382
 
39383
 
39384
 
39385
 
39386
 
39387
 
39388
 
39389
 
39390
 
39391
 
39392
 
39393
 
39394
 
39395
 
39396
 
39397
 
39398
 
39399
 
39400
 
39401
 
39402
 
39403
 
39404
 
39405
 
39406
 
39407
 
39408
 
39409
 
39410
 
39411
 
39412
 
39413
 
39414
 
39415
 
39416
 
39417
 
39418
 
39419
 
39420
 
39421
 
39422
 
39423
 
39424
 
39425
 
39426
 
39427
 
39428
 
39429
 
39430
 
39431
 
39432
 
39433
 
39434
 
39435
 
39436
 
39437
 
39438
 
39439
 
39440
 
39441
 
39442
 
39443
 
39444
 
39445
 
39446
 
39447
 
39448
 
39449
 
39450
 
39451
 
39452
 
39453
 
39454
 
39455
 
39456
 
39457
 
39458
 
39459
 
39460
 
39461
 
39462
 
39463
 
39464
 
39465
 
39466
 
39467
 
39468
 
39469
 
39470
 
39471
 
39472
 
39473
 
39474
 
39475
 
39476
 
39477
 
39478
 
39479
 
39480
 
39481
 
39482
 
39483
 
39484
 
39485
 
39486
 
39487
 
39488
 
39489
 
39490
 
39491
 
39492
 
39493
 
39494
 
39495
 
39496
 
39497
 
39498
 
39499
 
39500
 
39501
 
39502
 
39503
 
39504
 
39505
 
39506
 
39507
 
39508
 
39509
 
39510
 
39511
 
39512
 
39513
 
39514
 
39515
 
39516
 
39517
 
39518
 
39519
 
39520
 
39521
 
39522
 
39523
 
39524
 
39525
 
39526
 
39527
 
39528
 
39529
 
39530
 
39531
 
39532
 
39533
 
39534
 
39535
 
39536
 
39537
 
39538
 
39539
 
39540
 
39541
 
39542
 
39543
 
39544
 
39545
 
39546
 
39547
 
39548
 
39549
 
39550
 
39551
 
39552
 
39553
 
39554
 
39555
 
39556
 
39557
 
39558
 
39559
 
39560
 
39561
 
39562
 
39563
 
39564
 
39565
 
39566
 
39567
 
39568
 
39569
 
39570
 
39571
 
39572
 
39573
 
39574
 
39575
 
39576
 
39577
 
39578
 
39579
 
39580
 
39581
 
39582
 
39583
 
39584
 
39585
 
39586
 
39587
 
39588
 
39589
 
39590
 
39591
 
39592
 
39593
 
39594
 
39595
 
39596
 
39597
 
39598
 
39599
 
39600
 
39601
 
39602
 
39603
 
39604
 
39605
 
39606
 
39607
 
39608
 
39609
 
39610
 
39611
 
39612
 
39613
 
39614
 
39615
 
39616
 
39617
 
39618
 
39619
 
39620
 
39621
 
39622
 
39623
 
39624
 
39625
 
39626
 
39627
 
39628
 
39629
 
39630
 
39631
 
39632
 
39633
 
39634
 
39635
 
39636
 
39637
 
39638
 
39639
 
39640
 
39641
 
39642
 
39643
 
39644
 
39645
 
39646
 
39647
 
39648
 
39649
 
39650
 
39651
 
39652
 
39653
 
39654
 
39655
 
39656
 
39657
 
39658
 
39659
 
39660
 
39661
 
39662
 
39663
 
39664
 
39665
 
39666
 
39667
 
39668
 
39669
 
39670
 
39671
 
39672
 
39673
 
39674
 
39675
 
39676
 
39677
 
39678
 
39679
 
39680
 
39681
 
39682
 
39683
 
39684
 
39685
 
39686
 
39687
 
39688
 
39689
 
39690
 
39691
 
39692
 
39693
 
39694
 
39695
 
39696
 
39697
 
39698
 
39699
 
39700
 
39701
 
39702
 
39703
 
39704
 
39705
 
39706
 
39707
 
39708
 
39709
 
39710
 
39711
 
39712
 
39713
 
39714
 
39715
 
39716
 
39717
 
39718
 
39719
 
39720
 
39721
 
39722
 
39723
 
39724
 
39725
 
39726
 
39727
 
39728
 
39729
 
39730
 
39731
 
39732
 
39733
 
39734
 
39735
 
39736
 
39737
 
39738
 
39739
 
39740
 
39741
 
39742
 
39743
 
39744
 
39745
 
39746
 
39747
 
39748
 
39749
 
39750
 
39751
 
39752
 
39753
 
39754
 
39755
 
39756
 
39757
 
39758
 
39759
 
39760
 
39761
 
39762
 
39763
 
39764
 
39765
 
39766
 
39767
 
39768
 
39769
 
39770
 
39771
 
39772
 
39773
 
39774
 
39775
 
39776
 
39777
 
39778
 
39779
 
39780
 
39781
 
39782
 
39783
 
39784
 
39785
 
39786
 
39787
 
39788
 
39789
 
39790
 
39791
 
39792
 
39793
 
39794
 
39795
 
39796
 
39797
 
39798
 
39799
 
39800
 
39801
 
39802
 
39803
 
39804
 
39805
 
39806
 
39807
 
39808
 
39809
 
39810
 
39811
 
39812
 
39813
 
39814
 
39815
 
39816
 
39817
 
39818
 
39819
 
39820
 
39821
 
39822
 
39823
 
39824
 
39825
 
39826
 
39827
 
39828
 
39829
 
39830
 
39831
 
39832
 
39833
 
39834
 
39835
 
39836
 
39837
 
39838
 
39839
 
39840
 
39841
 
39842
 
39843
 
39844
 
39845
 
39846
 
39847
 
39848
 
39849
 
39850
 
39851
 
39852
 
39853
 
39854
 
39855
 
39856
 
39857
 
39858
 
39859
 
39860
 
39861
 
39862
 
39863
 
39864
 
39865
 
39866
 
39867
 
39868
 
39869
 
39870
 
39871
 
39872
 
39873
 
39874
 
39875
 
39876
 
39877
 
39878
 
39879
 
39880
 
39881
 
39882
 
39883
 
39884
 
39885
 
39886
 
39887
 
39888
 
39889
 
39890
 
39891
 
39892
 
39893
 
39894
 
39895
 
39896
 
39897
 
39898
 
39899
 
39900
 
39901
 
39902
 
39903
 
39904
 
39905
 
39906
 
39907
 
39908
 
39909
 
39910
 
39911
 
39912
 
39913
 
39914
 
39915
 
39916
 
39917
 
39918
 
39919
 
39920
 
39921
 
39922
 
39923
 
39924
 
39925
 
39926
 
39927
 
39928
 
39929
 
39930
 
39931
 
39932
 
39933
 
39934
 
39935
 
39936
 
39937
 
39938
 
39939
 
39940
 
39941
 
39942
 
39943
 
39944
 
39945
 
39946
 
39947
 
39948
 
39949
 
39950
 
39951
 
39952
 
39953
 
39954
 
39955
 
39956
 
39957
 
39958
 
39959
 
39960
 
39961
 
39962
 
39963
 
39964
 
39965
 
39966
 
39967
 
39968
 
39969
 
39970
 
39971
 
39972
 
39973
 
39974
 
39975
 
39976
 
39977
 
39978
 
39979
 
39980
 
39981
 
39982
 
39983
 
39984
 
39985
 
39986
 
39987
 
39988
 
39989
 
39990
 
39991
 
39992
 
39993
 
39994
 
39995
 
39996
 
39997
 
39998
 
39999
 
40000
 
40001
 
40002
 
40003
 
40004
 
40005
 
40006
 
40007
 
40008
 
40009
 
40010
 
40011
 
40012
 
40013
 
40014
 
40015
 
40016
 
40017
 
40018
 
40019
 
40020
 
40021
 
40022
 
40023
 
40024
 
40025
 
40026
 
40027
 
40028
 
40029
 
40030
 
40031
 
40032
 
40033
 
40034
 
40035
 
40036
 
40037
 
40038
 
40039
 
40040
 
40041
 
40042
 
40043
 
40044
 
40045
 
40046
 
40047
 
40048
 
40049
 
40050
 
40051
 
40052
 
40053
 
40054
 
40055
 
40056
 
40057
 
40058
 
40059
 
40060
 
40061
 
40062
 
40063
 
40064
 
40065
 
40066
 
40067
 
40068
 
40069
 
40070
 
40071
 
40072
 
40073
 
40074
 
40075
 
40076
 
40077
 
40078
 
40079
 
40080
 
40081
 
40082
 
40083
 
40084
 
40085
 
40086
 
40087
 
40088
 
40089
 
40090
 
40091
 
40092
 
40093
 
40094
 
40095
 
40096
 
40097
 
40098
 
40099
 
40100
 
40101
 
40102
 
40103
 
40104
 
40105
 
40106
 
40107
 
40108
 
40109
 
40110
 
40111
 
40112
 
40113
 
40114
 
40115
 
40116
 
40117
 
40118
 
40119
 
40120
 
40121
 
40122
 
40123
 
40124
 
40125
 
40126
 
40127
 
40128
 
40129
 
40130
 
40131
 
40132
 
40133
 
40134
 
40135
 
40136
 
40137
 
40138
 
40139
 
40140
 
40141
 
40142
 
40143
 
40144
 
40145
 
40146
 
40147
 
40148
 
40149
 
40150
 
40151
 
40152
 
40153
 
40154
 
40155
 
40156
 
40157
 
40158
 
40159
 
40160
 
40161
 
40162
 
40163
 
40164
 
40165
 
40166
 
40167
 
40168
 
40169
 
40170
 
40171
 
40172
 
40173
 
40174
 
40175
 
40176
 
40177
 
40178
 
40179
 
40180
 
40181
 
40182
 
40183
 
40184
 
40185
 
40186
 
40187
 
40188
 
40189
 
40190
 
40191
 
40192
 
40193
 
40194
 
40195
 
40196
 
40197
 
40198
 
40199
 
40200
 
40201
 
40202
 
40203
 
40204
 
40205
 
40206
 
40207
 
40208
 
40209
 
40210
 
40211
 
40212
 
40213
 
40214
 
40215
 
40216
 
40217
 
40218
 
40219
 
40220
 
40221
 
40222
 
40223
 
40224
 
40225
 
40226
 
40227
 
40228
 
40229
 
40230
 
40231
 
40232
 
40233
 
40234
 
40235
 
40236
 
40237
 
40238
 
40239
 
40240
 
40241
 
40242
 
40243
 
40244
 
40245
 
40246
 
40247
 
40248
 
40249
 
40250
 
40251
 
40252
 
40253
 
40254
 
40255
 
40256
 
40257
 
40258
 
40259
 
40260
 
40261
 
40262
 
40263
 
40264
 
40265
 
40266
 
40267
 
40268
 
40269
 
40270
 
40271
 
40272
 
40273
 
40274
 
40275
 
40276
 
40277
 
40278
 
40279
 
40280
 
40281
 
40282
 
40283
 
40284
 
40285
 
40286
 
40287
 
40288
 
40289
 
40290
 
40291
 
40292
 
40293
 
40294
 
40295
 
40296
 
40297
 
40298
 
40299
 
40300
 
40301
 
40302
 
40303
 
40304
 
40305
 
40306
 
40307
 
40308
 
40309
 
40310
 
40311
 
40312
 
40313
 
40314
 
40315
 
40316
 
40317
 
40318
 
40319
 
40320
 
40321
 
40322
 
40323
 
40324
 
40325
 
40326
 
40327
 
40328
 
40329
 
40330
 
40331
 
40332
 
40333
 
40334
 
40335
 
40336
 
40337
 
40338
 
40339
 
40340
 
40341
 
40342
 
40343
 
40344
 
40345
 
40346
 
40347
 
40348
 
40349
 
40350
 
40351
 
40352
 
40353
 
40354
 
40355
 
40356
 
40357
 
40358
 
40359
 
40360
 
40361
 
40362
 
40363
 
40364
 
40365
 
40366
 
40367
 
40368
 
40369
 
40370
 
40371
 
40372
 
40373
 
40374
 
40375
 
40376
 
40377
 
40378
 
40379
 
40380
 
40381
 
40382
 
40383
 
40384
 
40385
 
40386
 
40387
 
40388
 
40389
 
40390
 
40391
 
40392
 
40393
 
40394
 
40395
 
40396
 
40397
 
40398
 
40399
 
40400
 
40401
 
40402
 
40403
 
40404
 
40405
 
40406
 
40407
 
40408
 
40409
 
40410
 
40411
 
40412
 
40413
 
40414
 
40415
 
40416
 
40417
 
40418
 
40419
 
40420
 
40421
 
40422
 
40423
 
40424
 
40425
 
40426
 
40427
 
40428
 
40429
 
40430
 
40431
 
40432
 
40433
 
40434
 
40435
 
40436
 
40437
 
40438
 
40439
 
40440
 
40441
 
40442
 
40443
 
40444
 
40445
 
40446
 
40447
 
40448
 
40449
 
40450
 
40451
 
40452
 
40453
 
40454
 
40455
 
40456
 
40457
 
40458
 
40459
 
40460
 
40461
 
40462
 
40463
 
40464
 
40465
 
40466
 
40467
 
40468
 
40469
 
40470
 
40471
 
40472
 
40473
 
40474
 
40475
 
40476
 
40477
 
40478
 
40479
 
40480
 
40481
 
40482
 
40483
 
40484
 
40485
 
40486
 
40487
 
40488
 
40489
 
40490
 
40491
 
40492
 
40493
 
40494
 
40495
 
40496
 
40497
 
40498
 
40499
 
40500
 
40501
 
40502
 
40503
 
40504
 
40505
 
40506
 
40507
 
40508
 
40509
 
40510
 
40511
 
40512
 
40513
 
40514
 
40515
 
40516
 
40517
 
40518
 
40519
 
40520
 
40521
 
40522
 
40523
 
40524
 
40525
 
40526
 
40527
 
40528
 
40529
 
40530
 
40531
 
40532
 
40533
 
40534
 
40535
 
40536
 
40537
 
40538
 
40539
 
40540
 
40541
 
40542
 
40543
 
40544
 
40545
 
40546
 
40547
 
40548
 
40549
 
40550
 
40551
 
40552
 
40553
 
40554
 
40555
 
40556
 
40557
 
40558
 
40559
 
40560
 
40561
 
40562
 
40563
 
40564
 
40565
 
40566
 
40567
 
40568
 
40569
 
40570
 
40571
 
40572
 
40573
 
40574
 
40575
 
40576
 
40577
 
40578
 
40579
 
40580
 
40581
 
40582
 
40583
 
40584
 
40585
 
40586
 
40587
 
40588
 
40589
 
40590
 
40591
 
40592
 
40593
 
40594
 
40595
 
40596
 
40597
 
40598
 
40599
 
40600
 
40601
 
40602
 
40603
 
40604
 
40605
 
40606
 
40607
 
40608
 
40609
 
40610
 
40611
 
40612
 
40613
 
40614
 
40615
 
40616
 
40617
 
40618
 
40619
 
40620
 
40621
 
40622
 
40623
 
40624
 
40625
 
40626
 
40627
 
40628
 
40629
 
40630
 
40631
 
40632
 
40633
 
40634
 
40635
 
40636
 
40637
 
40638
 
40639
 
40640
 
40641
 
40642
 
40643
 
40644
 
40645
 
40646
 
40647
 
40648
 
40649
 
40650
 
40651
 
40652
 
40653
 
40654
 
40655
 
40656
 
40657
 
40658
 
40659
 
40660
 
40661
 
40662
 
40663
 
40664
 
40665
 
40666
 
40667
 
40668
 
40669
 
40670
 
40671
 
40672
 
40673
 
40674
 
40675
 
40676
 
40677
 
40678
 
40679
 
40680
 
40681
 
40682
 
40683
 
40684
 
40685
 
40686
 
40687
 
40688
 
40689
 
40690
 
40691
 
40692
 
40693
 
40694
 
40695
 
40696
 
40697
 
40698
 
40699
 
40700
 
40701
 
40702
 
40703
 
40704
 
40705
 
40706
 
40707
 
40708
 
40709
 
40710
 
40711
 
40712
 
40713
 
40714
 
40715
 
40716
 
40717
 
40718
 
40719
 
40720
 
40721
 
40722
 
40723
 
40724
 
40725
 
40726
 
40727
 
40728
 
40729
 
40730
 
40731
 
40732
 
40733
 
40734
 
40735
 
40736
 
40737
 
40738
 
40739
 
40740
 
40741
 
40742
 
40743
 
40744
 
40745
 
40746
 
40747
 
40748
 
40749
 
40750
 
40751
 
40752
 
40753
 
40754
 
40755
 
40756
 
40757
 
40758
 
40759
 
40760
 
40761
 
40762
 
40763
 
40764
 
40765
 
40766
 
40767
 
40768
 
40769
 
40770
 
40771
 
40772
 
40773
 
40774
 
40775
 
40776
 
40777
 
40778
 
40779
 
40780
 
40781
 
40782
 
40783
 
40784
 
40785
 
40786
 
40787
 
40788
 
40789
 
40790
 
40791
 
40792
 
40793
 
40794
 
40795
 
40796
 
40797
 
40798
 
40799
 
40800
 
40801
 
40802
 
40803
 
40804
 
40805
 
40806
 
40807
 
40808
 
40809
 
40810
 
40811
 
40812
 
40813
 
40814
 
40815
 
40816
 
40817
 
40818
 
40819
 
40820
 
40821
 
40822
 
40823
 
40824
 
40825
 
40826
 
40827
 
40828
 
40829
 
40830
 
40831
 
40832
 
40833
 
40834
 
40835
 
40836
 
40837
 
40838
 
40839
 
40840
 
40841
 
40842
 
40843
 
40844
 
40845
 
40846
 
40847
 
40848
 
40849
 
40850
 
40851
 
40852
 
40853
 
40854
 
40855
 
40856
 
40857
 
40858
 
40859
 
40860
 
40861
 
40862
 
40863
 
40864
 
40865
 
40866
 
40867
 
40868
 
40869
 
40870
 
40871
 
40872
 
40873
 
40874
 
40875
 
40876
 
40877
 
40878
 
40879
 
40880
 
40881
 
40882
 
40883
 
40884
 
40885
 
40886
 
40887
 
40888
 
40889
 
40890
 
40891
 
40892
 
40893
 
40894
 
40895
 
40896
 
40897
 
40898
 
40899
 
40900
 
40901
 
40902
 
40903
 
40904
 
40905
 
40906
 
40907
 
40908
 
40909
 
40910
 
40911
 
40912
 
40913
 
40914
 
40915
 
40916
 
40917
 
40918
 
40919
 
40920
 
40921
 
40922
 
40923
 
40924
 
40925
 
40926
 
40927
 
40928
 
40929
 
40930
 
40931
 
40932
 
40933
 
40934
 
40935
 
40936
 
40937
 
40938
 
40939
 
40940
 
40941
 
40942
 
40943
 
40944
 
40945
 
40946
 
40947
 
40948
 
40949
 
40950
 
40951
 
40952
 
40953
 
40954
 
40955
 
40956
 
40957
 
40958
 
40959
 
40960
 
40961
 
40962
 
40963
 
40964
 
40965
 
40966
 
40967
 
40968
 
40969
 
40970
 
40971
 
40972
 
40973
 
40974
 
40975
 
40976
 
40977
 
40978
 
40979
 
40980
 
40981
 
40982
 
40983
 
40984
 
40985
 
40986
 
40987
 
40988
 
40989
 
40990
 
40991
 
40992
 
40993
 
40994
 
40995
 
40996
 
40997
 
40998
 
40999
 
41000
 
41001
 
41002
 
41003
 
41004
 
41005
 
41006
 
41007
 
41008
 
41009
 
41010
 
41011
 
41012
 
41013
 
41014
 
41015
 
41016
 
41017
 
41018
 
41019
 
41020
 
41021
 
41022
 
41023
 
41024
 
41025
 
41026
 
41027
 
41028
 
41029
 
41030
 
41031
 
41032
 
41033
 
41034
 
41035
 
41036
 
41037
 
41038
 
41039
 
41040
 
41041
 
41042
 
41043
 
41044
 
41045
 
41046
 
41047
 
41048
 
41049
 
41050
 
41051
 
41052
 
41053
 
41054
 
41055
 
41056
 
41057
 
41058
 
41059
 
41060
 
41061
 
41062
 
41063
 
41064
 
41065
 
41066
 
41067
 
41068
 
41069
 
41070
 
41071
 
41072
 
41073
 
41074
 
41075
 
41076
 
41077
 
41078
 
41079
 
41080
 
41081
 
41082
 
41083
 
41084
 
41085
 
41086
 
41087
 
41088
 
41089
 
41090
 
41091
 
41092
 
41093
 
41094
 
41095
 
41096
 
41097
 
41098
 
41099
 
41100
 
41101
 
41102
 
41103
 
41104
 
41105
 
41106
 
41107
 
41108
 
41109
 
41110
 
41111
 
41112
 
41113
 
41114
 
41115
 
41116
 
41117
 
41118
 
41119
 
41120
 
41121
 
41122
 
41123
 
41124
 
41125
 
41126
 
41127
 
41128
 
41129
 
41130
 
41131
 
41132
 
41133
 
41134
 
41135
 
41136
 
41137
 
41138
 
41139
 
41140
 
41141
 
41142
 
41143
 
41144
 
41145
 
41146
 
41147
 
41148
 
41149
 
41150
 
41151
 
41152
 
41153
 
41154
 
41155
 
41156
 
41157
 
41158
 
41159
 
41160
 
41161
 
41162
 
41163
 
41164
 
41165
 
41166
 
41167
 
41168
 
41169
 
41170
 
41171
 
41172
 
41173
 
41174
 
41175
 
41176
 
41177
 
41178
 
41179
 
41180
 
41181
 
41182
 
41183
 
41184
 
41185
 
41186
 
41187
 
41188
 
41189
 
41190
 
41191
 
41192
 
41193
 
41194
 
41195
 
41196
 
41197
 
41198
 
41199
 
41200
 
41201
 
41202
 
41203
 
41204
 
41205
 
41206
 
41207
 
41208
 
41209
 
41210
 
41211
 
41212
 
41213
 
41214
 
41215
 
41216
 
41217
 
41218
 
41219
 
41220
 
41221
 
41222
 
41223
 
41224
 
41225
 
41226
 
41227
 
41228
 
41229
 
41230
 
41231
 
41232
 
41233
 
41234
 
41235
 
41236
 
41237
 
41238
 
41239
 
41240
 
41241
 
41242
 
41243
 
41244
 
41245
 
41246
 
41247
 
41248
 
41249
 
41250
 
41251
 
41252
 
41253
 
41254
 
41255
 
41256
 
41257
 
41258
 
41259
 
41260
 
41261
 
41262
 
41263
 
41264
 
41265
 
41266
 
41267
 
41268
 
41269
 
41270
 
41271
 
41272
 
41273
 
41274
 
41275
 
41276
 
41277
 
41278
 
41279
 
41280
 
41281
 
41282
 
41283
 
41284
 
41285
 
41286
 
41287
 
41288
 
41289
 
41290
 
41291
 
41292
 
41293
 
41294
 
41295
 
41296
 
41297
 
41298
 
41299
 
41300
 
41301
 
41302
 
41303
 
41304
 
41305
 
41306
 
41307
 
41308
 
41309
 
41310
 
41311
 
41312
 
41313
 
41314
 
41315
 
41316
 
41317
 
41318
 
41319
 
41320
 
41321
 
41322
 
41323
 
41324
 
41325
 
41326
 
41327
 
41328
 
41329
 
41330
 
41331
 
41332
 
41333
 
41334
 
41335
 
41336
 
41337
 
41338
 
41339
 
41340
 
41341
 
41342
 
41343
 
41344
 
41345
 
41346
 
41347
 
41348
 
41349
 
41350
 
41351
 
41352
 
41353
 
41354
 
41355
 
41356
 
41357
 
41358
 
41359
 
41360
 
41361
 
41362
 
41363
 
41364
 
41365
 
41366
 
41367
 
41368
 
41369
 
41370
 
41371
 
41372
 
41373
 
41374
 
41375
 
41376
 
41377
 
41378
 
41379
 
41380
 
41381
 
41382
 
41383
 
41384
 
41385
 
41386
 
41387
 
41388
 
41389
 
41390
 
41391
 
41392
 
41393
 
41394
 
41395
 
41396
 
41397
 
41398
 
41399
 
41400
 
41401
 
41402
 
41403
 
41404
 
41405
 
41406
 
41407
 
41408
 
41409
 
41410
 
41411
 
41412
 
41413
 
41414
 
41415
 
41416
 
41417
 
41418
 
41419
 
41420
 
41421
 
41422
 
41423
 
41424
 
41425
 
41426
 
41427
 
41428
 
41429
 
41430
 
41431
 
41432
 
41433
 
41434
 
41435
 
41436
 
41437
 
41438
 
41439
 
41440
 
41441
 
41442
 
41443
 
41444
 
41445
 
41446
 
41447
 
41448
 
41449
 
41450
 
41451
 
41452
 
41453
 
41454
 
41455
 
41456
 
41457
 
41458
 
41459
 
41460
 
41461
 
41462
 
41463
 
41464
 
41465
 
41466
 
41467
 
41468
 
41469
 
41470
 
41471
 
41472
 
41473
 
41474
 
41475
 
41476
 
41477
 
41478
 
41479
 
41480
 
41481
 
41482
 
41483
 
41484
 
41485
 
41486
 
41487
 
41488
 
41489
 
41490
 
41491
 
41492
 
41493
 
41494
 
41495
 
41496
 
41497
 
41498
 
41499
 
41500
 
41501
 
41502
 
41503
 
41504
 
41505
 
41506
 
41507
 
41508
 
41509
 
41510
 
41511
 
41512
 
41513
 
41514
 
41515
 
41516
 
41517
 
41518
 
41519
 
41520
 
41521
 
41522
 
41523
 
41524
 
41525
 
41526
 
41527
 
41528
 
41529
 
41530
 
41531
 
41532
 
41533
 
41534
 
41535
 
41536
 
41537
 
41538
 
41539
 
41540
 
41541
 
41542
 
41543
 
41544
 
41545
 
41546
 
41547
 
41548
 
41549
 
41550
 
41551
 
41552
 
41553
 
41554
 
41555
 
41556
 
41557
 
41558
 
41559
 
41560
 
41561
 
41562
 
41563
 
41564
 
41565
 
41566
 
41567
 
41568
 
41569
 
41570
 
41571
 
41572
 
41573
 
41574
 
41575
 
41576
 
41577
 
41578
 
41579
 
41580
 
41581
 
41582
 
41583
 
41584
 
41585
 
41586
 
41587
 
41588
 
41589
 
41590
 
41591
 
41592
 
41593
 
41594
 
41595
 
41596
 
41597
 
41598
 
41599
 
41600
 
41601
 
41602
 
41603
 
41604
 
41605
 
41606
 
41607
 
41608
 
41609
 
41610
 
41611
 
41612
 
41613
 
41614
 
41615
 
41616
 
41617
 
41618
 
41619
 
41620
 
41621
 
41622
 
41623
 
41624
 
41625
 
41626
 
41627
 
41628
 
41629
 
41630
 
41631
 
41632
 
41633
 
41634
 
41635
 
41636
 
41637
 
41638
 
41639
 
41640
 
41641
 
41642
 
41643
 
41644
 
41645
 
41646
 
41647
 
41648
 
41649
 
41650
 
41651
 
41652
 
41653
 
41654
 
41655
 
41656
 
41657
 
41658
 
41659
 
41660
 
41661
 
41662
 
41663
 
41664
 
41665
 
41666
 
41667
 
41668
 
41669
 
41670
 
41671
 
41672
 
41673
 
41674
 
41675
 
41676
 
41677
 
41678
 
41679
 
41680
 
41681
 
41682
 
41683
 
41684
 
41685
 
41686
 
41687
 
41688
 
41689
 
41690
 
41691
 
41692
 
41693
 
41694
 
41695
 
41696
 
41697
 
41698
 
41699
 
41700
 
41701
 
41702
 
41703
 
41704
 
41705
 
41706
 
41707
 
41708
 
41709
 
41710
 
41711
 
41712
 
41713
 
41714
 
41715
 
41716
 
41717
 
41718
 
41719
 
41720
 
41721
 
41722
 
41723
 
41724
 
41725
 
41726
 
41727
 
41728
 
41729
 
41730
 
41731
 
41732
 
41733
 
41734
 
41735
 
41736
 
41737
 
41738
 
41739
 
41740
 
41741
 
41742
 
41743
 
41744
 
41745
 
41746
 
41747
 
41748
 
41749
 
41750
 
41751
 
41752
 
41753
 
41754
 
41755
 
41756
 
41757
 
41758
 
41759
 
41760
 
41761
 
41762
 
41763
 
41764
 
41765
 
41766
 
41767
 
41768
 
41769
 
41770
 
41771
 
41772
 
41773
 
41774
 
41775
 
41776
 
41777
 
41778
 
41779
 
41780
 
41781
 
41782
 
41783
 
41784
 
41785
 
41786
 
41787
 
41788
 
41789
 
41790
 
41791
 
41792
 
41793
 
41794
 
41795
 
41796
 
41797
 
41798
 
41799
 
41800
 
41801
 
41802
 
41803
 
41804
 
41805
 
41806
 
41807
 
41808
 
41809
 
41810
 
41811
 
41812
 
41813
 
41814
 
41815
 
41816
 
41817
 
41818
 
41819
 
41820
 
41821
 
41822
 
41823
 
41824
 
41825
 
41826
 
41827
 
41828
 
41829
 
41830
 
41831
 
41832
 
41833
 
41834
 
41835
 
41836
 
41837
 
41838
 
41839
 
41840
 
41841
 
41842
 
41843
 
41844
 
41845
 
41846
 
41847
 
41848
 
41849
 
41850
 
41851
 
41852
 
41853
 
41854
 
41855
 
41856
 
41857
 
41858
 
41859
 
41860
 
41861
 
41862
 
41863
 
41864
 
41865
 
41866
 
41867
 
41868
 
41869
 
41870
 
41871
 
41872
 
41873
 
41874
 
41875
 
41876
 
41877
 
41878
 
41879
 
41880
 
41881
 
41882
 
41883
 
41884
 
41885
 
41886
 
41887
 
41888
 
41889
 
41890
 
41891
 
41892
 
41893
 
41894
 
41895
 
41896
 
41897
 
41898
 
41899
 
41900
 
41901
 
41902
 
41903
 
41904
 
41905
 
41906
 
41907
 
41908
 
41909
 
41910
 
41911
 
41912
 
41913
 
41914
 
41915
 
41916
 
41917
 
41918
 
41919
 
41920
 
41921
 
41922
 
41923
 
41924
 
41925
 
41926
 
41927
 
41928
 
41929
 
41930
 
41931
 
41932
 
41933
 
41934
 
41935
 
41936
 
41937
 
41938
 
41939
 
41940
 
41941
 
41942
 
41943
 
41944
 
41945
 
41946
 
41947
 
41948
 
41949
 
41950
 
41951
 
41952
 
41953
 
41954
 
41955
 
41956
 
41957
 
41958
 
41959
 
41960
 
41961
 
41962
 
41963
 
41964
 
41965
 
41966
 
41967
 
41968
 
41969
 
41970
 
41971
 
41972
 
41973
 
41974
 
41975
 
41976
 
41977
 
41978
 
41979
 
41980
 
41981
 
41982
 
41983
 
41984
 
41985
 
41986
 
41987
 
41988
 
41989
 
41990
 
41991
 
41992
 
41993
 
41994
 
41995
 
41996
 
41997
 
41998
 
41999
 
42000
 
42001
 
42002
 
42003
 
42004
 
42005
 
42006
 
42007
 
42008
 
42009
 
42010
 
42011
 
42012
 
42013
 
42014
 
42015
 
42016
 
42017
 
42018
 
42019
 
42020
 
42021
 
42022
 
42023
 
42024
 
42025
 
42026
 
42027
 
42028
 
42029
 
42030
 
42031
 
42032
 
42033
 
42034
 
42035
 
42036
 
42037
 
42038
 
42039
 
42040
 
42041
 
42042
 
42043
 
42044
 
42045
 
42046
 
42047
 
42048
 
42049
 
42050
 
42051
 
42052
 
42053
 
42054
 
42055
 
42056
 
42057
 
42058
 
42059
 
42060
 
42061
 
42062
 
42063
 
42064
 
42065
 
42066
 
42067
 
42068
 
42069
 
42070
 
42071
 
42072
 
42073
 
42074
 
42075
 
42076
 
42077
 
42078
 
42079
 
42080
 
42081
 
42082
 
42083
 
42084
 
42085
 
42086
 
42087
 
42088
 
42089
 
42090
 
42091
 
42092
 
42093
 
42094
 
42095
 
42096
 
42097
 
42098
 
42099
 
42100
 
42101
 
42102
 
42103
 
42104
 
42105
 
42106
 
42107
 
42108
 
42109
 
42110
 
42111
 
42112
 
42113
 
42114
 
42115
 
42116
 
42117
 
42118
 
42119
 
42120
 
42121
 
42122
 
42123
 
42124
 
42125
 
42126
 
42127
 
42128
 
42129
 
42130
 
42131
 
42132
 
42133
 
42134
 
42135
 
42136
 
42137
 
42138
 
42139
 
42140
 
42141
 
42142
 
42143
 
42144
 
42145
 
42146
 
42147
 
42148
 
42149
 
42150
 
42151
 
42152
 
42153
 
42154
 
42155
 
42156
 
42157
 
42158
 
42159
 
42160
 
42161
 
42162
 
42163
 
42164
 
42165
 
42166
 
42167
 
42168
 
42169
 
42170
 
42171
 
42172
 
42173
 
42174
 
42175
 
42176
 
42177
 
42178
 
42179
 
42180
 
42181
 
42182
 
42183
 
42184
 
42185
 
42186
 
42187
 
42188
 
42189
 
42190
 
42191
 
42192
 
42193
 
42194
 
42195
 
42196
 
42197
 
42198
 
42199
 
42200
 
42201
 
42202
 
42203
 
42204
 
42205
 
42206
 
42207
 
42208
 
42209
 
42210
 
42211
 
42212
 
42213
 
42214
 
42215
 
42216
 
42217
 
42218
 
42219
 
42220
 
42221
 
42222
 
42223
 
42224
 
42225
 
42226
 
42227
 
42228
 
42229
 
42230
 
42231
 
42232
 
42233
 
42234
 
42235
 
42236
 
42237
 
42238
 
42239
 
42240
 
42241
 
42242
 
42243
 
42244
 
42245
 
42246
 
42247
 
42248
 
42249
 
42250
 
42251
 
42252
 
42253
 
42254
 
42255
 
42256
 
42257
 
42258
 
42259
 
42260
 
42261
 
42262
 
42263
 
42264
 
42265
 
42266
 
42267
 
42268
 
42269
 
42270
 
42271
 
42272
 
42273
 
42274
 
42275
 
42276
 
42277
 
42278
 
42279
 
42280
 
42281
 
42282
 
42283
 
42284
 
42285
 
42286
 
42287
 
42288
 
42289
 
42290
 
42291
 
42292
 
42293
 
42294
 
42295
 
42296
 
42297
 
42298
 
42299
 
42300
 
42301
 
42302
 
42303
 
42304
 
42305
 
42306
 
42307
 
42308
 
42309
 
42310
 
42311
 
42312
 
42313
 
42314
 
42315
 
42316
 
42317
 
42318
 
42319
 
42320
 
42321
 
42322
 
42323
 
42324
 
42325
 
42326
 
42327
 
42328
 
42329
 
42330
 
42331
 
42332
 
42333
 
42334
 
42335
 
42336
 
42337
 
42338
 
42339
 
42340
 
42341
 
42342
 
42343
 
42344
 
42345
 
42346
 
42347
 
42348
 
42349
 
42350
 
42351
 
42352
 
42353
 
42354
 
42355
 
42356
 
42357
 
42358
 
42359
 
42360
 
42361
 
42362
 
42363
 
42364
 
42365
 
42366
 
42367
 
42368
 
42369
 
42370
 
42371
 
42372
 
42373
 
42374
 
42375
 
42376
 
42377
 
42378
 
42379
 
42380
 
42381
 
42382
 
42383
 
42384
 
42385
 
42386
 
42387
 
42388
 
42389
 
42390
 
42391
 
42392
 
42393
 
42394
 
42395
 
42396
 
42397
 
42398
 
42399
 
42400
 
42401
 
42402
 
42403
 
42404
 
42405
 
42406
 
42407
 
42408
 
42409
 
42410
 
42411
 
42412
 
42413
 
42414
 
42415
 
42416
 
42417
 
42418
 
42419
 
42420
 
42421
 
42422
 
42423
 
42424
 
42425
 
42426
 
42427
 
42428
 
42429
 
42430
 
42431
 
42432
 
42433
 
42434
 
42435
 
42436
 
42437
 
42438
 
42439
 
42440
 
42441
 
42442
 
42443
 
42444
 
42445
 
42446
 
42447
 
42448
 
42449
 
42450
 
42451
 
42452
 
42453
 
42454
 
42455
 
42456
 
42457
 
42458
 
42459
 
42460
 
42461
 
42462
 
42463
 
42464
 
42465
 
42466
 
42467
 
42468
 
42469
 
42470
 
42471
 
42472
 
42473
 
42474
 
42475
 
42476
 
42477
 
42478
 
42479
 
42480
 
42481
 
42482
 
42483
 
42484
 
42485
 
42486
 
42487
 
42488
 
42489
 
42490
 
42491
 
42492
 
42493
 
42494
 
42495
 
42496
 
42497
 
42498
 
42499
 
42500
 
42501
 
42502
 
42503
 
42504
 
42505
 
42506
 
42507
 
42508
 
42509
 
42510
 
42511
 
42512
 
42513
 
42514
 
42515
 
42516
 
42517
 
42518
 
42519
 
42520
 
42521
 
42522
 
42523
 
42524
 
42525
 
42526
 
42527
 
42528
 
42529
 
42530
 
42531
 
42532
 
42533
 
42534
 
42535
 
42536
 
42537
 
42538
 
42539
 
42540
 
42541
 
42542
 
42543
 
42544
 
42545
 
42546
 
42547
 
42548
 
42549
 
42550
 
42551
 
42552
 
42553
 
42554
 
42555
 
42556
 
42557
 
42558
 
42559
 
42560
 
42561
 
42562
 
42563
 
42564
 
42565
 
42566
 
42567
 
42568
 
42569
 
42570
 
42571
 
42572
 
42573
 
42574
 
42575
 
42576
 
42577
 
42578
 
42579
 
42580
 
42581
 
42582
 
42583
 
42584
 
42585
 
42586
 
42587
 
42588
 
42589
 
42590
 
42591
 
42592
 
42593
 
42594
 
42595
 
42596
 
42597
 
42598
 
42599
 
42600
 
42601
 
42602
 
42603
 
42604
 
42605
 
42606
 
42607
 
42608
 
42609
 
42610
 
42611
 
42612
 
42613
 
42614
 
42615
 
42616
 
42617
 
42618
 
42619
 
42620
 
42621
 
42622
 
42623
 
42624
 
42625
 
42626
 
42627
 
42628
 
42629
 
42630
 
42631
 
42632
 
42633
 
42634
 
42635
 
42636
 
42637
 
42638
 
42639
 
42640
 
42641
 
42642
 
42643
 
42644
 
42645
 
42646
 
42647
 
42648
 
42649
 
42650
 
42651
 
42652
 
42653
 
42654
 
42655
 
42656
 
42657
 
42658
 
42659
 
42660
 
42661
 
42662
 
42663
 
42664
 
42665
 
42666
 
42667
 
42668
 
42669
 
42670
 
42671
 
42672
 
42673
 
42674
 
42675
 
42676
 
42677
 
42678
 
42679
 
42680
 
42681
 
42682
 
42683
 
42684
 
42685
 
42686
 
42687
 
42688
 
42689
 
42690
 
42691
 
42692
 
42693
 
42694
 
42695
 
42696
 
42697
 
42698
 
42699
 
42700
 
42701
 
42702
 
42703
 
42704
 
42705
 
42706
 
42707
 
42708
 
42709
 
42710
 
42711
 
42712
 
42713
 
42714
 
42715
 
42716
 
42717
 
42718
 
42719
 
42720
 
42721
 
42722
 
42723
 
42724
 
42725
 
42726
 
42727
 
42728
 
42729
 
42730
 
42731
 
42732
 
42733
 
42734
 
42735
 
42736
 
42737
 
42738
 
42739
 
42740
 
42741
 
42742
 
42743
 
42744
 
42745
 
42746
 
42747
 
42748
 
42749
 
42750
 
42751
 
42752
 
42753
 
42754
 
42755
 
42756
 
42757
 
42758
 
42759
 
42760
 
42761
 
42762
 
42763
 
42764
 
42765
 
42766
 
42767
 
42768
 
42769
 
42770
 
42771
 
42772
 
42773
 
42774
 
42775
 
42776
 
42777
 
42778
 
42779
 
42780
 
42781
 
42782
 
42783
 
42784
 
42785
 
42786
 
42787
 
42788
 
42789
 
42790
 
42791
 
42792
 
42793
 
42794
 
42795
 
42796
 
42797
 
42798
 
42799
 
42800
 
42801
 
42802
 
42803
 
42804
 
42805
 
42806
 
42807
 
42808
 
42809
 
42810
 
42811
 
42812
 
42813
 
42814
 
42815
 
42816
 
42817
 
42818
 
42819
 
42820
 
42821
 
42822
 
42823
 
42824
 
42825
 
42826
 
42827
 
42828
 
42829
 
42830
 
42831
 
42832
 
42833
 
42834
 
42835
 
42836
 
42837
 
42838
 
42839
 
42840
 
42841
 
42842
 
42843
 
42844
 
42845
 
42846
 
42847
 
42848
 
42849
 
42850
 
42851
 
42852
 
42853
 
42854
 
42855
 
42856
 
42857
 
42858
 
42859
 
42860
 
42861
 
42862
 
42863
 
42864
 
42865
 
42866
 
42867
 
42868
 
42869
 
42870
 
42871
 
42872
 
42873
 
42874
 
42875
 
42876
 
42877
 
42878
 
42879
 
42880
 
42881
 
42882
 
42883
 
42884
 
42885
 
42886
 
42887
 
42888
 
42889
 
42890
 
42891
 
42892
 
42893
 
42894
 
42895
 
42896
 
42897
 
42898
 
42899
 
42900
 
42901
 
42902
 
42903
 
42904
 
42905
 
42906
 
42907
 
42908
 
42909
 
42910
 
42911
 
42912
 
42913
 
42914
 
42915
 
42916
 
42917
 
42918
 
42919
 
42920
 
42921
 
42922
 
42923
 
42924
 
42925
 
42926
 
42927
 
42928
 
42929
 
42930
 
42931
 
42932
 
42933
 
42934
 
42935
 
42936
 
42937
 
42938
 
42939
 
42940
 
42941
 
42942
 
42943
 
42944
 
42945
 
42946
 
42947
 
42948
 
42949
 
42950
 
42951
 
42952
 
42953
 
42954
 
42955
 
42956
 
42957
 
42958
 
42959
 
42960
 
42961
 
42962
 
42963
 
42964
 
42965
 
42966
 
42967
 
42968
 
42969
 
42970
 
42971
 
42972
 
42973
 
42974
 
42975
 
42976
 
42977
 
42978
 
42979
 
42980
 
42981
 
42982
 
42983
 
42984
 
42985
 
42986
 
42987
 
42988
 
42989
 
42990
 
42991
 
42992
 
42993
 
42994
 
42995
 
42996
 
42997
 
42998
 
42999
 
43000
 
43001
 
43002
 
43003
 
43004
 
43005
 
43006
 
43007
 
43008
 
43009
 
43010
 
43011
 
43012
 
43013
 
43014
 
43015
 
43016
 
43017
 
43018
 
43019
 
43020
 
43021
 
43022
 
43023
 
43024
 
43025
 
43026
 
43027
 
43028
 
43029
 
43030
 
43031
 
43032
 
43033
 
43034
 
43035
 
43036
 
43037
 
43038
 
43039
 
43040
 
43041
 
43042
 
43043
 
43044
 
43045
 
43046
 
43047
 
43048
 
43049
 
43050
 
43051
 
43052
 
43053
 
43054
 
43055
 
43056
 
43057
 
43058
 
43059
 
43060
 
43061
 
43062
 
43063
 
43064
 
43065
 
43066
 
43067
 
43068
 
43069
 
43070
 
43071
 
43072
 
43073
 
43074
 
43075
 
43076
 
43077
 
43078
 
43079
 
43080
 
43081
 
43082
 
43083
 
43084
 
43085
 
43086
 
43087
 
43088
 
43089
 
43090
 
43091
 
43092
 
43093
 
43094
 
43095
 
43096
 
43097
 
43098
 
43099
 
43100
 
43101
 
43102
 
43103
 
43104
 
43105
 
43106
 
43107
 
43108
 
43109
 
43110
 
43111
 
43112
 
43113
 
43114
 
43115
 
43116
 
43117
 
43118
 
43119
 
43120
 
43121
 
43122
 
43123
 
43124
 
43125
 
43126
 
43127
 
43128
 
43129
 
43130
 
43131
 
43132
 
43133
 
43134
 
43135
 
43136
 
43137
 
43138
 
43139
 
43140
 
43141
 
43142
 
43143
 
43144
 
43145
 
43146
 
43147
 
43148
 
43149
 
43150
 
43151
 
43152
 
43153
 
43154
 
43155
 
43156
 
43157
 
43158
 
43159
 
43160
 
43161
 
43162
 
43163
 
43164
 
43165
 
43166
 
43167
 
43168
 
43169
 
43170
 
43171
 
43172
 
43173
 
43174
 
43175
 
43176
 
43177
 
43178
 
43179
 
43180
 
43181
 
43182
 
43183
 
43184
 
43185
 
43186
 
43187
 
43188
 
43189
 
43190
 
43191
 
43192
 
43193
 
43194
 
43195
 
43196
 
43197
 
43198
 
43199
 
43200
 
43201
 
43202
 
43203
 
43204
 
43205
 
43206
 
43207
 
43208
 
43209
 
43210
 
43211
 
43212
 
43213
 
43214
 
43215
 
43216
 
43217
 
43218
 
43219
 
43220
 
43221
 
43222
 
43223
 
43224
 
43225
 
43226
 
43227
 
43228
 
43229
 
43230
 
43231
 
43232
 
43233
 
43234
 
43235
 
43236
 
43237
 
43238
 
43239
 
43240
 
43241
 
43242
 
43243
 
43244
 
43245
 
43246
 
43247
 
43248
 
43249
 
43250
 
43251
 
43252
 
43253
 
43254
 
43255
 
43256
 
43257
 
43258
 
43259
 
43260
 
43261
 
43262
 
43263
 
43264
 
43265
 
43266
 
43267
 
43268
 
43269
 
43270
 
43271
 
43272
 
43273
 
43274
 
43275
 
43276
 
43277
 
43278
 
43279
 
43280
 
43281
 
43282
 
43283
 
43284
 
43285
 
43286
 
43287
 
43288
 
43289
 
43290
 
43291
 
43292
 
43293
 
43294
 
43295
 
43296
 
43297
 
43298
 
43299
 
43300
 
43301
 
43302
 
43303
 
43304
 
43305
 
43306
 
43307
 
43308
 
43309
 
43310
 
43311
 
43312
 
43313
 
43314
 
43315
 
43316
 
43317
 
43318
 
43319
 
43320
 
43321
 
43322
 
43323
 
43324
 
43325
 
43326
 
43327
 
43328
 
43329
 
43330
 
43331
 
43332
 
43333
 
43334
 
43335
 
43336
 
43337
 
43338
 
43339
 
43340
 
43341
 
43342
 
43343
 
43344
 
43345
 
43346
 
43347
 
43348
 
43349
 
43350
 
43351
 
43352
 
43353
 
43354
 
43355
 
43356
 
43357
 
43358
 
43359
 
43360
 
43361
 
43362
 
43363
 
43364
 
43365
 
43366
 
43367
 
43368
 
43369
 
43370
 
43371
 
43372
 
43373
 
43374
 
43375
 
43376
 
43377
 
43378
 
43379
 
43380
 
43381
 
43382
 
43383
 
43384
 
43385
 
43386
 
43387
 
43388
 
43389
 
43390
 
43391
 
43392
 
43393
 
43394
 
43395
 
43396
 
43397
 
43398
 
43399
 
43400
 
43401
 
43402
 
43403
 
43404
 
43405
 
43406
 
43407
 
43408
 
43409
 
43410
 
43411
 
43412
 
43413
 
43414
 
43415
 
43416
 
43417
 
43418
 
43419
 
43420
 
43421
 
43422
 
43423
 
43424
 
43425
 
43426
 
43427
 
43428
 
43429
 
43430
 
43431
 
43432
 
43433
 
43434
 
43435
 
43436
 
43437
 
43438
 
43439
 
43440
 
43441
 
43442
 
43443
 
43444
 
43445
 
43446
 
43447
 
43448
 
43449
 
43450
 
43451
 
43452
 
43453
 
43454
 
43455
 
43456
 
43457
 
43458
 
43459
 
43460
 
43461
 
43462
 
43463
 
43464
 
43465
 
43466
 
43467
 
43468
 
43469
 
43470
 
43471
 
43472
 
43473
 
43474
 
43475
 
43476
 
43477
 
43478
 
43479
 
43480
 
43481
 
43482
 
43483
 
43484
 
43485
 
43486
 
43487
 
43488
 
43489
 
43490
 
43491
 
43492
 
43493
 
43494
 
43495
 
43496
 
43497
 
43498
 
43499
 
43500
 
43501
 
43502
 
43503
 
43504
 
43505
 
43506
 
43507
 
43508
 
43509
 
43510
 
43511
 
43512
 
43513
 
43514
 
43515
 
43516
 
43517
 
43518
 
43519
 
43520
 
43521
 
43522
 
43523
 
43524
 
43525
 
43526
 
43527
 
43528
 
43529
 
43530
 
43531
 
43532
 
43533
 
43534
 
43535
 
43536
 
43537
 
43538
 
43539
 
43540
 
43541
 
43542
 
43543
 
43544
 
43545
 
43546
 
43547
 
43548
 
43549
 
43550
 
43551
 
43552
 
43553
 
43554
 
43555
 
43556
 
43557
 
43558
 
43559
 
43560
 
43561
 
43562
 
43563
 
43564
 
43565
 
43566
 
43567
 
43568
 
43569
 
43570
 
43571
 
43572
 
43573
 
43574
 
43575
 
43576
 
43577
 
43578
 
43579
 
43580
 
43581
 
43582
 
43583
 
43584
 
43585
 
43586
 
43587
 
43588
 
43589
 
43590
 
43591
 
43592
 
43593
 
43594
 
43595
 
43596
 
43597
 
43598
 
43599
 
43600
 
43601
 
43602
 
43603
 
43604
 
43605
 
43606
 
43607
 
43608
 
43609
 
43610
 
43611
 
43612
 
43613
 
43614
 
43615
 
43616
 
43617
 
43618
 
43619
 
43620
 
43621
 
43622
 
43623
 
43624
 
43625
 
43626
 
43627
 
43628
 
43629
 
43630
 
43631
 
43632
 
43633
 
43634
 
43635
 
43636
 
43637
 
43638
 
43639
 
43640
 
43641
 
43642
 
43643
 
43644
 
43645
 
43646
 
43647
 
43648
 
43649
 
43650
 
43651
 
43652
 
43653
 
43654
 
43655
 
43656
 
43657
 
43658
 
43659
 
43660
 
43661
 
43662
 
43663
 
43664
 
43665
 
43666
 
43667
 
43668
 
43669
 
43670
 
43671
 
43672
 
43673
 
43674
 
43675
 
43676
 
43677
 
43678
 
43679
 
43680
 
43681
 
43682
 
43683
 
43684
 
43685
 
43686
 
43687
 
43688
 
43689
 
43690
 
43691
 
43692
 
43693
 
43694
 
43695
 
43696
 
43697
 
43698
 
43699
 
43700
 
43701
 
43702
 
43703
 
43704
 
43705
 
43706
 
43707
 
43708
 
43709
 
43710
 
43711
 
43712
 
43713
 
43714
 
43715
 
43716
 
43717
 
43718
 
43719
 
43720
 
43721
 
43722
 
43723
 
43724
 
43725
 
43726
 
43727
 
43728
 
43729
 
43730
 
43731
 
43732
 
43733
 
43734
 
43735
 
43736
 
43737
 
43738
 
43739
 
43740
 
43741
 
43742
 
43743
 
43744
 
43745
 
43746
 
43747
 
43748
 
43749
 
43750
 
43751
 
43752
 
43753
 
43754
 
43755
 
43756
 
43757
 
43758
 
43759
 
43760
 
43761
 
43762
 
43763
 
43764
 
43765
 
43766
 
43767
 
43768
 
43769
 
43770
 
43771
 
43772
 
43773
 
43774
 
43775
 
43776
 
43777
 
43778
 
43779
 
43780
 
43781
 
43782
 
43783
 
43784
 
43785
 
43786
 
43787
 
43788
 
43789
 
43790
 
43791
 
43792
 
43793
 
43794
 
43795
 
43796
 
43797
 
43798
 
43799
 
43800
 
43801
 
43802
 
43803
 
43804
 
43805
 
43806
 
43807
 
43808
 
43809
 
43810
 
43811
 
43812
 
43813
 
43814
 
43815
 
43816
 
43817
 
43818
 
43819
 
43820
 
43821
 
43822
 
43823
 
43824
 
43825
 
43826
 
43827
 
43828
 
43829
 
43830
 
43831
 
43832
 
43833
 
43834
 
43835
 
43836
 
43837
 
43838
 
43839
 
43840
 
43841
 
43842
 
43843
 
43844
 
43845
 
43846
 
43847
 
43848
 
43849
 
43850
 
43851
 
43852
 
43853
 
43854
 
43855
 
43856
 
43857
 
43858
 
43859
 
43860
 
43861
 
43862
 
43863
 
43864
 
43865
 
43866
 
43867
 
43868
 
43869
 
43870
 
43871
 
43872
 
43873
 
43874
 
43875
 
43876
 
43877
 
43878
 
43879
 
43880
 
43881
 
43882
 
43883
 
43884
 
43885
 
43886
 
43887
 
43888
 
43889
 
43890
 
43891
 
43892
 
43893
 
43894
 
43895
 
43896
 
43897
 
43898
 
43899
 
43900
 
43901
 
43902
 
43903
 
43904
 
43905
 
43906
 
43907
 
43908
 
43909
 
43910
 
43911
 
43912
 
43913
 
43914
 
43915
 
43916
 
43917
 
43918
 
43919
 
43920
 
43921
 
43922
 
43923
 
43924
 
43925
 
43926
 
43927
 
43928
 
43929
 
43930
 
43931
 
43932
 
43933
 
43934
 
43935
 
43936
 
43937
 
43938
 
43939
 
43940
 
43941
 
43942
 
43943
 
43944
 
43945
 
43946
 
43947
 
43948
 
43949
 
43950
 
43951
 
43952
 
43953
 
43954
 
43955
 
43956
 
43957
 
43958
 
43959
 
43960
 
43961
 
43962
 
43963
 
43964
 
43965
 
43966
 
43967
 
43968
 
43969
 
43970
 
43971
 
43972
 
43973
 
43974
 
43975
 
43976
 
43977
 
43978
 
43979
 
43980
 
43981
 
43982
 
43983
 
43984
 
43985
 
43986
 
43987
 
43988
 
43989
 
43990
 
43991
 
43992
 
43993
 
43994
 
43995
 
43996
 
43997
 
43998
 
43999
 
44000
 
44001
 
44002
 
44003
 
44004
 
44005
 
44006
 
44007
 
44008
 
44009
 
44010
 
44011
 
44012
 
44013
 
44014
 
44015
 
44016
 
44017
 
44018
 
44019
 
44020
 
44021
 
44022
 
44023
 
44024
 
44025
 
44026
 
44027
 
44028
 
44029
 
44030
 
44031
 
44032
 
44033
 
44034
 
44035
 
44036
 
44037
 
44038
 
44039
 
44040
 
44041
 
44042
 
44043
 
44044
 
44045
 
44046
 
44047
 
44048
 
44049
 
44050
 
44051
 
44052
 
44053
 
44054
 
44055
 
44056
 
44057
 
44058
 
44059
 
44060
 
44061
 
44062
 
44063
 
44064
 
44065
 
44066
 
44067
 
44068
 
44069
 
44070
 
44071
 
44072
 
44073
 
44074
 
44075
 
44076
 
44077
 
44078
 
44079
 
44080
 
44081
 
44082
 
44083
 
44084
 
44085
 
44086
 
44087
 
44088
 
44089
 
44090
 
44091
 
44092
 
44093
 
44094
 
44095
 
44096
 
44097
 
44098
 
44099
 
44100
 
44101
 
44102
 
44103
 
44104
 
44105
 
44106
 
44107
 
44108
 
44109
 
44110
 
44111
 
44112
 
44113
 
44114
 
44115
 
44116
 
44117
 
44118
 
44119
 
44120
 
44121
 
44122
 
44123
 
44124
 
44125
 
44126
 
44127
 
44128
 
44129
 
44130
 
44131
 
44132
 
44133
 
44134
 
44135
 
44136
 
44137
 
44138
 
44139
 
44140
 
44141
 
44142
 
44143
 
44144
 
44145
 
44146
 
44147
 
44148
 
44149
 
44150
 
44151
 
44152
 
44153
 
44154
 
44155
 
44156
 
44157
 
44158
 
44159
 
44160
 
44161
 
44162
 
44163
 
44164
 
44165
 
44166
 
44167
 
44168
 
44169
 
44170
 
44171
 
44172
 
44173
 
44174
 
44175
 
44176
 
44177
 
44178
 
44179
 
44180
 
44181
 
44182
 
44183
 
44184
 
44185
 
44186
 
44187
 
44188
 
44189
 
44190
 
44191
 
44192
 
44193
 
44194
 
44195
 
44196
 
44197
 
44198
 
44199
 
44200
 
44201
 
44202
 
44203
 
44204
 
44205
 
44206
 
44207
 
44208
 
44209
 
44210
 
44211
 
44212
 
44213
 
44214
 
44215
 
44216
 
44217
 
44218
 
44219
 
44220
 
44221
 
44222
 
44223
 
44224
 
44225
 
44226
 
44227
 
44228
 
44229
 
44230
 
44231
 
44232
 
44233
 
44234
 
44235
 
44236
 
44237
 
44238
 
44239
 
44240
 
44241
 
44242
 
44243
 
44244
 
44245
 
44246
 
44247
 
44248
 
44249
 
44250
 
44251
 
44252
 
44253
 
44254
 
44255
 
44256
 
44257
 
44258
 
44259
 
44260
 
44261
 
44262
 
44263
 
44264
 
44265
 
44266
 
44267
 
44268
 
44269
 
44270
 
44271
 
44272
 
44273
 
44274
 
44275
 
44276
 
44277
 
44278
 
44279
 
44280
 
44281
 
44282
 
44283
 
44284
 
44285
 
44286
 
44287
 
44288
 
44289
 
44290
 
44291
 
44292
 
44293
 
44294
 
44295
 
44296
 
44297
 
44298
 
44299
 
44300
 
44301
 
44302
 
44303
 
44304
 
44305
 
44306
 
44307
 
44308
 
44309
 
44310
 
44311
 
44312
 
44313
 
44314
 
44315
 
44316
 
44317
 
44318
 
44319
 
44320
 
44321
 
44322
 
44323
 
44324
 
44325
 
44326
 
44327
 
44328
 
44329
 
44330
 
44331
 
44332
 
44333
 
44334
 
44335
 
44336
 
44337
 
44338
 
44339
 
44340
 
44341
 
44342
 
44343
 
44344
 
44345
 
44346
 
44347
 
44348
 
44349
 
44350
 
44351
 
44352
 
44353
 
44354
 
44355
 
44356
 
44357
 
44358
 
44359
 
44360
 
44361
 
44362
 
44363
 
44364
 
44365
 
44366
 
44367
 
44368
 
44369
 
44370
 
44371
 
44372
 
44373
 
44374
 
44375
 
44376
 
44377
 
44378
 
44379
 
44380
 
44381
 
44382
 
44383
 
44384
 
44385
 
44386
 
44387
 
44388
 
44389
 
44390
 
44391
 
44392
 
44393
 
44394
 
44395
 
44396
 
44397
 
44398
 
44399
 
44400
 
44401
 
44402
 
44403
 
44404
 
44405
 
44406
 
44407
 
44408
 
44409
 
44410
 
44411
 
44412
 
44413
 
44414
 
44415
 
44416
 
44417
 
44418
 
44419
 
44420
 
44421
 
44422
 
44423
 
44424
 
44425
 
44426
 
44427
 
44428
 
44429
 
44430
 
44431
 
44432
 
44433
 
44434
 
44435
 
44436
 
44437
 
44438
 
44439
 
44440
 
44441
 
44442
 
44443
 
44444
 
44445
 
44446
 
44447
 
44448
 
44449
 
44450
 
44451
 
44452
 
44453
 
44454
 
44455
 
44456
 
44457
 
44458
 
44459
 
44460
 
44461
 
44462
 
44463
 
44464
 
44465
 
44466
 
44467
 
44468
 
44469
 
44470
 
44471
 
44472
 
44473
 
44474
 
44475
 
44476
 
44477
 
44478
 
44479
 
44480
 
44481
 
44482
 
44483
 
44484
 
44485
 
44486
 
44487
 
44488
 
44489
 
44490
 
44491
 
44492
 
44493
 
44494
 
44495
 
44496
 
44497
 
44498
 
44499
 
44500
 
44501
 
44502
 
44503
 
44504
 
44505
 
44506
 
44507
 
44508
 
44509
 
44510
 
44511
 
44512
 
44513
 
44514
 
44515
 
44516
 
44517
 
44518
 
44519
 
44520
 
44521
 
44522
 
44523
 
44524
 
44525
 
44526
 
44527
 
44528
 
44529
 
44530
 
44531
 
44532
 
44533
 
44534
 
44535
 
44536
 
44537
 
44538
 
44539
 
44540
 
44541
 
44542
 
44543
 
44544
 
44545
 
44546
 
44547
 
44548
 
44549
 
44550
 
44551
 
44552
 
44553
 
44554
 
44555
 
44556
 
44557
 
44558
 
44559
 
44560
 
44561
 
44562
 
44563
 
44564
 
44565
 
44566
 
44567
 
44568
 
44569
 
44570
 
44571
 
44572
 
44573
 
44574
 
44575
 
44576
 
44577
 
44578
 
44579
 
44580
 
44581
 
44582
 
44583
 
44584
 
44585
 
44586
 
44587
 
44588
 
44589
 
44590
 
44591
 
44592
 
44593
 
44594
 
44595
 
44596
 
44597
 
44598
 
44599
 
44600
 
44601
 
44602
 
44603
 
44604
 
44605
 
44606
 
44607
 
44608
 
44609
 
44610
 
44611
 
44612
 
44613
 
44614
 
44615
 
44616
 
44617
 
44618
 
44619
 
44620
 
44621
 
44622
 
44623
 
44624
 
44625
 
44626
 
44627
 
44628
 
44629
 
44630
 
44631
 
44632
 
44633
 
44634
 
44635
 
44636
 
44637
 
44638
 
44639
 
44640
 
44641
 
44642
 
44643
 
44644
 
44645
 
44646
 
44647
 
44648
 
44649
 
44650
 
44651
 
44652
 
44653
 
44654
 
44655
 
44656
 
44657
 
44658
 
44659
 
44660
 
44661
 
44662
 
44663
 
44664
 
44665
 
44666
 
44667
 
44668
 
44669
 
44670
 
44671
 
44672
 
44673
 
44674
 
44675
 
44676
 
44677
 
44678
 
44679
 
44680
 
44681
 
44682
 
44683
 
44684
 
44685
 
44686
 
44687
 
44688
 
44689
 
44690
 
44691
 
44692
 
44693
 
44694
 
44695
 
44696
 
44697
 
44698
 
44699
 
44700
 
44701
 
44702
 
44703
 
44704
 
44705
 
44706
 
44707
 
44708
 
44709
 
44710
 
44711
 
44712
 
44713
 
44714
 
44715
 
44716
 
44717
 
44718
 
44719
 
44720
 
44721
 
44722
 
44723
 
44724
 
44725
 
44726
 
44727
 
44728
 
44729
 
44730
 
44731
 
44732
 
44733
 
44734
 
44735
 
44736
 
44737
 
44738
 
44739
 
44740
 
44741
 
44742
 
44743
 
44744
 
44745
 
44746
 
44747
 
44748
 
44749
 
44750
 
44751
 
44752
 
44753
 
44754
 
44755
 
44756
 
44757
 
44758
 
44759
 
44760
 
44761
 
44762
 
44763
 
44764
 
44765
 
44766
 
44767
 
44768
 
44769
 
44770
 
44771
 
44772
 
44773
 
44774
 
44775
 
44776
 
44777
 
44778
 
44779
 
44780
 
44781
 
44782
 
44783
 
44784
 
44785
 
44786
 
44787
 
44788
 
44789
 
44790
 
44791
 
44792
 
44793
 
44794
 
44795
 
44796
 
44797
 
44798
 
44799
 
44800
 
44801
 
44802
 
44803
 
44804
 
44805
 
44806
 
44807
 
44808
 
44809
 
44810
 
44811
 
44812
 
44813
 
44814
 
44815
 
44816
 
44817
 
44818
 
44819
 
44820
 
44821
 
44822
 
44823
 
44824
 
44825
 
44826
 
44827
 
44828
 
44829
 
44830
 
44831
 
44832
 
44833
 
44834
 
44835
 
44836
 
44837
 
44838
 
44839
 
44840
 
44841
 
44842
 
44843
 
44844
 
44845
 
44846
 
44847
 
44848
 
44849
 
44850
 
44851
 
44852
 
44853
 
44854
 
44855
 
44856
 
44857
 
44858
 
44859
 
44860
 
44861
 
44862
 
44863
 
44864
 
44865
 
44866
 
44867
 
44868
 
44869
 
44870
 
44871
 
44872
 
44873
 
44874
 
44875
 
44876
 
44877
 
44878
 
44879
 
44880
 
44881
 
44882
 
44883
 
44884
 
44885
 
44886
 
44887
 
44888
 
44889
 
44890
 
44891
 
44892
 
44893
 
44894
 
44895
 
44896
 
44897
 
44898
 
44899
 
44900
 
44901
 
44902
 
44903
 
44904
 
44905
 
44906
 
44907
 
44908
 
44909
 
44910
 
44911
 
44912
 
44913
 
44914
 
44915
 
44916
 
44917
 
44918
 
44919
 
44920
 
44921
 
44922
 
44923
 
44924
 
44925
 
44926
 
44927
 
44928
 
44929
 
44930
 
44931
 
44932
 
44933
 
44934
 
44935
 
44936
 
44937
 
44938
 
44939
 
44940
 
44941
 
44942
 
44943
 
44944
 
44945
 
44946
 
44947
 
44948
 
44949
 
44950
 
44951
 
44952
 
44953
 
44954
 
44955
 
44956
 
44957
 
44958
 
44959
 
44960
 
44961
 
44962
 
44963
 
44964
 
44965
 
44966
 
44967
 
44968
 
44969
 
44970
 
44971
 
44972
 
44973
 
44974
 
44975
 
44976
 
44977
 
44978
 
44979
 
44980
 
44981
 
44982
 
44983
 
44984
 
44985
 
44986
 
44987
 
44988
 
44989
 
44990
 
44991
 
44992
 
44993
 
44994
 
44995
 
44996
 
44997
 
44998
 
44999
 
45000
 
45001
 
45002
 
45003
 
45004
 
45005
 
45006
 
45007
 
45008
 
45009
 
45010
 
45011
 
45012
 
45013
 
45014
 
45015
 
45016
 
45017
 
45018
 
45019
 
45020
 
45021
 
45022
 
45023
 
45024
 
45025
 
45026
 
45027
 
45028
 
45029
 
45030
 
45031
 
45032
 
45033
 
45034
 
45035
 
45036
 
45037
 
45038
 
45039
 
45040
 
45041
 
45042
 
45043
 
45044
 
45045
 
45046
 
45047
 
45048
 
45049
 
45050
 
45051
 
45052
 
45053
 
45054
 
45055
 
45056
 
45057
 
45058
 
45059
 
45060
 
45061
 
45062
 
45063
 
45064
 
45065
 
45066
 
45067
 
45068
 
45069
 
45070
 
45071
 
45072
 
45073
 
45074
 
45075
 
45076
 
45077
 
45078
 
45079
 
45080
 
45081
 
45082
 
45083
 
45084
 
45085
 
45086
 
45087
 
45088
 
45089
 
45090
 
45091
 
45092
 
45093
 
45094
 
45095
 
45096
 
45097
 
45098
 
45099
 
45100
 
45101
 
45102
 
45103
 
45104
 
45105
 
45106
 
45107
 
45108
 
45109
 
45110
 
45111
 
45112
 
45113
 
45114
 
45115
 
45116
 
45117
 
45118
 
45119
 
45120
 
45121
 
45122
 
45123
 
45124
 
45125
 
45126
 
45127
 
45128
 
45129
 
45130
 
45131
 
45132
 
45133
 
45134
 
45135
 
45136
 
45137
 
45138
 
45139
 
45140
 
45141
 
45142
 
45143
 
45144
 
45145
 
45146
 
45147
 
45148
 
45149
 
45150
 
45151
 
45152
 
45153
 
45154
 
45155
 
45156
 
45157
 
45158
 
45159
 
45160
 
45161
 
45162
 
45163
 
45164
 
45165
 
45166
 
45167
 
45168
 
45169
 
45170
 
45171
 
45172
 
45173
 
45174
 
45175
 
45176
 
45177
 
45178
 
45179
 
45180
 
45181
 
45182
 
45183
 
45184
 
45185
 
45186
 
45187
 
45188
 
45189
 
45190
 
45191
 
45192
 
45193
 
45194
 
45195
 
45196
 
45197
 
45198
 
45199
 
45200
 
45201
 
45202
 
45203
 
45204
 
45205
 
45206
 
45207
 
45208
 
45209
 
45210
 
45211
 
45212
 
45213
 
45214
 
45215
 
45216
 
45217
 
45218
 
45219
 
45220
 
45221
 
45222
 
45223
 
45224
 
45225
 
45226
 
45227
 
45228
 
45229
 
45230
 
45231
 
45232
 
45233
 
45234
 
45235
 
45236
 
45237
 
45238
 
45239
 
45240
 
45241
 
45242
 
45243
 
45244
 
45245
 
45246
 
45247
 
45248
 
45249
 
45250
 
45251
 
45252
 
45253
 
45254
 
45255
 
45256
 
45257
 
45258
 
45259
 
45260
 
45261
 
45262
 
45263
 
45264
 
45265
 
45266
 
45267
 
45268
 
45269
 
45270
 
45271
 
45272
 
45273
 
45274
 
45275
 
45276
 
45277
 
45278
 
45279
 
45280
 
45281
 
45282
 
45283
 
45284
 
45285
 
45286
 
45287
 
45288
 
45289
 
45290
 
45291
 
45292
 
45293
 
45294
 
45295
 
45296
 
45297
 
45298
 
45299
 
45300
 
45301
 
45302
 
45303
 
45304
 
45305
 
45306
 
45307
 
45308
 
45309
 
45310
 
45311
 
45312
 
45313
 
45314
 
45315
 
45316
 
45317
 
45318
 
45319
 
45320
 
45321
 
45322
 
45323
 
45324
 
45325
 
45326
 
45327
 
45328
 
45329
 
45330
 
45331
 
45332
 
45333
 
45334
 
45335
 
45336
 
45337
 
45338
 
45339
 
45340
 
45341
 
45342
 
45343
 
45344
 
45345
 
45346
 
45347
 
45348
 
45349
 
45350
 
45351
 
45352
 
45353
 
45354
 
45355
 
45356
 
45357
 
45358
 
45359
 
45360
 
45361
 
45362
 
45363
 
45364
 
45365
 
45366
 
45367
 
45368
 
45369
 
45370
 
45371
 
45372
 
45373
 
45374
 
45375
 
45376
 
45377
 
45378
 
45379
 
45380
 
45381
 
45382
 
45383
 
45384
 
45385
 
45386
 
45387
 
45388
 
45389
 
45390
 
45391
 
45392
 
45393
 
45394
 
45395
 
45396
 
45397
 
45398
 
45399
 
45400
 
45401
 
45402
 
45403
 
45404
 
45405
 
45406
 
45407
 
45408
 
45409
 
45410
 
45411
 
45412
 
45413
 
45414
 
45415
 
45416
 
45417
 
45418
 
45419
 
45420
 
45421
 
45422
 
45423
 
45424
 
45425
 
45426
 
45427
 
45428
 
45429
 
45430
 
45431
 
45432
 
45433
 
45434
 
45435
 
45436
 
45437
 
45438
 
45439
 
45440
 
45441
 
45442
 
45443
 
45444
 
45445
 
45446
 
45447
 
45448
 
45449
 
45450
 
45451
 
45452
 
45453
 
45454
 
45455
 
45456
 
45457
 
45458
 
45459
 
45460
 
45461
 
45462
 
45463
 
45464
 
45465
 
45466
 
45467
 
45468
 
45469
 
45470
 
45471
 
45472
 
45473
 
45474
 
45475
 
45476
 
45477
 
45478
 
45479
 
45480
 
45481
 
45482
 
45483
 
45484
 
45485
 
45486
 
45487
 
45488
 
45489
 
45490
 
45491
 
45492
 
45493
 
45494
 
45495
 
45496
 
45497
 
45498
 
45499
 
45500
 
45501
 
45502
 
45503
 
45504
 
45505
 
45506
 
45507
 
45508
 
45509
 
45510
 
45511
 
45512
 
45513
 
45514
 
45515
 
45516
 
45517
 
45518
 
45519
 
45520
 
45521
 
45522
 
45523
 
45524
 
45525
 
45526
 
45527
 
45528
 
45529
 
45530
 
45531
 
45532
 
45533
 
45534
 
45535
 
45536
 
45537
 
45538
 
45539
 
45540
 
45541
 
45542
 
45543
 
45544
 
45545
 
45546
 
45547
 
45548
 
45549
 
45550
 
45551
 
45552
 
45553
 
45554
 
45555
 
45556
 
45557
 
45558
 
45559
 
45560
 
45561
 
45562
 
45563
 
45564
 
45565
 
45566
 
45567
 
45568
 
45569
 
45570
 
45571
 
45572
 
45573
 
45574
 
45575
 
45576
 
45577
 
45578
 
45579
 
45580
 
45581
 
45582
 
45583
 
45584
 
45585
 
45586
 
45587
 
45588
 
45589
 
45590
 
45591
 
45592
 
45593
 
45594
 
45595
 
45596
 
45597
 
45598
 
45599
 
45600
 
45601
 
45602
 
45603
 
45604
 
45605
 
45606
 
45607
 
45608
 
45609
 
45610
 
45611
 
45612
 
45613
 
45614
 
45615
 
45616
 
45617
 
45618
 
45619
 
45620
 
45621
 
45622
 
45623
 
45624
 
45625
 
45626
 
45627
 
45628
 
45629
 
45630
 
45631
 
45632
 
45633
 
45634
 
45635
 
45636
 
45637
 
45638
 
45639
 
45640
 
45641
 
45642
 
45643
 
45644
 
45645
 
45646
 
45647
 
45648
 
45649
 
45650
 
45651
 
45652
 
45653
 
45654
 
45655
 
45656
 
45657
 
45658
 
45659
 
45660
 
45661
 
45662
 
45663
 
45664
 
45665
 
45666
 
45667
 
45668
 
45669
 
45670
 
45671
 
45672
 
45673
 
45674
 
45675
 
45676
 
45677
 
45678
 
45679
 
45680
 
45681
 
45682
 
45683
 
45684
 
45685
 
45686
 
45687
 
45688
 
45689
 
45690
 
45691
 
45692
 
45693
 
45694
 
45695
 
45696
 
45697
 
45698
 
45699
 
45700
 
45701
 
45702
 
45703
 
45704
 
45705
 
45706
 
45707
 
45708
 
45709
 
45710
 
45711
 
45712
 
45713
 
45714
 
45715
 
45716
 
45717
 
45718
 
45719
 
45720
 
45721
 
45722
 
45723
 
45724
 
45725
 
45726
 
45727
 
45728
 
45729
 
45730
 
45731
 
45732
 
45733
 
45734
 
45735
 
45736
 
45737
 
45738
 
45739
 
45740
 
45741
 
45742
 
45743
 
45744
 
45745
 
45746
 
45747
 
45748
 
45749
 
45750
 
45751
 
45752
 
45753
 
45754
 
45755
 
45756
 
45757
 
45758
 
45759
 
45760
 
45761
 
45762
 
45763
 
45764
 
45765
 
45766
 
45767
 
45768
 
45769
 
45770
 
45771
 
45772
 
45773
 
45774
 
45775
 
45776
 
45777
 
45778
 
45779
 
45780
 
45781
 
45782
 
45783
 
45784
 
45785
 
45786
 
45787
 
45788
 
45789
 
45790
 
45791
 
45792
 
45793
 
45794
 
45795
 
45796
 
45797
 
45798
 
45799
 
45800
 
45801
 
45802
 
45803
 
45804
 
45805
 
45806
 
45807
 
45808
 
45809
 
45810
 
45811
 
45812
 
45813
 
45814
 
45815
 
45816
 
45817
 
45818
 
45819
 
45820
 
45821
 
45822
 
45823
 
45824
 
45825
 
45826
 
45827
 
45828
 
45829
 
45830
 
45831
 
45832
 
45833
 
45834
 
45835
 
45836
 
45837
 
45838
 
45839
 
45840
 
45841
 
45842
 
45843
 
45844
 
45845
 
45846
 
45847
 
45848
 
45849
 
45850
 
45851
 
45852
 
45853
 
45854
 
45855
 
45856
 
45857
 
45858
 
45859
 
45860
 
45861
 
45862
 
45863
 
45864
 
45865
 
45866
 
45867
 
45868
 
45869
 
45870
 
45871
 
45872
 
45873
 
45874
 
45875
 
45876
 
45877
 
45878
 
45879
 
45880
 
45881
 
45882
 
45883
 
45884
 
45885
 
45886
 
45887
 
45888
 
45889
 
45890
 
45891
 
45892
 
45893
 
45894
 
45895
 
45896
 
45897
 
45898
 
45899
 
45900
 
45901
 
45902
 
45903
 
45904
 
45905
 
45906
 
45907
 
45908
 
45909
 
45910
 
45911
 
45912
 
45913
 
45914
 
45915
 
45916
 
45917
 
45918
 
45919
 
45920
 
45921
 
45922
 
45923
 
45924
 
45925
 
45926
 
45927
 
45928
 
45929
 
45930
 
45931
 
45932
 
45933
 
45934
 
45935
 
45936
 
45937
 
45938
 
45939
 
45940
 
45941
 
45942
 
45943
 
45944
 
45945
 
45946
 
45947
 
45948
 
45949
 
45950
 
45951
 
45952
 
45953
 
45954
 
45955
 
45956
 
45957
 
45958
 
45959
 
45960
 
45961
 
45962
 
45963
 
45964
 
45965
 
45966
 
45967
 
45968
 
45969
 
45970
 
45971
 
45972
 
45973
 
45974
 
45975
 
45976
 
45977
 
45978
 
45979
 
45980
 
45981
 
45982
 
45983
 
45984
 
45985
 
45986
 
45987
 
45988
 
45989
 
45990
 
45991
 
45992
 
45993
 
45994
 
45995
 
45996
 
45997
 
45998
 
45999
 
46000
 
46001
 
46002
 
46003
 
46004
 
46005
 
46006
 
46007
 
46008
 
46009
 
46010
 
46011
 
46012
 
46013
 
46014
 
46015
 
46016
 
46017
 
46018
 
46019
 
46020
 
46021
 
46022
 
46023
 
46024
 
46025
 
46026
 
46027
 
46028
 
46029
 
46030
 
46031
 
46032
 
46033
 
46034
 
46035
 
46036
 
46037
 
46038
 
46039
 
46040
 
46041
 
46042
 
46043
 
46044
 
46045
 
46046
 
46047
 
46048
 
46049
 
46050
 
46051
 
46052
 
46053
 
46054
 
46055
 
46056
 
46057
 
46058
 
46059
 
46060
 
46061
 
46062
 
46063
 
46064
 
46065
 
46066
 
46067
 
46068
 
46069
 
46070
 
46071
 
46072
 
46073
 
46074
 
46075
 
46076
 
46077
 
46078
 
46079
 
46080
 
46081
 
46082
 
46083
 
46084
 
46085
 
46086
 
46087
 
46088
 
46089
 
46090
 
46091
 
46092
 
46093
 
46094
 
46095
 
46096
 
46097
 
46098
 
46099
 
46100
 
46101
 
46102
 
46103
 
46104
 
46105
 
46106
 
46107
 
46108
 
46109
 
46110
 
46111
 
46112
 
46113
 
46114
 
46115
 
46116
 
46117
 
46118
 
46119
 
46120
 
46121
 
46122
 
46123
 
46124
 
46125
 
46126
 
46127
 
46128
 
46129
 
46130
 
46131
 
46132
 
46133
 
46134
 
46135
 
46136
 
46137
 
46138
 
46139
 
46140
 
46141
 
46142
 
46143
 
46144
 
46145
 
46146
 
46147
 
46148
 
46149
 
46150
 
46151
 
46152
 
46153
 
46154
 
46155
 
46156
 
46157
 
46158
 
46159
 
46160
 
46161
 
46162
 
46163
 
46164
 
46165
 
46166
 
46167
 
46168
 
46169
 
46170
 
46171
 
46172
 
46173
 
46174
 
46175
 
46176
 
46177
 
46178
 
46179
 
46180
 
46181
 
46182
 
46183
 
46184
 
46185
 
46186
 
46187
 
46188
 
46189
 
46190
 
46191
 
46192
 
46193
 
46194
 
46195
 
46196
 
46197
 
46198
 
46199
 
46200
 
46201
 
46202
 
46203
 
46204
 
46205
 
46206
 
46207
 
46208
 
46209
 
46210
 
46211
 
46212
 
46213
 
46214
 
46215
 
46216
 
46217
 
46218
 
46219
 
46220
 
46221
 
46222
 
46223
 
46224
 
46225
 
46226
 
46227
 
46228
 
46229
 
46230
 
46231
 
46232
 
46233
 
46234
 
46235
 
46236
 
46237
 
46238
 
46239
 
46240
 
46241
 
46242
 
46243
 
46244
 
46245
 
46246
 
46247
 
46248
 
46249
 
46250
 
46251
 
46252
 
46253
 
46254
 
46255
 
46256
 
46257
 
46258
 
46259
 
46260
 
46261
 
46262
 
46263
 
46264
 
46265
 
46266
 
46267
 
46268
 
46269
 
46270
 
46271
 
46272
 
46273
 
46274
 
46275
 
46276
 
46277
 
46278
 
46279
 
46280
 
46281
 
46282
 
46283
 
46284
 
46285
 
46286
 
46287
 
46288
 
46289
 
46290
 
46291
 
46292
 
46293
 
46294
 
46295
 
46296
 
46297
 
46298
 
46299
 
46300
 
46301
 
46302
 
46303
 
46304
 
46305
 
46306
 
46307
 
46308
 
46309
 
46310
 
46311
 
46312
 
46313
 
46314
 
46315
 
46316
 
46317
 
46318
 
46319
 
46320
 
46321
 
46322
 
46323
 
46324
 
46325
 
46326
 
46327
 
46328
 
46329
 
46330
 
46331
 
46332
 
46333
 
46334
 
46335
 
46336
 
46337
 
46338
 
46339
 
46340
 
46341
 
46342
 
46343
 
46344
 
46345
 
46346
 
46347
 
46348
 
46349
 
46350
 
46351
 
46352
 
46353
 
46354
 
46355
 
46356
 
46357
 
46358
 
46359
 
46360
 
46361
 
46362
 
46363
 
46364
 
46365
 
46366
 
46367
 
46368
 
46369
 
46370
 
46371
 
46372
 
46373
 
46374
 
46375
 
46376
 
46377
 
46378
 
46379
 
46380
 
46381
 
46382
 
46383
 
46384
 
46385
 
46386
 
46387
 
46388
 
46389
 
46390
 
46391
 
46392
 
46393
 
46394
 
46395
 
46396
 
46397
 
46398
 
46399
 
46400
 
46401
 
46402
 
46403
 
46404
 
46405
 
46406
 
46407
 
46408
 
46409
 
46410
 
46411
 
46412
 
46413
 
46414
 
46415
 
46416
 
46417
 
46418
 
46419
 
46420
 
46421
 
46422
 
46423
 
46424
 
46425
 
46426
 
46427
 
46428
 
46429
 
46430
 
46431
 
46432
 
46433
 
46434
 
46435
 
46436
 
46437
 
46438
 
46439
 
46440
 
46441
 
46442
 
46443
 
46444
 
46445
 
46446
 
46447
 
46448
 
46449
 
46450
 
46451
 
46452
 
46453
 
46454
 
46455
 
46456
 
46457
 
46458
 
46459
 
46460
 
46461
 
46462
 
46463
 
46464
 
46465
 
46466
 
46467
 
46468
 
46469
 
46470
 
46471
 
46472
 
46473
 
46474
 
46475
 
46476
 
46477
 
46478
 
46479
 
46480
 
46481
 
46482
 
46483
 
46484
 
46485
 
46486
 
46487
 
46488
 
46489
 
46490
 
46491
 
46492
 
46493
 
46494
 
46495
 
46496
 
46497
 
46498
 
46499
 
46500
 
46501
 
46502
 
46503
 
46504
 
46505
 
46506
 
46507
 
46508
 
46509
 
46510
 
46511
 
46512
 
46513
 
46514
 
46515
 
46516
 
46517
 
46518
 
46519
 
46520
 
46521
 
46522
 
46523
 
46524
 
46525
 
46526
 
46527
 
46528
 
46529
 
46530
 
46531
 
46532
 
46533
 
46534
 
46535
 
46536
 
46537
 
46538
 
46539
 
46540
 
46541
 
46542
 
46543
 
46544
 
46545
 
46546
 
46547
 
46548
 
46549
 
46550
 
46551
 
46552
 
46553
 
46554
 
46555
 
46556
 
46557
 
46558
 
46559
 
46560
 
46561
 
46562
 
46563
 
46564
 
46565
 
46566
 
46567
 
46568
 
46569
 
46570
 
46571
 
46572
 
46573
 
46574
 
46575
 
46576
 
46577
 
46578
 
46579
 
46580
 
46581
 
46582
 
46583
 
46584
 
46585
 
46586
 
46587
 
46588
 
46589
 
46590
 
46591
 
46592
 
46593
 
46594
 
46595
 
46596
 
46597
 
46598
 
46599
 
46600
 
46601
 
46602
 
46603
 
46604
 
46605
 
46606
 
46607
 
46608
 
46609
 
46610
 
46611
 
46612
 
46613
 
46614
 
46615
 
46616
 
46617
 
46618
 
46619
 
46620
 
46621
 
46622
 
46623
 
46624
 
46625
 
46626
 
46627
 
46628
 
46629
 
46630
 
46631
 
46632
 
46633
 
46634
 
46635
 
46636
 
46637
 
46638
 
46639
 
46640
 
46641
 
46642
 
46643
 
46644
 
46645
 
46646
 
46647
 
46648
 
46649
 
46650
 
46651
 
46652
 
46653
 
46654
 
46655
 
46656
 
46657
 
46658
 
46659
 
46660
 
46661
 
46662
 
46663
 
46664
 
46665
 
46666
 
46667
 
46668
 
46669
 
46670
 
46671
 
46672
 
46673
 
46674
 
46675
 
46676
 
46677
 
46678
 
46679
 
46680
 
46681
 
46682
 
46683
 
46684
 
46685
 
46686
 
46687
 
46688
 
46689
 
46690
 
46691
 
46692
 
46693
 
46694
 
46695
 
46696
 
46697
 
46698
 
46699
 
46700
 
46701
 
46702
 
46703
 
46704
 
46705
 
46706
 
46707
 
46708
 
46709
 
46710
 
46711
 
46712
 
46713
 
46714
 
46715
 
46716
 
46717
 
46718
 
46719
 
46720
 
46721
 
46722
 
46723
 
46724
 
46725
 
46726
 
46727
 
46728
 
46729
 
46730
 
46731
 
46732
 
46733
 
46734
 
46735
 
46736
 
46737
 
46738
 
46739
 
46740
 
46741
 
46742
 
46743
 
46744
 
46745
 
46746
 
46747
 
46748
 
46749
 
46750
 
46751
 
46752
 
46753
 
46754
 
46755
 
46756
 
46757
 
46758
 
46759
 
46760
 
46761
 
46762
 
46763
 
46764
 
46765
 
46766
 
46767
 
46768
 
46769
 
46770
 
46771
 
46772
 
46773
 
46774
 
46775
 
46776
 
46777
 
46778
 
46779
 
46780
 
46781
 
46782
 
46783
 
46784
 
46785
 
46786
 
46787
 
46788
 
46789
 
46790
 
46791
 
46792
 
46793
 
46794
 
46795
 
46796
 
46797
 
46798
 
46799
 
46800
 
46801
 
46802
 
46803
 
46804
 
46805
 
46806
 
46807
 
46808
 
46809
 
46810
 
46811
 
46812
 
46813
 
46814
 
46815
 
46816
 
46817
 
46818
 
46819
 
46820
 
46821
 
46822
 
46823
 
46824
 
46825
 
46826
 
46827
 
46828
 
46829
 
46830
 
46831
 
46832
 
46833
 
46834
 
46835
 
46836
 
46837
 
46838
 
46839
 
46840
 
46841
 
46842
 
46843
 
46844
 
46845
 
46846
 
46847
 
46848
 
46849
 
46850
 
46851
 
46852
 
46853
 
46854
 
46855
 
46856
 
46857
 
46858
 
46859
 
46860
 
46861
 
46862
 
46863
 
46864
 
46865
 
46866
 
46867
 
46868
 
46869
 
46870
 
46871
 
46872
 
46873
 
46874
 
46875
 
46876
 
46877
 
46878
 
46879
 
46880
 
46881
 
46882
 
46883
 
46884
 
46885
 
46886
 
46887
 
46888
 
46889
 
46890
 
46891
 
46892
 
46893
 
46894
 
46895
 
46896
 
46897
 
46898
 
46899
 
46900
 
46901
 
46902
 
46903
 
46904
 
46905
 
46906
 
46907
 
46908
 
46909
 
46910
 
46911
 
46912
 
46913
 
46914
 
46915
 
46916
 
46917
 
46918
 
46919
 
46920
 
46921
 
46922
 
46923
 
46924
 
46925
 
46926
 
46927
 
46928
 
46929
 
46930
 
46931
 
46932
 
46933
 
46934
 
46935
 
46936
 
46937
 
46938
 
46939
 
46940
 
46941
 
46942
 
46943
 
46944
 
46945
 
46946
 
46947
 
46948
 
46949
 
46950
 
46951
 
46952
 
46953
 
46954
 
46955
 
46956
 
46957
 
46958
 
46959
 
46960
 
46961
 
46962
 
46963
 
46964
 
46965
 
46966
 
46967
 
46968
 
46969
 
46970
 
46971
 
46972
 
46973
 
46974
 
46975
 
46976
 
46977
 
46978
 
46979
 
46980
 
46981
 
46982
 
46983
 
46984
 
46985
 
46986
 
46987
 
46988
 
46989
 
46990
 
46991
 
46992
 
46993
 
46994
 
46995
 
46996
 
46997
 
46998
 
46999
 
47000
 
47001
 
47002
 
47003
 
47004
 
47005
 
47006
 
47007
 
47008
 
47009
 
47010
 
47011
 
47012
 
47013
 
47014
 
47015
 
47016
 
47017
 
47018
 
47019
 
47020
 
47021
 
47022
 
47023
 
47024
 
47025
 
47026
 
47027
 
47028
 
47029
 
47030
 
47031
 
47032
 
47033
 
47034
 
47035
 
47036
 
47037
 
47038
 
47039
 
47040
 
47041
 
47042
 
47043
 
47044
 
47045
 
47046
 
47047
 
47048
 
47049
 
47050
 
47051
 
47052
 
47053
 
47054
 
47055
 
47056
 
47057
 
47058
 
47059
 
47060
 
47061
 
47062
 
47063
 
47064
 
47065
 
47066
 
47067
 
47068
 
47069
 
47070
 
47071
 
47072
 
47073
 
47074
 
47075
 
47076
 
47077
 
47078
 
47079
 
47080
 
47081
 
47082
 
47083
 
47084
 
47085
 
47086
 
47087
 
47088
 
47089
 
47090
 
47091
 
47092
 
47093
 
47094
 
47095
 
47096
 
47097
 
47098
 
47099
 
47100
 
47101
 
47102
 
47103
 
47104
 
47105
 
47106
 
47107
 
47108
 
47109
 
47110
 
47111
 
47112
 
47113
 
47114
 
47115
 
47116
 
47117
 
47118
 
47119
 
47120
 
47121
 
47122
 
47123
 
47124
 
47125
 
47126
 
47127
 
47128
 
47129
 
47130
 
47131
 
47132
 
47133
 
47134
 
47135
 
47136
 
47137
 
47138
 
47139
 
47140
 
47141
 
47142
 
47143
 
47144
 
47145
 
47146
 
47147
 
47148
 
47149
 
47150
 
47151
 
47152
 
47153
 
47154
 
47155
 
47156
 
47157
 
47158
 
47159
 
47160
 
47161
 
47162
 
47163
 
47164
 
47165
 
47166
 
47167
 
47168
 
47169
 
47170
 
47171
 
47172
 
47173
 
47174
 
47175
 
47176
 
47177
 
47178
 
47179
 
47180
 
47181
 
47182
 
47183
 
47184
 
47185
 
47186
 
47187
 
47188
 
47189
 
47190
 
47191
 
47192
 
47193
 
47194
 
47195
 
47196
 
47197
 
47198
 
47199
 
47200
 
47201
 
47202
 
47203
 
47204
 
47205
 
47206
 
47207
 
47208
 
47209
 
47210
 
47211
 
47212
 
47213
 
47214
 
47215
 
47216
 
47217
 
47218
 
47219
 
47220
 
47221
 
47222
 
47223
 
47224
 
47225
 
47226
 
47227
 
47228
 
47229
 
47230
 
47231
 
47232
 
47233
 
47234
 
47235
 
47236
 
47237
 
47238
 
47239
 
47240
 
47241
 
47242
 
47243
 
47244
 
47245
 
47246
 
47247
 
47248
 
47249
 
47250
 
47251
 
47252
 
47253
 
47254
 
47255
 
47256
 
47257
 
47258
 
47259
 
47260
 
47261
 
47262
 
47263
 
47264
 
47265
 
47266
 
47267
 
47268
 
47269
 
47270
 
47271
 
47272
 
47273
 
47274
 
47275
 
47276
 
47277
 
47278
 
47279
 
47280
 
47281
 
47282
 
47283
 
47284
 
47285
 
47286
 
47287
 
47288
 
47289
 
47290
 
47291
 
47292
 
47293
 
47294
 
47295
 
47296
 
47297
 
47298
 
47299
 
47300
 
47301
 
47302
 
47303
 
47304
 
47305
 
47306
 
47307
 
47308
 
47309
 
47310
 
47311
 
47312
 
47313
 
47314
 
47315
 
47316
 
47317
 
47318
 
47319
 
47320
 
47321
 
47322
 
47323
 
47324
 
47325
 
47326
 
47327
 
47328
 
47329
 
47330
 
47331
 
47332
 
47333
 
47334
 
47335
 
47336
 
47337
 
47338
 
47339
 
47340
 
47341
 
47342
 
47343
 
47344
 
47345
 
47346
 
47347
 
47348
 
47349
 
47350
 
47351
 
47352
 
47353
 
47354
 
47355
 
47356
 
47357
 
47358
 
47359
 
47360
 
47361
 
47362
 
47363
 
47364
 
47365
 
47366
 
47367
 
47368
 
47369
 
47370
 
47371
 
47372
 
47373
 
47374
 
47375
 
47376
 
47377
 
47378
 
47379
 
47380
 
47381
 
47382
 
47383
 
47384
 
47385
 
47386
 
47387
 
47388
 
47389
 
47390
 
47391
 
47392
 
47393
 
47394
 
47395
 
47396
 
47397
 
47398
 
47399
 
47400
 
47401
 
47402
 
47403
 
47404
 
47405
 
47406
 
47407
 
47408
 
47409
 
47410
 
47411
 
47412
 
47413
 
47414
 
47415
 
47416
 
47417
 
47418
 
47419
 
47420
 
47421
 
47422
 
47423
 
47424
 
47425
 
47426
 
47427
 
47428
 
47429
 
47430
 
47431
 
47432
 
47433
 
47434
 
47435
 
47436
 
47437
 
47438
 
47439
 
47440
 
47441
 
47442
 
47443
 
47444
 
47445
 
47446
 
47447
 
47448
 
47449
 
47450
 
47451
 
47452
 
47453
 
47454
 
47455
 
47456
 
47457
 
47458
 
47459
 
47460
 
47461
 
47462
 
47463
 
47464
 
47465
 
47466
 
47467
 
47468
 
47469
 
47470
 
47471
 
47472
 
47473
 
47474
 
47475
 
47476
 
47477
 
47478
 
47479
 
47480
 
47481
 
47482
 
47483
 
47484
 
47485
 
47486
 
47487
 
47488
 
47489
 
47490
 
47491
 
47492
 
47493
 
47494
 
47495
 
47496
 
47497
 
47498
 
47499
 
47500
 
47501
 
47502
 
47503
 
47504
 
47505
 
47506
 
47507
 
47508
 
47509
 
47510
 
47511
 
47512
 
47513
 
47514
 
47515
 
47516
 
47517
 
47518
 
47519
 
47520
 
47521
 
47522
 
47523
 
47524
 
47525
 
47526
 
47527
 
47528
 
47529
 
47530
 
47531
 
47532
 
47533
 
47534
 
47535
 
47536
 
47537
 
47538
 
47539
 
47540
 
47541
 
47542
 
47543
 
47544
 
47545
 
47546
 
47547
 
47548
 
47549
 
47550
 
47551
 
47552
 
47553
 
47554
 
47555
 
47556
 
47557
 
47558
 
47559
 
47560
 
47561
 
47562
 
47563
 
47564
 
47565
 
47566
 
47567
 
47568
 
47569
 
47570
 
47571
 
47572
 
47573
 
47574
 
47575
 
47576
 
47577
 
47578
 
47579
 
47580
 
47581
 
47582
 
47583
 
47584
 
47585
 
47586
 
47587
 
47588
 
47589
 
47590
 
47591
 
47592
 
47593
 
47594
 
47595
 
47596
 
47597
 
47598
 
47599
 
47600
 
47601
 
47602
 
47603
 
47604
 
47605
 
47606
 
47607
 
47608
 
47609
 
47610
 
47611
 
47612
 
47613
 
47614
 
47615
 
47616
 
47617
 
47618
 
47619
 
47620
 
47621
 
47622
 
47623
 
47624
 
47625
 
47626
 
47627
 
47628
 
47629
 
47630
 
47631
 
47632
 
47633
 
47634
 
47635
 
47636
 
47637
 
47638
 
47639
 
47640
 
47641
 
47642
 
47643
 
47644
 
47645
 
47646
 
47647
 
47648
 
47649
 
47650
 
47651
 
47652
 
47653
 
47654
 
47655
 
47656
 
47657
 
47658
 
47659
 
47660
 
47661
 
47662
 
47663
 
47664
 
47665
 
47666
 
47667
 
47668
 
47669
 
47670
 
47671
 
47672
 
47673
 
47674
 
47675
 
47676
 
47677
 
47678
 
47679
 
47680
 
47681
 
47682
 
47683
 
47684
 
47685
 
47686
 
47687
 
47688
 
47689
 
47690
 
47691
 
47692
 
47693
 
47694
 
47695
 
47696
 
47697
 
47698
 
47699
 
47700
 
47701
 
47702
 
47703
 
47704
 
47705
 
47706
 
47707
 
47708
 
47709
 
47710
 
47711
 
47712
 
47713
 
47714
 
47715
 
47716
 
47717
 
47718
 
47719
 
47720
 
47721
 
47722
 
47723
 
47724
 
47725
 
47726
 
47727
 
47728
 
47729
 
47730
 
47731
 
47732
 
47733
 
47734
 
47735
 
47736
 
47737
 
47738
 
47739
 
47740
 
47741
 
47742
 
47743
 
47744
 
47745
 
47746
 
47747
 
47748
 
47749
 
47750
 
47751
 
47752
 
47753
 
47754
 
47755
 
47756
 
47757
 
47758
 
47759
 
47760
 
47761
 
47762
 
47763
 
47764
 
47765
 
47766
 
47767
 
47768
 
47769
 
47770
 
47771
 
47772
 
47773
 
47774
 
47775
 
47776
 
47777
 
47778
 
47779
 
47780
 
47781
 
47782
 
47783
 
47784
 
47785
 
47786
 
47787
 
47788
 
47789
 
47790
 
47791
 
47792
 
47793
 
47794
 
47795
 
47796
 
47797
 
47798
 
47799
 
47800
 
47801
 
47802
 
47803
 
47804
 
47805
 
47806
 
47807
 
47808
 
47809
 
47810
 
47811
 
47812
 
47813
 
47814
 
47815
 
47816
 
47817
 
47818
 
47819
 
47820
 
47821
 
47822
 
47823
 
47824
 
47825
 
47826
 
47827
 
47828
 
47829
 
47830
 
47831
 
47832
 
47833
 
47834
 
47835
 
47836
 
47837
 
47838
 
47839
 
47840
 
47841
 
47842
 
47843
 
47844
 
47845
 
47846
 
47847
 
47848
 
47849
 
47850
 
47851
 
47852
 
47853
 
47854
 
47855
 
47856
 
47857
 
47858
 
47859
 
47860
 
47861
 
47862
 
47863
 
47864
 
47865
 
47866
 
47867
 
47868
 
47869
 
47870
 
47871
 
47872
 
47873
 
47874
 
47875
 
47876
 
47877
 
47878
 
47879
 
47880
 
47881
 
47882
 
47883
 
47884
 
47885
 
47886
 
47887
 
47888
 
47889
 
47890
 
47891
 
47892
 
47893
 
47894
 
47895
 
47896
 
47897
 
47898
 
47899
 
47900
 
47901
 
47902
 
47903
 
47904
 
47905
 
47906
 
47907
 
47908
 
47909
 
47910
 
47911
 
47912
 
47913
 
47914
 
47915
 
47916
 
47917
 
47918
 
47919
 
47920
 
47921
 
47922
 
47923
 
47924
 
47925
 
47926
 
47927
 
47928
 
47929
 
47930
 
47931
 
47932
 
47933
 
47934
 
47935
 
47936
 
47937
 
47938
 
47939
 
47940
 
47941
 
47942
 
47943
 
47944
 
47945
 
47946
 
47947
 
47948
 
47949
 
47950
 
47951
 
47952
 
47953
 
47954
 
47955
 
47956
 
47957
 
47958
 
47959
 
47960
 
47961
 
47962
 
47963
 
47964
 
47965
 
47966
 
47967
 
47968
 
47969
 
47970
 
47971
 
47972
 
47973
 
47974
 
47975
 
47976
 
47977
 
47978
 
47979
 
47980
 
47981
 
47982
 
47983
 
47984
 
47985
 
47986
 
47987
 
47988
 
47989
 
47990
 
47991
 
47992
 
47993
 
47994
 
47995
 
47996
 
47997
 
47998
 
47999
 
48000
 
48001
 
48002
 
48003
 
48004
 
48005
 
48006
 
48007
 
48008
 
48009
 
48010
 
48011
 
48012
 
48013
 
48014
 
48015
 
48016
 
48017
 
48018
 
48019
 
48020
 
48021
 
48022
 
48023
 
48024
 
48025
 
48026
 
48027
 
48028
 
48029
 
48030
 
48031
 
48032
 
48033
 
48034
 
48035
 
48036
 
48037
 
48038
 
48039
 
48040
 
48041
 
48042
 
48043
 
48044
 
48045
 
48046
 
48047
 
48048
 
48049
 
48050
 
48051
 
48052
 
48053
 
48054
 
48055
 
48056
 
48057
 
48058
 
48059
 
48060
 
48061
 
48062
 
48063
 
48064
 
48065
 
48066
 
48067
 
48068
 
48069
 
48070
 
48071
 
48072
 
48073
 
48074
 
48075
 
48076
 
48077
 
48078
 
48079
 
48080
 
48081
 
48082
 
48083
 
48084
 
48085
 
48086
 
48087
 
48088
 
48089
 
48090
 
48091
 
48092
 
48093
 
48094
 
48095
 
48096
 
48097
 
48098
 
48099
 
48100
 
48101
 
48102
 
48103
 
48104
 
48105
 
48106
 
48107
 
48108
 
48109
 
48110
 
48111
 
48112
 
48113
 
48114
 
48115
 
48116
 
48117
 
48118
 
48119
 
48120
 
48121
 
48122
 
48123
 
48124
 
48125
 
48126
 
48127
 
48128
 
48129
 
48130
 
48131
 
48132
 
48133
 
48134
 
48135
 
48136
 
48137
 
48138
 
48139
 
48140
 
48141
 
48142
 
48143
 
48144
 
48145
 
48146
 
48147
 
48148
 
48149
 
48150
 
48151
 
48152
 
48153
 
48154
 
48155
 
48156
 
48157
 
48158
 
48159
 
48160
 
48161
 
48162
 
48163
 
48164
 
48165
 
48166
 
48167
 
48168
 
48169
 
48170
 
48171
 
48172
 
48173
 
48174
 
48175
 
48176
 
48177
 
48178
 
48179
 
48180
 
48181
 
48182
 
48183
 
48184
 
48185
 
48186
 
48187
 
48188
 
48189
 
48190
 
48191
 
48192
 
48193
 
48194
 
48195
 
48196
 
48197
 
48198
 
48199
 
48200
 
48201
 
48202
 
48203
 
48204
 
48205
 
48206
 
48207
 
48208
 
48209
 
48210
 
48211
 
48212
 
48213
 
48214
 
48215
 
48216
 
48217
 
48218
 
48219
 
48220
 
48221
 
48222
 
48223
 
48224
 
48225
 
48226
 
48227
 
48228
 
48229
 
48230
 
48231
 
48232
 
48233
 
48234
 
48235
 
48236
 
48237
 
48238
 
48239
 
48240
 
48241
 
48242
 
48243
 
48244
 
48245
 
48246
 
48247
 
48248
 
48249
 
48250
 
48251
 
48252
 
48253
 
48254
 
48255
 
48256
 
48257
 
48258
 
48259
 
48260
 
48261
 
48262
 
48263
 
48264
 
48265
 
48266
 
48267
 
48268
 
48269
 
48270
 
48271
 
48272
 
48273
 
48274
 
48275
 
48276
 
48277
 
48278
 
48279
 
48280
 
48281
 
48282
 
48283
 
48284
 
48285
 
48286
 
48287
 
48288
 
48289
 
48290
 
48291
 
48292
 
48293
 
48294
 
48295
 
48296
 
48297
 
48298
 
48299
 
48300
 
48301
 
48302
 
48303
 
48304
 
48305
 
48306
 
48307
 
48308
 
48309
 
48310
 
48311
 
48312
 
48313
 
48314
 
48315
 
48316
 
48317
 
48318
 
48319
 
48320
 
48321
 
48322
 
48323
 
48324
 
48325
 
48326
 
48327
 
48328
 
48329
 
48330
 
48331
 
48332
 
48333
 
48334
 
48335
 
48336
 
48337
 
48338
 
48339
 
48340
 
48341
 
48342
 
48343
 
48344
 
48345
 
48346
 
48347
 
48348
 
48349
 
48350
 
48351
 
48352
 
48353
 
48354
 
48355
 
48356
 
48357
 
48358
 
48359
 
48360
 
48361
 
48362
 
48363
 
48364
 
48365
 
48366
 
48367
 
48368
 
48369
 
48370
 
48371
 
48372
 
48373
 
48374
 
48375
 
48376
 
48377
 
48378
 
48379
 
48380
 
48381
 
48382
 
48383
 
48384
 
48385
 
48386
 
48387
 
48388
 
48389
 
48390
 
48391
 
48392
 
48393
 
48394
 
48395
 
48396
 
48397
 
48398
 
48399
 
48400
 
48401
 
48402
 
48403
 
48404
 
48405
 
48406
 
48407
 
48408
 
48409
 
48410
 
48411
 
48412
 
48413
 
48414
 
48415
 
48416
 
48417
 
48418
 
48419
 
48420
 
48421
 
48422
 
48423
 
48424
 
48425
 
48426
 
48427
 
48428
 
48429
 
48430
 
48431
 
48432
 
48433
 
48434
 
48435
 
48436
 
48437
 
48438
 
48439
 
48440
 
48441
 
48442
 
48443
 
48444
 
48445
 
48446
 
48447
 
48448
 
48449
 
48450
 
48451
 
48452
 
48453
 
48454
 
48455
 
48456
 
48457
 
48458
 
48459
 
48460
 
48461
 
48462
 
48463
 
48464
 
48465
 
48466
 
48467
 
48468
 
48469
 
48470
 
48471
 
48472
 
48473
 
48474
 
48475
 
48476
 
48477
 
48478
 
48479
 
48480
 
48481
 
48482
 
48483
 
48484
 
48485
 
48486
 
48487
 
48488
 
48489
 
48490
 
48491
 
48492
 
48493
 
48494
 
48495
 
48496
 
48497
 
48498
 
48499
 
48500
 
48501
 
48502
 
48503
 
48504
 
48505
 
48506
 
48507
 
48508
 
48509
 
48510
 
48511
 
48512
 
48513
 
48514
 
48515
 
48516
 
48517
 
48518
 
48519
 
48520
 
48521
 
48522
 
48523
 
48524
 
48525
 
48526
 
48527
 
48528
 
48529
 
48530
 
48531
 
48532
 
48533
 
48534
 
48535
 
48536
 
48537
 
48538
 
48539
 
48540
 
48541
 
48542
 
48543
 
48544
 
48545
 
48546
 
48547
 
48548
 
48549
 
48550
 
48551
 
48552
 
48553
 
48554
 
48555
 
48556
 
48557
 
48558
 
48559
 
48560
 
48561
 
48562
 
48563
 
48564
 
48565
 
48566
 
48567
 
48568
 
48569
 
48570
 
48571
 
48572
 
48573
 
48574
 
48575
 
48576
 
48577
 
48578
 
48579
 
48580
 
48581
 
48582
 
48583
 
48584
 
48585
 
48586
 
48587
 
48588
 
48589
 
48590
 
48591
 
48592
 
48593
 
48594
 
48595
 
48596
 
48597
 
48598
 
48599
 
48600
 
48601
 
48602
 
48603
 
48604
 
48605
 
48606
 
48607
 
48608
 
48609
 
48610
 
48611
 
48612
 
48613
 
48614
 
48615
 
48616
 
48617
 
48618
 
48619
 
48620
 
48621
 
48622
 
48623
 
48624
 
48625
 
48626
 
48627
 
48628
 
48629
 
48630
 
48631
 
48632
 
48633
 
48634
 
48635
 
48636
 
48637
 
48638
 
48639
 
48640
 
48641
 
48642
 
48643
 
48644
 
48645
 
48646
 
48647
 
48648
 
48649
 
48650
 
48651
 
48652
 
48653
 
48654
 
48655
 
48656
 
48657
 
48658
 
48659
 
48660
 
48661
 
48662
 
48663
 
48664
 
48665
 
48666
 
48667
 
48668
 
48669
 
48670
 
48671
 
48672
 
48673
 
48674
 
48675
 
48676
 
48677
 
48678
 
48679
 
48680
 
48681
 
48682
 
48683
 
48684
 
48685
 
48686
 
48687
 
48688
 
48689
 
48690
 
48691
 
48692
 
48693
 
48694
 
48695
 
48696
 
48697
 
48698
 
48699
 
48700
 
48701
 
48702
 
48703
 
48704
 
48705
 
48706
 
48707
 
48708
 
48709
 
48710
 
48711
 
48712
 
48713
 
48714
 
48715
 
48716
 
48717
 
48718
 
48719
 
48720
 
48721
 
48722
 
48723
 
48724
 
48725
 
48726
 
48727
 
48728
 
48729
 
48730
 
48731
 
48732
 
48733
 
48734
 
48735
 
48736
 
48737
 
48738
 
48739
 
48740
 
48741
 
48742
 
48743
 
48744
 
48745
 
48746
 
48747
 
48748
 
48749
 
48750
 
48751
 
48752
 
48753
 
48754
 
48755
 
48756
 
48757
 
48758
 
48759
 
48760
 
48761
 
48762
 
48763
 
48764
 
48765
 
48766
 
48767
 
48768
 
48769
 
48770
 
48771
 
48772
 
48773
 
48774
 
48775
 
48776
 
48777
 
48778
 
48779
 
48780
 
48781
 
48782
 
48783
 
48784
 
48785
 
48786
 
48787
 
48788
 
48789
 
48790
 
48791
 
48792
 
48793
 
48794
 
48795
 
48796
 
48797
 
48798
 
48799
 
48800
 
48801
 
48802
 
48803
 
48804
 
48805
 
48806
 
48807
 
48808
 
48809
 
48810
 
48811
 
48812
 
48813
 
48814
 
48815
 
48816
 
48817
 
48818
 
48819
 
48820
 
48821
 
48822
 
48823
 
48824
 
48825
 
48826
 
48827
 
48828
 
48829
 
48830
 
48831
 
48832
 
48833
 
48834
 
48835
 
48836
 
48837
 
48838
 
48839
 
48840
 
48841
 
48842
 
48843
 
48844
 
48845
 
48846
 
48847
 
48848
 
48849
 
48850
 
48851
 
48852
 
48853
 
48854
 
48855
 
48856
 
48857
 
48858
 
48859
 
48860
 
48861
 
48862
 
48863
 
48864
 
48865
 
48866
 
48867
 
48868
 
48869
 
48870
 
48871
 
48872
 
48873
 
48874
 
48875
 
48876
 
48877
 
48878
 
48879
 
48880
 
48881
 
48882
 
48883
 
48884
 
48885
 
48886
 
48887
 
48888
 
48889
 
48890
 
48891
 
48892
 
48893
 
48894
 
48895
 
48896
 
48897
 
48898
 
48899
 
48900
 
48901
 
48902
 
48903
 
48904
 
48905
 
48906
 
48907
 
48908
 
48909
 
48910
 
48911
 
48912
 
48913
 
48914
 
48915
 
48916
 
48917
 
48918
 
48919
 
48920
 
48921
 
48922
 
48923
 
48924
 
48925
 
48926
 
48927
 
48928
 
48929
 
48930
 
48931
 
48932
 
48933
 
48934
 
48935
 
48936
 
48937
 
48938
 
48939
 
48940
 
48941
 
48942
 
48943
 
48944
 
48945
 
48946
 
48947
 
48948
 
48949
 
48950
 
48951
 
48952
 
48953
 
48954
 
48955
 
48956
 
48957
 
48958
 
48959
 
48960
 
48961
 
48962
 
48963
 
48964
 
48965
 
48966
 
48967
 
48968
 
48969
 
48970
 
48971
 
48972
 
48973
 
48974
 
48975
 
48976
 
48977
 
48978
 
48979
 
48980
 
48981
 
48982
 
48983
 
48984
 
48985
 
48986
 
48987
 
48988
 
48989
 
48990
 
48991
 
48992
 
48993
 
48994
 
48995
 
48996
 
48997
 
48998
 
48999
 
49000
 
49001
 
49002
 
49003
 
49004
 
49005
 
49006
 
49007
 
49008
 
49009
 
49010
 
49011
 
49012
 
49013
 
49014
 
49015
 
49016
 
49017
 
49018
 
49019
 
49020
 
49021
 
49022
 
49023
 
49024
 
49025
 
49026
 
49027
 
49028
 
49029
 
49030
 
49031
 
49032
 
49033
 
49034
 
49035
 
49036
 
49037
 
49038
 
49039
 
49040
 
49041
 
49042
 
49043
 
49044
 
49045
 
49046
 
49047
 
49048
 
49049
 
49050
 
49051
 
49052
 
49053
 
49054
 
49055
 
49056
 
49057
 
49058
 
49059
 
49060
 
49061
 
49062
 
49063
 
49064
 
49065
 
49066
 
49067
 
49068
 
49069
 
49070
 
49071
 
49072
 
49073
 
49074
 
49075
 
49076
 
49077
 
49078
 
49079
 
49080
 
49081
 
49082
 
49083
 
49084
 
49085
 
49086
 
49087
 
49088
 
49089
 
49090
 
49091
 
49092
 
49093
 
49094
 
49095
 
49096
 
49097
 
49098
 
49099
 
49100
 
49101
 
49102
 
49103
 
49104
 
49105
 
49106
 
49107
 
49108
 
49109
 
49110
 
49111
 
49112
 
49113
 
49114
 
49115
 
49116
 
49117
 
49118
 
49119
 
49120
 
49121
 
49122
 
49123
 
49124
 
49125
 
49126
 
49127
 
49128
 
49129
 
49130
 
49131
 
49132
 
49133
 
49134
 
49135
 
49136
 
49137
 
49138
 
49139
 
49140
 
49141
 
49142
 
49143
 
49144
 
49145
 
49146
 
49147
 
49148
 
49149
 
49150
 
49151
 
49152
 
49153
 
49154
 
49155
 
49156
 
49157
 
49158
 
49159
 
49160
 
49161
 
49162
 
49163
 
49164
 
49165
 
49166
 
49167
 
49168
 
49169
 
49170
 
49171
 
49172
 
49173
 
49174
 
49175
 
49176
 
49177
 
49178
 
49179
 
49180
 
49181
 
49182
 
49183
 
49184
 
49185
 
49186
 
49187
 
49188
 
49189
 
49190
 
49191
 
49192
 
49193
 
49194
 
49195
 
49196
 
49197
 
49198
 
49199
 
49200
 
49201
 
49202
 
49203
 
49204
 
49205
 
49206
 
49207
 
49208
 
49209
 
49210
 
49211
 
49212
 
49213
 
49214
 
49215
 
49216
 
49217
 
49218
 
49219
 
49220
 
49221
 
49222
 
49223
 
49224
 
49225
 
49226
 
49227
 
49228
 
49229
 
49230
 
49231
 
49232
 
49233
 
49234
 
49235
 
49236
 
49237
 
49238
 
49239
 
49240
 
49241
 
49242
 
49243
 
49244
 
49245
 
49246
 
49247
 
49248
 
49249
 
49250
 
49251
 
49252
 
49253
 
49254
 
49255
 
49256
 
49257
 
49258
 
49259
 
49260
 
49261
 
49262
 
49263
 
49264
 
49265
 
49266
 
49267
 
49268
 
49269
 
49270
 
49271
 
49272
 
49273
 
49274
 
49275
 
49276
 
49277
 
49278
 
49279
 
49280
 
49281
 
49282
 
49283
 
49284
 
49285
 
49286
 
49287
 
49288
 
49289
 
49290
 
49291
 
49292
 
49293
 
49294
 
49295
 
49296
 
49297
 
49298
 
49299
 
49300
 
49301
 
49302
 
49303
 
49304
 
49305
 
49306
 
49307
 
49308
 
49309
 
49310
 
49311
 
49312
 
49313
 
49314
 
49315
 
49316
 
49317
 
49318
 
49319
 
49320
 
49321
 
49322
 
49323
 
49324
 
49325
 
49326
 
49327
 
49328
 
49329
 
49330
 
49331
 
49332
 
49333
 
49334
 
49335
 
49336
 
49337
 
49338
 
49339
 
49340
 
49341
 
49342
 
49343
 
49344
 
49345
 
49346
 
49347
 
49348
 
49349
 
49350
 
49351
 
49352
 
49353
 
49354
 
49355
 
49356
 
49357
 
49358
 
49359
 
49360
 
49361
 
49362
 
49363
 
49364
 
49365
 
49366
 
49367
 
49368
 
49369
 
49370
 
49371
 
49372
 
49373
 
49374
 
49375
 
49376
 
49377
 
49378
 
49379
 
49380
 
49381
 
49382
 
49383
 
49384
 
49385
 
49386
 
49387
 
49388
 
49389
 
49390
 
49391
 
49392
 
49393
 
49394
 
49395
 
49396
 
49397
 
49398
 
49399
 
49400
 
49401
 
49402
 
49403
 
49404
 
49405
 
49406
 
49407
 
49408
 
49409
 
49410
 
49411
 
49412
 
49413
 
49414
 
49415
 
49416
 
49417
 
49418
 
49419
 
49420
 
49421
 
49422
 
49423
 
49424
 
49425
 
49426
 
49427
 
49428
 
49429
 
49430
 
49431
 
49432
 
49433
 
49434
 
49435
 
49436
 
49437
 
49438
 
49439
 
49440
 
49441
 
49442
 
49443
 
49444
 
49445
 
49446
 
49447
 
49448
 
49449
 
49450
 
49451
 
49452
 
49453
 
49454
 
49455
 
49456
 
49457
 
49458
 
49459
 
49460
 
49461
 
49462
 
49463
 
49464
 
49465
 
49466
 
49467
 
49468
 
49469
 
49470
 
49471
 
49472
 
49473
 
49474
 
49475
 
49476
 
49477
 
49478
 
49479
 
49480
 
49481
 
49482
 
49483
 
49484
 
49485
 
49486
 
49487
 
49488
 
49489
 
49490
 
49491
 
49492
 
49493
 
49494
 
49495
 
49496
 
49497
 
49498
 
49499
 
49500
 
49501
 
49502
 
49503
 
49504
 
49505
 
49506
 
49507
 
49508
 
49509
 
49510
 
49511
 
49512
 
49513
 
49514
 
49515
 
49516
 
49517
 
49518
 
49519
 
49520
 
49521
 
49522
 
49523
 
49524
 
49525
 
49526
 
49527
 
49528
 
49529
 
49530
 
49531
 
49532
 
49533
 
49534
 
49535
 
49536
 
49537
 
49538
 
49539
 
49540
 
49541
 
49542
 
49543
 
49544
 
49545
 
49546
 
49547
 
49548
 
49549
 
49550
 
49551
 
49552
 
49553
 
49554
 
49555
 
49556
 
49557
 
49558
 
49559
 
49560
 
49561
 
49562
 
49563
 
49564
 
49565
 
49566
 
49567
 
49568
 
49569
 
49570
 
49571
 
49572
 
49573
 
49574
 
49575
 
49576
 
49577
 
49578
 
49579
 
49580
 
49581
 
49582
 
49583
 
49584
 
49585
 
49586
 
49587
 
49588
 
49589
 
49590
 
49591
 
49592
 
49593
 
49594
 
49595
 
49596
 
49597
 
49598
 
49599
 
49600
 
49601
 
49602
 
49603
 
49604
 
49605
 
49606
 
49607
 
49608
 
49609
 
49610
 
49611
 
49612
 
49613
 
49614
 
49615
 
49616
 
49617
 
49618
 
49619
 
49620
 
49621
 
49622
 
49623
 
49624
 
49625
 
49626
 
49627
 
49628
 
49629
 
49630
 
49631
 
49632
 
49633
 
49634
 
49635
 
49636
 
49637
 
49638
 
49639
 
49640
 
49641
 
49642
 
49643
 
49644
 
49645
 
49646
 
49647
 
49648
 
49649
 
49650
 
49651
 
49652
 
49653
 
49654
 
49655
 
49656
 
49657
 
49658
 
49659
 
49660
 
49661
 
49662
 
49663
 
49664
 
49665
 
49666
 
49667
 
49668
 
49669
 
49670
 
49671
 
49672
 
49673
 
49674
 
49675
 
49676
 
49677
 
49678
 
49679
 
49680
 
49681
 
49682
 
49683
 
49684
 
49685
 
49686
 
49687
 
49688
 
49689
 
49690
 
49691
 
49692
 
49693
 
49694
 
49695
 
49696
 
49697
 
49698
 
49699
 
49700
 
49701
 
49702
 
49703
 
49704
 
49705
 
49706
 
49707
 
49708
 
49709
 
49710
 
49711
 
49712
 
49713
 
49714
 
49715
 
49716
 
49717
 
49718
 
49719
 
49720
 
49721
 
49722
 
49723
 
49724
 
49725
 
49726
 
49727
 
49728
 
49729
 
49730
 
49731
 
49732
 
49733
 
49734
 
49735
 
49736
 
49737
 
49738
 
49739
 
49740
 
49741
 
49742
 
49743
 
49744
 
49745
 
49746
 
49747
 
49748
 
49749
 
49750
 
49751
 
49752
 
49753
 
49754
 
49755
 
49756
 
49757
 
49758
 
49759
 
49760
 
49761
 
49762
 
49763
 
49764
 
49765
 
49766
 
49767
 
49768
 
49769
 
49770
 
49771
 
49772
 
49773
 
49774
 
49775
 
49776
 
49777
 
49778
 
49779
 
49780
 
49781
 
49782
 
49783
 
49784
 
49785
 
49786
 
49787
 
49788
 
49789
 
49790
 
49791
 
49792
 
49793
 
49794
 
49795
 
49796
 
49797
 
49798
 
49799
 
49800
 
49801
 
49802
 
49803
 
49804
 
49805
 
49806
 
49807
 
49808
 
49809
 
49810
 
49811
 
49812
 
49813
 
49814
 
49815
 
49816
 
49817
 
49818
 
49819
 
49820
 
49821
 
49822
 
49823
 
49824
 
49825
 
49826
 
49827
 
49828
 
49829
 
49830
 
49831
 
49832
 
49833
 
49834
 
49835
 
49836
 
49837
 
49838
 
49839
 
49840
 
49841
 
49842
 
49843
 
49844
 
49845
 
49846
 
49847
 
49848
 
49849
 
49850
 
49851
 
49852
 
49853
 
49854
 
49855
 
49856
 
49857
 
49858
 
49859
 
49860
 
49861
 
49862
 
49863
 
49864
 
49865
 
49866
 
49867
 
49868
 
49869
 
49870
 
49871
 
49872
 
49873
 
49874
 
49875
 
49876
 
49877
 
49878
 
49879
 
49880
 
49881
 
49882
 
49883
 
49884
 
49885
 
49886
 
49887
 
49888
 
49889
 
49890
 
49891
 
49892
 
49893
 
49894
 
49895
 
49896
 
49897
 
49898
 
49899
 
49900
 
49901
 
49902
 
49903
 
49904
 
49905
 
49906
 
49907
 
49908
 
49909
 
49910
 
49911
 
49912
 
49913
 
49914
 
49915
 
49916
 
49917
 
49918
 
49919
 
49920
 
49921
 
49922
 
49923
 
49924
 
49925
 
49926
 
49927
 
49928
 
49929
 
49930
 
49931
 
49932
 
49933
 
49934
 
49935
 
49936
 
49937
 
49938
 
49939
 
49940
 
49941
 
49942
 
49943
 
49944
 
49945
 
49946
 
49947
 
49948
 
49949
 
49950
 
49951
 
49952
 
49953
 
49954
 
49955
 
49956
 
49957
 
49958
 
49959
 
49960
 
49961
 
49962
 
49963
 
49964
 
49965
 
49966
 
49967
 
49968
 
49969
 
49970
 
49971
 
49972
 
49973
 
49974
 
49975
 
49976
 
49977
 
49978
 
49979
 
49980
 
49981
 
49982
 
49983
 
49984
 
49985
 
49986
 
49987
 
49988
 
49989
 
49990
 
49991
 
49992
 
49993
 
49994
 
49995
 
49996
 
49997
 
49998
 
49999
 
50000
 
50001
 
50002
 
50003
 
50004
 
50005
 
50006
 
50007
 
50008
 
50009
 
50010
 
50011
 
50012
 
50013
 
50014
 
50015
 
50016
 
50017
 
50018
 
50019
 
50020
 
50021
 
50022
 
50023
 
50024
 
50025
 
50026
 
50027
 
50028
 
50029
 
50030
 
50031
 
50032
 
50033
 
50034
 
50035
 
50036
 
50037
 
50038
 
50039
 
50040
 
50041
 
50042
 
50043
 
50044
 
50045
 
50046
 
50047
 
50048
 
50049
 
50050
 
50051
 
50052
 
50053
 
50054
 
50055
 
50056
 
50057
 
50058
 
50059
 
50060
 
50061
 
50062
 
50063
 
50064
 
50065
 
50066
 
50067
 
50068
 
50069
 
50070
 
50071
 
50072
 
50073
 
50074
 
50075
 
50076
 
50077
 
50078
 
50079
 
50080
 
50081
 
50082
 
50083
 
50084
 
50085
 
50086
 
50087
 
50088
 
50089
 
50090
 
50091
 
50092
 
50093
 
50094
 
50095
 
50096
 
50097
 
50098
 
50099
 
50100
 
50101
 
50102
 
50103
 
50104
 
50105
 
50106
 
50107
 
50108
 
50109
 
50110
 
50111
 
50112
 
50113
 
50114
 
50115
 
50116
 
50117
 
50118
 
50119
 
50120
 
50121
 
50122
 
50123
 
50124
 
50125
 
50126
 
50127
 
50128
 
50129
 
50130
 
50131
 
50132
 
50133
 
50134
 
50135
 
50136
 
50137
 
50138
 
50139
 
50140
 
50141
 
50142
 
50143
 
50144
 
50145
 
50146
 
50147
 
50148
 
50149
 
50150
 
50151
 
50152
 
50153
 
50154
 
50155
 
50156
 
50157
 
50158
 
50159
 
50160
 
50161
 
50162
 
50163
 
50164
 
50165
 
50166
 
50167
 
50168
 
50169
 
50170
 
50171
 
50172
 
50173
 
50174
 
50175
 
50176
 
50177
 
50178
 
50179
 
50180
 
50181
 
50182
 
50183
 
50184
 
50185
 
50186
 
50187
 
50188
 
50189
 
50190
 
50191
 
50192
 
50193
 
50194
 
50195
 
50196
 
50197
 
50198
 
50199
 
50200
 
50201
 
50202
 
50203
 
50204
 
50205
 
50206
 
50207
 
50208
 
50209
 
50210
 
50211
 
50212
 
50213
 
50214
 
50215
 
50216
 
50217
 
50218
 
50219
 
50220
 
50221
 
50222
 
50223
 
50224
 
50225
 
50226
 
50227
 
50228
 
50229
 
50230
 
50231
 
50232
 
50233
 
50234
 
50235
 
50236
 
50237
 
50238
 
50239
 
50240
 
50241
 
50242
 
50243
 
50244
 
50245
 
50246
 
50247
 
50248
 
50249
 
50250
 
50251
 
50252
 
50253
 
50254
 
50255
 
50256
 
50257
 
50258
 
50259
 
50260
 
50261
 
50262
 
50263
 
50264
 
50265
 
50266
 
50267
 
50268
 
50269
 
50270
 
50271
 
50272
 
50273
 
50274
 
50275
 
50276
 
50277
 
50278
 
50279
 
50280
 
50281
 
50282
 
50283
 
50284
 
50285
 
50286
 
50287
 
50288
 
50289
 
50290
 
50291
 
50292
 
50293
 
50294
 
50295
 
50296
 
50297
 
50298
 
50299
 
50300
 
50301
 
50302
 
50303
 
50304
 
50305
 
50306
 
50307
 
50308
 
50309
 
50310
 
50311
 
50312
 
50313
 
50314
 
50315
 
50316
 
50317
 
50318
 
50319
 
50320
 
50321
 
50322
 
50323
 
50324
 
50325
 
50326
 
50327
 
50328
 
50329
 
50330
 
50331
 
50332
 
50333
 
50334
 
50335
 
50336
 
50337
 
50338
 
50339
 
50340
 
50341
 
50342
 
50343
 
50344
 
50345
 
50346
 
50347
 
50348
 
50349
 
50350
 
50351
 
50352
 
50353
 
50354
 
50355
 
50356
 
50357
 
50358
 
50359
 
50360
 
50361
 
50362
 
50363
 
50364
 
50365
 
50366
 
50367
 
50368
 
50369
 
50370
 
50371
 
50372
 
50373
 
50374
 
50375
 
50376
 
50377
 
50378
 
50379
 
50380
 
50381
 
50382
 
50383
 
50384
 
50385
 
50386
 
50387
 
50388
 
50389
 
50390
 
50391
 
50392
 
50393
 
50394
 
50395
 
50396
 
50397
 
50398
 
50399
 
50400
 
50401
 
50402
 
50403
 
50404
 
50405
 
50406
 
50407
 
50408
 
50409
 
50410
 
50411
 
50412
 
50413
 
50414
 
50415
 
50416
 
50417
 
50418
 
50419
 
50420
 
50421
 
50422
 
50423
 
50424
 
50425
 
50426
 
50427
 
50428
 
50429
 
50430
 
50431
 
50432
 
50433
 
50434
 
50435
 
50436
 
50437
 
50438
 
50439
 
50440
 
50441
 
50442
 
50443
 
50444
 
50445
 
50446
 
50447
 
50448
 
50449
 
50450
 
50451
 
50452
 
50453
 
50454
 
50455
 
50456
 
50457
 
50458
 
50459
 
50460
 
50461
 
50462
 
50463
 
50464
 
50465
 
50466
 
50467
 
50468
 
50469
 
50470
 
50471
 
50472
 
50473
 
50474
 
50475
 
50476
 
50477
 
50478
 
50479
 
50480
 
50481
 
50482
 
50483
 
50484
 
50485
 
50486
 
50487
 
50488
 
50489
 
50490
 
50491
 
50492
 
50493
 
50494
 
50495
 
50496
 
50497
 
50498
 
50499
 
50500
 
50501
 
50502
 
50503
 
50504
 
50505
 
50506
 
50507
 
50508
 
50509
 
50510
 
50511
 
50512
 
50513
 
50514
 
50515
 
50516
 
50517
 
50518
 
50519
 
50520
 
50521
 
50522
 
50523
 
50524
 
50525
 
50526
 
50527
 
50528
 
50529
 
50530
 
50531
 
50532
 
50533
 
50534
 
50535
 
50536
 
50537
 
50538
 
50539
 
50540
 
50541
 
50542
 
50543
 
50544
 
50545
 
50546
 
50547
 
50548
 
50549
 
50550
 
50551
 
50552
 
50553
 
50554
 
50555
 
50556
 
50557
 
50558
 
50559
 
50560
 
50561
 
50562
 
50563
 
50564
 
50565
 
50566
 
50567
 
50568
 
50569
 
50570
 
50571
 
50572
 
50573
 
50574
 
50575
 
50576
 
50577
 
50578
 
50579
 
50580
 
50581
 
50582
 
50583
 
50584
 
50585
 
50586
 
50587
 
50588
 
50589
 
50590
 
50591
 
50592
 
50593
 
50594
 
50595
 
50596
 
50597
 
50598
 
50599
 
50600
 
50601
 
50602
 
50603
 
50604
 
50605
 
50606
 
50607
 
50608
 
50609
 
50610
 
50611
 
50612
 
50613
 
50614
 
50615
 
50616
 
50617
 
50618
 
50619
 
50620
 
50621
 
50622
 
50623
 
50624
 
50625
 
50626
 
50627
 
50628
 
50629
 
50630
 
50631
 
50632
 
50633
 
50634
 
50635
 
50636
 
50637
 
50638
 
50639
 
50640
 
50641
 
50642
 
50643
 
50644
 
50645
 
50646
 
50647
 
50648
 
50649
 
50650
 
50651
 
50652
 
50653
 
50654
 
50655
 
50656
 
50657
 
50658
 
50659
 
50660
 
50661
 
50662
 
50663
 
50664
 
50665
 
50666
 
50667
 
50668
 
50669
 
50670
 
50671
 
50672
 
50673
 
50674
 
50675
 
50676
 
50677
 
50678
 
50679
 
50680
 
50681
 
50682
 
50683
 
50684
 
50685
 
50686
 
50687
 
50688
 
50689
 
50690
 
50691
 
50692
 
50693
 
50694
 
50695
 
50696
 
50697
 
50698
 
50699
 
50700
 
50701
 
50702
 
50703
 
50704
 
50705
 
50706
 
50707
 
50708
 
50709
 
50710
 
50711
 
50712
 
50713
 
50714
 
50715
 
50716
 
50717
 
50718
 
50719
 
50720
 
50721
 
50722
 
50723
 
50724
 
50725
 
50726
 
50727
 
50728
 
50729
 
50730
 
50731
 
50732
 
50733
 
50734
 
50735
 
50736
 
50737
 
50738
 
50739
 
50740
 
50741
 
50742
 
50743
 
50744
 
50745
 
50746
 
50747
 
50748
 
50749
 
50750
 
50751
 
50752
 
50753
 
50754
 
50755
 
50756
 
50757
 
50758
 
50759
 
50760
 
50761
 
50762
 
50763
 
50764
 
50765
 
50766
 
50767
 
50768
 
50769
 
50770
 
50771
 
50772
 
50773
 
50774
 
50775
 
50776
 
50777
 
50778
 
50779
 
50780
 
50781
 
50782
 
50783
 
50784
 
50785
 
50786
 
50787
 
50788
 
50789
 
50790
 
50791
 
50792
 
50793
 
50794
 
50795
 
50796
 
50797
 
50798
 
50799
 
50800
 
50801
 
50802
 
50803
 
50804
 
50805
 
50806
 
50807
 
50808
 
50809
 
50810
 
50811
 
50812
 
50813
 
50814
 
50815
 
50816
 
50817
 
50818
 
50819
 
50820
 
50821
 
50822
 
50823
 
50824
 
50825
 
50826
 
50827
 
50828
 
50829
 
50830
 
50831
 
50832
 
50833
 
50834
 
50835
 
50836
 
50837
 
50838
 
50839
 
50840
 
50841
 
50842
 
50843
 
50844
 
50845
 
50846
 
50847
 
50848
 
50849
 
50850
 
50851
 
50852
 
50853
 
50854
 
50855
 
50856
 
50857
 
50858
 
50859
 
50860
 
50861
 
50862
 
50863
 
50864
 
50865
 
50866
 
50867
 
50868
 
50869
 
50870
 
50871
 
50872
 
50873
 
50874
 
50875
 
50876
 
50877
 
50878
 
50879
 
50880
 
50881
 
50882
 
50883
 
50884
 
50885
 
50886
 
50887
 
50888
 
50889
 
50890
 
50891
 
50892
 
50893
 
50894
 
50895
 
50896
 
50897
 
50898
 
50899
 
50900
 
50901
 
50902
 
50903
 
50904
 
50905
 
50906
 
50907
 
50908
 
50909
 
50910
 
50911
 
50912
 
50913
 
50914
 
50915
 
50916
 
50917
 
50918
 
50919
 
50920
 
50921
 
50922
 
50923
 
50924
 
50925
 
50926
 
50927
 
50928
 
50929
 
50930
 
50931
 
50932
 
50933
 
50934
 
50935
 
50936
 
50937
 
50938
 
50939
 
50940
 
50941
 
50942
 
50943
 
50944
 
50945
 
50946
 
50947
 
50948
 
50949
 
50950
 
50951
 
50952
 
50953
 
50954
 
50955
 
50956
 
50957
 
50958
 
50959
 
50960
 
50961
 
50962
 
50963
 
50964
 
50965
 
50966
 
50967
 
50968
 
50969
 
50970
 
50971
 
50972
 
50973
 
50974
 
50975
 
50976
 
50977
 
50978
 
50979
 
50980
 
50981
 
50982
 
50983
 
50984
 
50985
 
50986
 
50987
 
50988
 
50989
 
50990
 
50991
 
50992
 
50993
 
50994
 
50995
 
50996
 
50997
 
50998
 
50999
 
51000
 
51001
 
51002
 
51003
 
51004
 
51005
 
51006
 
51007
 
51008
 
51009
 
51010
 
51011
 
51012
 
51013
 
51014
 
51015
 
51016
 
51017
 
51018
 
51019
 
51020
 
51021
 
51022
 
51023
 
51024
 
51025
 
51026
 
51027
 
51028
 
51029
 
51030
 
51031
 
51032
 
51033
 
51034
 
51035
 
51036
 
51037
 
51038
 
51039
 
51040
 
51041
 
51042
 
51043
 
51044
 
51045
 
51046
 
51047
 
51048
 
51049
 
51050
 
51051
 
51052
 
51053
 
51054
 
51055
 
51056
 
51057
 
51058
 
51059
 
51060
 
51061
 
51062
 
51063
 
51064
 
51065
 
51066
 
51067
 
51068
 
51069
 
51070
 
51071
 
51072
 
51073
 
51074
 
51075
 
51076
 
51077
 
51078
 
51079
 
51080
 
51081
 
51082
 
51083
 
51084
 
51085
 
51086
 
51087
 
51088
 
51089
 
51090
 
51091
 
51092
 
51093
 
51094
 
51095
 
51096
 
51097
 
51098
 
51099
 
51100
 
51101
 
51102
 
51103
 
51104
 
51105
 
51106
 
51107
 
51108
 
51109
 
51110
 
51111
 
51112
 
51113
 
51114
 
51115
 
51116
 
51117
 
51118
 
51119
 
51120
 
51121
 
51122
 
51123
 
51124
 
51125
 
51126
 
51127
 
51128
 
51129
 
51130
 
51131
 
51132
 
51133
 
51134
 
51135
 
51136
 
51137
 
51138
 
51139
 
51140
 
51141
 
51142
 
51143
 
51144
 
51145
 
51146
 
51147
 
51148
 
51149
 
51150
 
51151
 
51152
 
51153
 
51154
 
51155
 
51156
 
51157
 
51158
 
51159
 
51160
 
51161
 
51162
 
51163
 
51164
 
51165
 
51166
 
51167
 
51168
 
51169
 
51170
 
51171
 
51172
 
51173
 
51174
 
51175
 
51176
 
51177
 
51178
 
51179
 
51180
 
51181
 
51182
 
51183
 
51184
 
51185
 
51186
 
51187
 
51188
 
51189
 
51190
 
51191
 
51192
 
51193
 
51194
 
51195
 
51196
 
51197
 
51198
 
51199
 
51200
 
51201
 
51202
 
51203
 
51204
 
51205
 
51206
 
51207
 
51208
 
51209
 
51210
 
51211
 
51212
 
51213
 
51214
 
51215
 
51216
 
51217
 
51218
 
51219
 
51220
 
51221
 
51222
 
51223
 
51224
 
51225
 
51226
 
51227
 
51228
 
51229
 
51230
 
51231
 
51232
 
51233
 
51234
 
51235
 
51236
 
51237
 
51238
 
51239
 
51240
 
51241
 
51242
 
51243
 
51244
 
51245
 
51246
 
51247
 
51248
 
51249
 
51250
 
51251
 
51252
 
51253
 
51254
 
51255
 
51256
 
51257
 
51258
 
51259
 
51260
 
51261
 
51262
 
51263
 
51264
 
51265
 
51266
 
51267
 
51268
 
51269
 
51270
 
51271
 
51272
 
51273
 
51274
 
51275
 
51276
 
51277
 
51278
 
51279
 
51280
 
51281
 
51282
 
51283
 
51284
 
51285
 
51286
 
51287
 
51288
 
51289
 
51290
 
51291
 
51292
 
51293
 
51294
 
51295
 
51296
 
51297
 
51298
 
51299
 
51300
 
51301
 
51302
 
51303
 
51304
 
51305
 
51306
 
51307
 
51308
 
51309
 
51310
 
51311
 
51312
 
51313
 
51314
 
51315
 
51316
 
51317
 
51318
 
51319
 
51320
 
51321
 
51322
 
51323
 
51324
 
51325
 
51326
 
51327
 
51328
 
51329
 
51330
 
51331
 
51332
 
51333
 
51334
 
51335
 
51336
 
51337
 
51338
 
51339
 
51340
 
51341
 
51342
 
51343
 
51344
 
51345
 
51346
 
51347
 
51348
 
51349
 
51350
 
51351
 
51352
 
51353
 
51354
 
51355
 
51356
 
51357
 
51358
 
51359
 
51360
 
51361
 
51362
 
51363
 
51364
 
51365
 
51366
 
51367
 
51368
 
51369
 
51370
 
51371
 
51372
 
51373
 
51374
 
51375
 
51376
 
51377
 
51378
 
51379
 
51380
 
51381
 
51382
 
51383
 
51384
 
51385
 
51386
 
51387
 
51388
 
51389
 
51390
 
51391
 
51392
 
51393
 
51394
 
51395
 
51396
 
51397
 
51398
 
51399
 
51400
 
51401
 
51402
 
51403
 
51404
 
51405
 
51406
 
51407
 
51408
 
51409
 
51410
 
51411
 
51412
 
51413
 
51414
 
51415
 
51416
 
51417
 
51418
 
51419
 
51420
 
51421
 
51422
 
51423
 
51424
 
51425
 
51426
 
51427
 
51428
 
51429
 
51430
 
51431
 
51432
 
51433
 
51434
 
51435
 
51436
 
51437
 
51438
 
51439
 
51440
 
51441
 
51442
 
51443
 
51444
 
51445
 
51446
 
51447
 
51448
 
51449
 
51450
 
51451
 
51452
 
51453
 
51454
 
51455
 
51456
 
51457
 
51458
 
51459
 
51460
 
51461
 
51462
 
51463
 
51464
 
51465
 
51466
 
51467
 
51468
 
51469
 
51470
 
51471
 
51472
 
51473
 
51474
 
51475
 
51476
 
51477
 
51478
 
51479
 
51480
 
51481
 
51482
 
51483
 
51484
 
51485
 
51486
 
51487
 
51488
 
51489
 
51490
 
51491
 
51492
 
51493
 
51494
 
51495
 
51496
 
51497
 
51498
 
51499
 
51500
 
51501
 
51502
 
51503
 
51504
 
51505
 
51506
 
51507
 
51508
 
51509
 
51510
 
51511
 
51512
 
51513
 
51514
 
51515
 
51516
 
51517
 
51518
 
51519
 
51520
 
51521
 
51522
 
51523
 
51524
 
51525
 
51526
 
51527
 
51528
 
51529
 
51530
 
51531
 
51532
 
51533
 
51534
 
51535
 
51536
 
51537
 
51538
 
51539
 
51540
 
51541
 
51542
 
51543
 
51544
 
51545
 
51546
 
51547
 
51548
 
51549
 
51550
 
51551
 
51552
 
51553
 
51554
 
51555
 
51556
 
51557
 
51558
 
51559
 
51560
 
51561
 
51562
 
51563
 
51564
 
51565
 
51566
 
51567
 
51568
 
51569
 
51570
 
51571
 
51572
 
51573
 
51574
 
51575
 
51576
 
51577
 
51578
 
51579
 
51580
 
51581
 
51582
 
51583
 
51584
 
51585
 
51586
 
51587
 
51588
 
51589
 
51590
 
51591
 
51592
 
51593
 
51594
 
51595
 
51596
 
51597
 
51598
 
51599
 
51600
 
51601
 
51602
 
51603
 
51604
 
51605
 
51606
 
51607
 
51608
 
51609
 
51610
 
51611
 
51612
 
51613
 
51614
 
51615
 
51616
 
51617
 
51618
 
51619
 
51620
 
51621
 
51622
 
51623
 
51624
 
51625
 
51626
 
51627
 
51628
 
51629
 
51630
 
51631
 
51632
 
51633
 
51634
 
51635
 
51636
 
51637
 
51638
 
51639
 
51640
 
51641
 
51642
 
51643
 
51644
 
51645
 
51646
 
51647
 
51648
 
51649
 
51650
 
51651
 
51652
 
51653
 
51654
 
51655
 
51656
 
51657
 
51658
 
51659
 
51660
 
51661
 
51662
 
51663
 
51664
 
51665
 
51666
 
51667
 
51668
 
51669
 
51670
 
51671
 
51672
 
51673
 
51674
 
51675
 
51676
 
51677
 
51678
 
51679
 
51680
 
51681
 
51682
 
51683
 
51684
 
51685
 
51686
 
51687
 
51688
 
51689
 
51690
 
51691
 
51692
 
51693
 
51694
 
51695
 
51696
 
51697
 
51698
 
51699
 
51700
 
51701
 
51702
 
51703
 
51704
 
51705
 
51706
 
51707
 
51708
 
51709
 
51710
 
51711
 
51712
 
51713
 
51714
 
51715
 
51716
 
51717
 
51718
 
51719
 
51720
 
51721
 
51722
 
51723
 
51724
 
51725
 
51726
 
51727
 
51728
 
51729
 
51730
 
51731
 
51732
 
51733
 
51734
 
51735
 
51736
 
51737
 
51738
 
51739
 
51740
 
51741
 
51742
 
51743
 
51744
 
51745
 
51746
 
51747
 
51748
 
51749
 
51750
 
51751
 
51752
 
51753
 
51754
 
51755
 
51756
 
51757
 
51758
 
51759
 
51760
 
51761
 
51762
 
51763
 
51764
 
51765
 
51766
 
51767
 
51768
 
51769
 
51770
 
51771
 
51772
 
51773
 
51774
 
51775
 
51776
 
51777
 
51778
 
51779
 
51780
 
51781
 
51782
 
51783
 
51784
 
51785
 
51786
 
51787
 
51788
 
51789
 
51790
 
51791
 
51792
 
51793
 
51794
 
51795
 
51796
 
51797
 
51798
 
51799
 
51800
 
51801
 
51802
 
51803
 
51804
 
51805
 
51806
 
51807
 
51808
 
51809
 
51810
 
51811
 
51812
 
51813
 
51814
 
51815
 
51816
 
51817
 
51818
 
51819
 
51820
 
51821
 
51822
 
51823
 
51824
 
51825
 
51826
 
51827
 
51828
 
51829
 
51830
 
51831
 
51832
 
51833
 
51834
 
51835
 
51836
 
51837
 
51838
 
51839
 
51840
 
51841
 
51842
 
51843
 
51844
 
51845
 
51846
 
51847
 
51848
 
51849
 
51850
 
51851
 
51852
 
51853
 
51854
 
51855
 
51856
 
51857
 
51858
 
51859
 
51860
 
51861
 
51862
 
51863
 
51864
 
51865
 
51866
 
51867
 
51868
 
51869
 
51870
 
51871
 
51872
 
51873
 
51874
 
51875
 
51876
 
51877
 
51878
 
51879
 
51880
 
51881
 
51882
 
51883
 
51884
 
51885
 
51886
 
51887
 
51888
 
51889
 
51890
 
51891
 
51892
 
51893
 
51894
 
51895
 
51896
 
51897
 
51898
 
51899
 
51900
 
51901
 
51902
 
51903
 
51904
 
51905
 
51906
 
51907
 
51908
 
51909
 
51910
 
51911
 
51912
 
51913
 
51914
 
51915
 
51916
 
51917
 
51918
 
51919
 
51920
 
51921
 
51922
 
51923
 
51924
 
51925
 
51926
 
51927
 
51928
 
51929
 
51930
 
51931
 
51932
 
51933
 
51934
 
51935
 
51936
 
51937
 
51938
 
51939
 
51940
 
51941
 
51942
 
51943
 
51944
 
51945
 
51946
 
51947
 
51948
 
51949
 
51950
 
51951
 
51952
 
51953
 
51954
 
51955
 
51956
 
51957
 
51958
 
51959
 
51960
 
51961
 
51962
 
51963
 
51964
 
51965
 
51966
 
51967
 
51968
 
51969
 
51970
 
51971
 
51972
 
51973
 
51974
 
51975
 
51976
 
51977
 
51978
 
51979
 
51980
 
51981
 
51982
 
51983
 
51984
 
51985
 
51986
 
51987
 
51988
 
51989
 
51990
 
51991
 
51992
 
51993
 
51994
 
51995
 
51996
 
51997
 
51998
 
51999
 
52000
 
52001
 
52002
 
52003
 
52004
 
52005
 
52006
 
52007
 
52008
 
52009
 
52010
 
52011
 
52012
 
52013
 
52014
 
52015
 
52016
 
52017
 
52018
 
52019
 
52020
 
52021
 
52022
 
52023
 
52024
 
52025
 
52026
 
52027
 
52028
 
52029
 
52030
 
52031
 
52032
 
52033
 
52034
 
52035
 
52036
 
52037
 
52038
 
52039
 
52040
 
52041
 
52042
 
52043
 
52044
 
52045
 
52046
 
52047
 
52048
 
52049
 
52050
 
52051
 
52052
 
52053
 
52054
 
52055
 
52056
 
52057
 
52058
 
52059
 
52060
 
52061
 
52062
 
52063
 
52064
 
52065
 
52066
 
52067
 
52068
 
52069
 
52070
 
52071
 
52072
 
52073
 
52074
 
52075
 
52076
 
52077
 
52078
 
52079
 
52080
 
52081
 
52082
 
52083
 
52084
 
52085
 
52086
 
52087
 
52088
 
52089
 
52090
 
52091
 
52092
 
52093
 
52094
 
52095
 
52096
 
52097
 
52098
 
52099
 
52100
 
52101
 
52102
 
52103
 
52104
 
52105
 
52106
 
52107
 
52108
 
52109
 
52110
 
52111
 
52112
 
52113
 
52114
 
52115
 
52116
 
52117
 
52118
 
52119
 
52120
 
52121
 
52122
 
52123
 
52124
 
52125
 
52126
 
52127
 
52128
 
52129
 
52130
 
52131
 
52132
 
52133
 
52134
 
52135
 
52136
 
52137
 
52138
 
52139
 
52140
 
52141
 
52142
 
52143
 
52144
 
52145
 
52146
 
52147
 
52148
 
52149
 
52150
 
52151
 
52152
 
52153
 
52154
 
52155
 
52156
 
52157
 
52158
 
52159
 
52160
 
52161
 
52162
 
52163
 
52164
 
52165
 
52166
 
52167
 
52168
 
52169
 
52170
 
52171
 
52172
 
52173
 
52174
 
52175
 
52176
 
52177
 
52178
 
52179
 
52180
 
52181
 
52182
 
52183
 
52184
 
52185
 
52186
 
52187
 
52188
 
52189
 
52190
 
52191
 
52192
 
52193
 
52194
 
52195
 
52196
 
52197
 
52198
 
52199
 
52200
 
52201
 
52202
 
52203
 
52204
 
52205
 
52206
 
52207
 
52208
 
52209
 
52210
 
52211
 
52212
 
52213
 
52214
 
52215
 
52216
 
52217
 
52218
 
52219
 
52220
 
52221
 
52222
 
52223
 
52224
 
52225
 
52226
 
52227
 
52228
 
52229
 
52230
 
52231
 
52232
 
52233
 
52234
 
52235
 
52236
 
52237
 
52238
 
52239
 
52240
 
52241
 
52242
 
52243
 
52244
 
52245
 
52246
 
52247
 
52248
 
52249
 
52250
 
52251
 
52252
 
52253
 
52254
 
52255
 
52256
 
52257
 
52258
 
52259
 
52260
 
52261
 
52262
 
52263
 
52264
 
52265
 
52266
 
52267
 
52268
 
52269
 
52270
 
52271
 
52272
 
52273
 
52274
 
52275
 
52276
 
52277
 
52278
 
52279
 
52280
 
52281
 
52282
 
52283
 
52284
 
52285
 
52286
 
52287
 
52288
 
52289
 
52290
 
52291
 
52292
 
52293
 
52294
 
52295
 
52296
 
52297
 
52298
 
52299
 
52300
 
52301
 
52302
 
52303
 
52304
 
52305
 
52306
 
52307
 
52308
 
52309
 
52310
 
52311
 
52312
 
52313
 
52314
 
52315
 
52316
 
52317
 
52318
 
52319
 
52320
 
52321
 
52322
 
52323
 
52324
 
52325
 
52326
 
52327
 
52328
 
52329
 
52330
 
52331
 
52332
 
52333
 
52334
 
52335
 
52336
 
52337
 
52338
 
52339
 
52340
 
52341
 
52342
 
52343
 
52344
 
52345
 
52346
 
52347
 
52348
 
52349
 
52350
 
52351
 
52352
 
52353
 
52354
 
52355
 
52356
 
52357
 
52358
 
52359
 
52360
 
52361
 
52362
 
52363
 
52364
 
52365
 
52366
 
52367
 
52368
 
52369
 
52370
 
52371
 
52372
 
52373
 
52374
 
52375
 
52376
 
52377
 
52378
 
52379
 
52380
 
52381
 
52382
 
52383
 
52384
 
52385
 
52386
 
52387
 
52388
 
52389
 
52390
 
52391
 
52392
 
52393
 
52394
 
52395
 
52396
 
52397
 
52398
 
52399
 
52400
 
52401
 
52402
 
52403
 
52404
 
52405
 
52406
 
52407
 
52408
 
52409
 
52410
 
52411
 
52412
 
52413
 
52414
 
52415
 
52416
 
52417
 
52418
 
52419
 
52420
 
52421
 
52422
 
52423
 
52424
 
52425
 
52426
 
52427
 
52428
 
52429
 
52430
 
52431
 
52432
 
52433
 
52434
 
52435
 
52436
 
52437
 
52438
 
52439
 
52440
 
52441
 
52442
 
52443
 
52444
 
52445
 
52446
 
52447
 
52448
 
52449
 
52450
 
52451
 
52452
 
52453
 
52454
 
52455
 
52456
 
52457
 
52458
 
52459
 
52460
 
52461
 
52462
 
52463
 
52464
 
52465
 
52466
 
52467
 
52468
 
52469
 
52470
 
52471
 
52472
 
52473
 
52474
 
52475
 
52476
 
52477
 
52478
 
52479
 
52480
 
52481
 
52482
 
52483
 
52484
 
52485
 
52486
 
52487
 
52488
 
52489
 
52490
 
52491
 
52492
 
52493
 
52494
 
52495
 
52496
 
52497
 
52498
 
52499
 
52500
 
52501
 
52502
 
52503
 
52504
 
52505
 
52506
 
52507
 
52508
 
52509
 
52510
 
52511
 
52512
 
52513
 
52514
 
52515
 
52516
 
52517
 
52518
 
52519
 
52520
 
52521
 
52522
 
52523
 
52524
 
52525
 
52526
 
52527
 
52528
 
52529
 
52530
 
52531
 
52532
 
52533
 
52534
 
52535
 
52536
 
52537
 
52538
 
52539
 
52540
 
52541
 
52542
 
52543
 
52544
 
52545
 
52546
 
52547
 
52548
 
52549
 
52550
 
52551
 
52552
 
52553
 
52554
 
52555
 
52556
 
52557
 
52558
 
52559
 
52560
 
52561
 
52562
 
52563
 
52564
 
52565
 
52566
 
52567
 
52568
 
52569
 
52570
 
52571
 
52572
 
52573
 
52574
 
52575
 
52576
 
52577
 
52578
 
52579
 
52580
 
52581
 
52582
 
52583
 
52584
 
52585
 
52586
 
52587
 
52588
 
52589
 
52590
 
52591
 
52592
 
52593
 
52594
 
52595
 
52596
 
52597
 
52598
 
52599
 
52600
 
52601
 
52602
 
52603
 
52604
 
52605
 
52606
 
52607
 
52608
 
52609
 
52610
 
52611
 
52612
 
52613
 
52614
 
52615
 
52616
 
52617
 
52618
 
52619
 
52620
 
52621
 
52622
 
52623
 
52624
 
52625
 
52626
 
52627
 
52628
 
52629
 
52630
 
52631
 
52632
 
52633
 
52634
 
52635
 
52636
 
52637
 
52638
 
52639
 
52640
 
52641
 
52642
 
52643
 
52644
 
52645
 
52646
 
52647
 
52648
 
52649
 
52650
 
52651
 
52652
 
52653
 
52654
 
52655
 
52656
 
52657
 
52658
 
52659
 
52660
 
52661
 
52662
 
52663
 
52664
 
52665
 
52666
 
52667
 
52668
 
52669
 
52670
 
52671
 
52672
 
52673
 
52674
 
52675
 
52676
 
52677
 
52678
 
52679
 
52680
 
52681
 
52682
 
52683
 
52684
 
52685
 
52686
 
52687
 
52688
 
52689
 
52690
 
52691
 
52692
 
52693
 
52694
 
52695
 
52696
 
52697
 
52698
 
52699
 
52700
 
52701
 
52702
 
52703
 
52704
 
52705
 
52706
 
52707
 
52708
 
52709
 
52710
 
52711
 
52712
 
52713
 
52714
 
52715
 
52716
 
52717
 
52718
 
52719
 
52720
 
52721
 
52722
 
52723
 
52724
 
52725
 
52726
 
52727
 
52728
 
52729
 
52730
 
52731
 
52732
 
52733
 
52734
 
52735
 
52736
 
52737
 
52738
 
52739
 
52740
 
52741
 
52742
 
52743
 
52744
 
52745
 
52746
 
52747
 
52748
 
52749
 
52750
 
52751
 
52752
 
52753
 
52754
 
52755
 
52756
 
52757
 
52758
 
52759
 
52760
 
52761
 
52762
 
52763
 
52764
 
52765
 
52766
 
52767
 
52768
 
52769
 
52770
 
52771
 
52772
 
52773
 
52774
 
52775
 
52776
 
52777
 
52778
 
52779
 
52780
 
52781
 
52782
 
52783
 
52784
 
52785
 
52786
 
52787
 
52788
 
52789
 
52790
 
52791
 
52792
 
52793
 
52794
 
52795
 
52796
 
52797
 
52798
 
52799
 
52800
 
52801
 
52802
 
52803
 
52804
 
52805
 
52806
 
52807
 
52808
 
52809
 
52810
 
52811
 
52812
 
52813
 
52814
 
52815
 
52816
 
52817
 
52818
 
52819
 
52820
 
52821
 
52822
 
52823
 
52824
 
52825
 
52826
 
52827
 
52828
 
52829
 
52830
 
52831
 
52832
 
52833
 
52834
 
52835
 
52836
 
52837
 
52838
 
52839
 
52840
 
52841
 
52842
 
52843
 
52844
 
52845
 
52846
 
52847
 
52848
 
52849
 
52850
 
52851
 
52852
 
52853
 
52854
 
52855
 
52856
 
52857
 
52858
 
52859
 
52860
 
52861
 
52862
 
52863
 
52864
 
52865
 
52866
 
52867
 
52868
 
52869
 
52870
 
52871
 
52872
 
52873
 
52874
 
52875
 
52876
 
52877
 
52878
 
52879
 
52880
 
52881
 
52882
 
52883
 
52884
 
52885
 
52886
 
52887
 
52888
 
52889
 
52890
 
52891
 
52892
 
52893
 
52894
 
52895
 
52896
 
52897
 
52898
 
52899
 
52900
 
52901
 
52902
 
52903
 
52904
 
52905
 
52906
 
52907
 
52908
 
52909
 
52910
 
52911
 
52912
 
52913
 
52914
 
52915
 
52916
 
52917
 
52918
 
52919
 
52920
 
52921
 
52922
 
52923
 
52924
 
52925
 
52926
 
52927
 
52928
 
52929
 
52930
 
52931
 
52932
 
52933
 
52934
 
52935
 
52936
 
52937
 
52938
 
52939
 
52940
 
52941
 
52942
 
52943
 
52944
 
52945
 
52946
 
52947
 
52948
 
52949
 
52950
 
52951
 
52952
 
52953
 
52954
 
52955
 
52956
 
52957
 
52958
 
52959
 
52960
 
52961
 
52962
 
52963
 
52964
 
52965
 
52966
 
52967
 
52968
 
52969
 
52970
 
52971
 
52972
 
52973
 
52974
 
52975
 
52976
 
52977
 
52978
 
52979
 
52980
 
52981
 
52982
 
52983
 
52984
 
52985
 
52986
 
52987
 
52988
 
52989
 
52990
 
52991
 
52992
 
52993
 
52994
 
52995
 
52996
 
52997
 
52998
 
52999
 
53000
 
53001
 
53002
 
53003
 
53004
 
53005
 
53006
 
53007
 
53008
 
53009
 
53010
 
53011
 
53012
 
53013
 
53014
 
53015
 
53016
 
53017
 
53018
 
53019
 
53020
 
53021
 
53022
 
53023
 
53024
 
53025
 
53026
 
53027
 
53028
 
53029
 
53030
 
53031
 
53032
 
53033
 
53034
 
53035
 
53036
 
53037
 
53038
 
53039
 
53040
 
53041
 
53042
 
53043
 
53044
 
53045
 
53046
 
53047
 
53048
 
53049
 
53050
 
53051
 
53052
 
53053
 
53054
 
53055
 
53056
 
53057
 
53058
 
53059
 
53060
 
53061
 
53062
 
53063
 
53064
 
53065
 
53066
 
53067
 
53068
 
53069
 
53070
 
53071
 
53072
 
53073
 
53074
 
53075
 
53076
 
53077
 
53078
 
53079
 
53080
 
53081
 
53082
 
53083
 
53084
 
53085
 
53086
 
53087
 
53088
 
53089
 
53090
 
53091
 
53092
 
53093
 
53094
 
53095
 
53096
 
53097
 
53098
 
53099
 
53100
 
53101
 
53102
 
53103
 
53104
 
53105
 
53106
 
53107
 
53108
 
53109
 
53110
 
53111
 
53112
 
53113
 
53114
 
53115
 
53116
 
53117
 
53118
 
53119
 
53120
 
53121
 
53122
 
53123
 
53124
 
53125
 
53126
 
53127
 
53128
 
53129
 
53130
 
53131
 
53132
 
53133
 
53134
 
53135
 
53136
 
53137
 
53138
 
53139
 
53140
 
53141
 
53142
 
53143
 
53144
 
53145
 
53146
 
53147
 
53148
 
53149
 
53150
 
53151
 
53152
 
53153
 
53154
 
53155
 
53156
 
53157
 
53158
 
53159
 
53160
 
53161
 
53162
 
53163
 
53164
 
53165
 
53166
 
53167
 
53168
 
53169
 
53170
 
53171
 
53172
 
53173
 
53174
 
53175
 
53176
 
53177
 
53178
 
53179
 
53180
 
53181
 
53182
 
53183
 
53184
 
53185
 
53186
 
53187
 
53188
 
53189
 
53190
 
53191
 
53192
 
53193
 
53194
 
53195
 
53196
 
53197
 
53198
 
53199
 
53200
 
53201
 
53202
 
53203
 
53204
 
53205
 
53206
 
53207
 
53208
 
53209
 
53210
 
53211
 
53212
 
53213
 
53214
 
53215
 
53216
 
53217
 
53218
 
53219
 
53220
 
53221
 
53222
 
53223
 
53224
 
53225
 
53226
 
53227
 
53228
 
53229
 
53230
 
53231
 
53232
 
53233
 
53234
 
53235
 
53236
 
53237
 
53238
 
53239
 
53240
 
53241
 
53242
 
53243
 
53244
 
53245
 
53246
 
53247
 
53248
 
53249
 
53250
 
53251
 
53252
 
53253
 
53254
 
53255
 
53256
 
53257
 
53258
 
53259
 
53260
 
53261
 
53262
 
53263
 
53264
 
53265
 
53266
 
53267
 
53268
 
53269
 
53270
 
53271
 
53272
 
53273
 
53274
 
53275
 
53276
 
53277
 
53278
 
53279
 
53280
 
53281
 
53282
 
53283
 
53284
 
53285
 
53286
 
53287
 
53288
 
53289
 
53290
 
53291
 
53292
 
53293
 
53294
 
53295
 
53296
 
53297
 
53298
 
53299
 
53300
 
53301
 
53302
 
53303
 
53304
 
53305
 
53306
 
53307
 
53308
 
53309
 
53310
 
53311
 
53312
 
53313
 
53314
 
53315
 
53316
 
53317
 
53318
 
53319
 
53320
 
53321
 
53322
 
53323
 
53324
 
53325
 
53326
 
53327
 
53328
 
53329
 
53330
 
53331
 
53332
 
53333
 
53334
 
53335
 
53336
 
53337
 
53338
 
53339
 
53340
 
53341
 
53342
 
53343
 
53344
 
53345
 
53346
 
53347
 
53348
 
53349
 
53350
 
53351
 
53352
 
53353
 
53354
 
53355
 
53356
 
53357
 
53358
 
53359
 
53360
 
53361
 
53362
 
53363
 
53364
 
53365
 
53366
 
53367
 
53368
 
53369
 
53370
 
53371
 
53372
 
53373
 
53374
 
53375
 
53376
 
53377
 
53378
 
53379
 
53380
 
53381
 
53382
 
53383
 
53384
 
53385
 
53386
 
53387
 
53388
 
53389
 
53390
 
53391
 
53392
 
53393
 
53394
 
53395
 
53396
 
53397
 
53398
 
53399
 
53400
 
53401
 
53402
 
53403
 
53404
 
53405
 
53406
 
53407
 
53408
 
53409
 
53410
 
53411
 
53412
 
53413
 
53414
 
53415
 
53416
 
53417
 
53418
 
53419
 
53420
 
53421
 
53422
 
53423
 
53424
 
53425
 
53426
 
53427
 
53428
 
53429
 
53430
 
53431
 
53432
 
53433
 
53434
 
53435
 
53436
 
53437
 
53438
 
53439
 
53440
 
53441
 
53442
 
53443
 
53444
 
53445
 
53446
 
53447
 
53448
 
53449
 
53450
 
53451
 
53452
 
53453
 
53454
 
53455
 
53456
 
53457
 
53458
 
53459
 
53460
 
53461
 
53462
 
53463
 
53464
 
53465
 
53466
 
53467
 
53468
 
53469
 
53470
 
53471
 
53472
 
53473
 
53474
 
53475
 
53476
 
53477
 
53478
 
53479
 
53480
 
53481
 
53482
 
53483
 
53484
 
53485
 
53486
 
53487
 
53488
 
53489
 
53490
 
53491
 
53492
 
53493
 
53494
 
53495
 
53496
 
53497
 
53498
 
53499
 
53500
 
53501
 
53502
 
53503
 
53504
 
53505
 
53506
 
53507
 
53508
 
53509
 
53510
 
53511
 
53512
 
53513
 
53514
 
53515
 
53516
 
53517
 
53518
 
53519
 
53520
 
53521
 
53522
 
53523
 
53524
 
53525
 
53526
 
53527
 
53528
 
53529
 
53530
 
53531
 
53532
 
53533
 
53534
 
53535
 
53536
 
53537
 
53538
 
53539
 
53540
 
53541
 
53542
 
53543
 
53544
 
53545
 
53546
 
53547
 
53548
 
53549
 
53550
 
53551
 
53552
 
53553
 
53554
 
53555
 
53556
 
53557
 
53558
 
53559
 
53560
 
53561
 
53562
 
53563
 
53564
 
53565
 
53566
 
53567
 
53568
 
53569
 
53570
 
53571
 
53572
 
53573
 
53574
 
53575
 
53576
 
53577
 
53578
 
53579
 
53580
 
53581
 
53582
 
53583
 
53584
 
53585
 
53586
 
53587
 
53588
 
53589
 
53590
 
53591
 
53592
 
53593
 
53594
 
53595
 
53596
 
53597
 
53598
 
53599
 
53600
 
53601
 
53602
 
53603
 
53604
 
53605
 
53606
 
53607
 
53608
 
53609
 
53610
 
53611
 
53612
 
53613
 
53614
 
53615
 
53616
 
53617
 
53618
 
53619
 
53620
 
53621
 
53622
 
53623
 
53624
 
53625
 
53626
 
53627
 
53628
 
53629
 
53630
 
53631
 
53632
 
53633
 
53634
 
53635
 
53636
 
53637
 
53638
 
53639
 
53640
 
53641
 
53642
 
53643
 
53644
 
53645
 
53646
 
53647
 
53648
 
53649
 
53650
 
53651
 
53652
 
53653
 
53654
 
53655
 
53656
 
53657
 
53658
 
53659
 
53660
 
53661
 
53662
 
53663
 
53664
 
53665
 
53666
 
53667
 
53668
 
53669
 
53670
 
53671
 
53672
 
53673
 
53674
 
53675
 
53676
 
53677
 
53678
 
53679
 
53680
 
53681
 
53682
 
53683
 
53684
 
53685
 
53686
 
53687
 
53688
 
53689
 
53690
 
53691
 
53692
 
53693
 
53694
 
53695
 
53696
 
53697
 
53698
 
53699
 
53700
 
53701
 
53702
 
53703
 
53704
 
53705
 
53706
 
53707
 
53708
 
53709
 
53710
 
53711
 
53712
 
53713
 
53714
 
53715
 
53716
 
53717
 
53718
 
53719
 
53720
 
53721
 
53722
 
53723
 
53724
 
53725
 
53726
 
53727
 
53728
 
53729
 
53730
 
53731
 
53732
 
53733
 
53734
 
53735
 
53736
 
53737
 
53738
 
53739
 
53740
 
53741
 
53742
 
53743
 
53744
 
53745
 
53746
 
53747
 
53748
 
53749
 
53750
 
53751
 
53752
 
53753
 
53754
 
53755
 
53756
 
53757
 
53758
 
53759
 
53760
 
53761
 
53762
 
53763
 
53764
 
53765
 
53766
 
53767
 
53768
 
53769
 
53770
 
53771
 
53772
 
53773
 
53774
 
53775
 
53776
 
53777
 
53778
 
53779
 
53780
 
53781
 
53782
 
53783
 
53784
 
53785
 
53786
 
53787
 
53788
 
53789
 
53790
 
53791
 
53792
 
53793
 
53794
 
53795
 
53796
 
53797
 
53798
 
53799
 
53800
 
53801
 
53802
 
53803
 
53804
 
53805
 
53806
 
53807
 
53808
 
53809
 
53810
 
53811
 
53812
 
53813
 
53814
 
53815
 
53816
 
53817
 
53818
 
53819
 
53820
 
53821
 
53822
 
53823
 
53824
 
53825
 
53826
 
53827
 
53828
 
53829
 
53830
 
53831
 
53832
 
53833
 
53834
 
53835
 
53836
 
53837
 
53838
 
53839
 
53840
 
53841
 
53842
 
53843
 
53844
 
53845
 
53846
 
53847
 
53848
 
53849
 
53850
 
53851
 
53852
 
53853
 
53854
 
53855
 
53856
 
53857
 
53858
 
53859
 
53860
 
53861
 
53862
 
53863
 
53864
 
53865
 
53866
 
53867
 
53868
 
53869
 
53870
 
53871
 
53872
 
53873
 
53874
 
53875
 
53876
 
53877
 
53878
 
53879
 
53880
 
53881
 
53882
 
53883
 
53884
 
53885
 
53886
 
53887
 
53888
 
53889
 
53890
 
53891
 
53892
 
53893
 
53894
 
53895
 
53896
 
53897
 
53898
 
53899
 
53900
 
53901
 
53902
 
53903
 
53904
 
53905
 
53906
 
53907
 
53908
 
53909
 
53910
 
53911
 
53912
 
53913
 
53914
 
53915
 
53916
 
53917
 
53918
 
53919
 
53920
 
53921
 
53922
 
53923
 
53924
 
53925
 
53926
 
53927
 
53928
 
53929
 
53930
 
53931
 
53932
 
53933
 
53934
 
53935
 
53936
 
53937
 
53938
 
53939
 
53940
 
53941
 
53942
 
53943
 
53944
 
53945
 
53946
 
53947
 
53948
 
53949
 
53950
 
53951
 
53952
 
53953
 
53954
 
53955
 
53956
 
53957
 
53958
 
53959
 
53960
 
53961
 
53962
 
53963
 
53964
 
53965
 
53966
 
53967
 
53968
 
53969
 
53970
 
53971
 
53972
 
53973
 
53974
 
53975
 
53976
 
53977
 
53978
 
53979
 
53980
 
53981
 
53982
 
53983
 
53984
 
53985
 
53986
 
53987
 
53988
 
53989
 
53990
 
53991
 
53992
 
53993
 
53994
 
53995
 
53996
 
53997
 
53998
 
53999
 
54000
 
54001
 
54002
 
54003
 
54004
 
54005
 
54006
 
54007
 
54008
 
54009
 
54010
 
54011
 
54012
 
54013
 
54014
 
54015
 
54016
 
54017
 
54018
 
54019
 
54020
 
54021
 
54022
 
54023
 
54024
 
54025
 
54026
 
54027
 
54028
 
54029
 
54030
 
54031
 
54032
 
54033
 
54034
 
54035
 
54036
 
54037
 
54038
 
54039
 
54040
 
54041
 
54042
 
54043
 
54044
 
54045
 
54046
 
54047
 
54048
 
54049
 
54050
 
54051
 
54052
 
54053
 
54054
 
54055
 
54056
 
54057
 
54058
 
54059
 
54060
 
54061
 
54062
 
54063
 
54064
 
54065
 
54066
 
54067
 
54068
 
54069
 
54070
 
54071
 
54072
 
54073
 
54074
 
54075
 
54076
 
54077
 
54078
 
54079
 
54080
 
54081
 
54082
 
54083
 
54084
 
54085
 
54086
 
54087
 
54088
 
54089
 
54090
 
54091
 
54092
 
54093
 
54094
 
54095
 
54096
 
54097
 
54098
 
54099
 
54100
 
54101
 
54102
 
54103
 
54104
 
54105
 
54106
 
54107
 
54108
 
54109
 
54110
 
54111
 
54112
 
54113
 
54114
 
54115
 
54116
 
54117
 
54118
 
54119
 
54120
 
54121
 
54122
 
54123
 
54124
 
54125
 
54126
 
54127
 
54128
 
54129
 
54130
 
54131
 
54132
 
54133
 
54134
 
54135
 
54136
 
54137
 
54138
 
54139
 
54140
 
54141
 
54142
 
54143
 
54144
 
54145
 
54146
 
54147
 
54148
 
54149
 
54150
 
54151
 
54152
 
54153
 
54154
 
54155
 
54156
 
54157
 
54158
 
54159
 
54160
 
54161
 
54162
 
54163
 
54164
 
54165
 
54166
 
54167
 
54168
 
54169
 
54170
 
54171
 
54172
 
54173
 
54174
 
54175
 
54176
 
54177
 
54178
 
54179
 
54180
 
54181
 
54182
 
54183
 
54184
 
54185
 
54186
 
54187
 
54188
 
54189
 
54190
 
54191
 
54192
 
54193
 
54194
 
54195
 
54196
 
54197
 
54198
 
54199
 
54200
 
54201
 
54202
 
54203
 
54204
 
54205
 
54206
 
54207
 
54208
 
54209
 
54210
 
54211
 
54212
 
54213
 
54214
 
54215
 
54216
 
54217
 
54218
 
54219
 
54220
 
54221
 
54222
 
54223
 
54224
 
54225
 
54226
 
54227
 
54228
 
54229
 
54230
 
54231
 
54232
 
54233
 
54234
 
54235
 
54236
 
54237
 
54238
 
54239
 
54240
 
54241
 
54242
 
54243
 
54244
 
54245
 
54246
 
54247
 
54248
 
54249
 
54250
 
54251
 
54252
 
54253
 
54254
 
54255
 
54256
 
54257
 
54258
 
54259
 
54260
 
54261
 
54262
 
54263
 
54264
 
54265
 
54266
 
54267
 
54268
 
54269
 
54270
 
54271
 
54272
 
54273
 
54274
 
54275
 
54276
 
54277
 
54278
 
54279
 
54280
 
54281
 
54282
 
54283
 
54284
 
54285
 
54286
 
54287
 
54288
 
54289
 
54290
 
54291
 
54292
 
54293
 
54294
 
54295
 
54296
 
54297
 
54298
 
54299
 
54300
 
54301
 
54302
 
54303
 
54304
 
54305
 
54306
 
54307
 
54308
 
54309
 
54310
 
54311
 
54312
 
54313
 
54314
 
54315
 
54316
 
54317
 
54318
 
54319
 
54320
 
54321
 
54322
 
54323
 
54324
 
54325
 
54326
 
54327
 
54328
 
54329
 
54330
 
54331
 
54332
 
54333
 
54334
 
54335
 
54336
 
54337
 
54338
 
54339
 
54340
 
54341
 
54342
 
54343
 
54344
 
54345
 
54346
 
54347
 
54348
 
54349
 
54350
 
54351
 
54352
 
54353
 
54354
 
54355
 
54356
 
54357
 
54358
 
54359
 
54360
 
54361
 
54362
 
54363
 
54364
 
54365
 
54366
 
54367
 
54368
 
54369
 
54370
 
54371
 
54372
 
54373
 
54374
 
54375
 
54376
 
54377
 
54378
 
54379
 
54380
 
54381
 
54382
 
54383
 
54384
 
54385
 
54386
 
54387
 
54388
 
54389
 
54390
 
54391
 
54392
 
54393
 
54394
 
54395
 
54396
 
54397
 
54398
 
54399
 
54400
 
54401
 
54402
 
54403
 
54404
 
54405
 
54406
 
54407
 
54408
 
54409
 
54410
 
54411
 
54412
 
54413
 
54414
 
54415
 
54416
 
54417
 
54418
 
54419
 
54420
 
54421
 
54422
 
54423
 
54424
 
54425
 
54426
 
54427
 
54428
 
54429
 
54430
 
54431
 
54432
 
54433
 
54434
 
54435
 
54436
 
54437
 
54438
 
54439
 
54440
 
54441
 
54442
 
54443
 
54444
 
54445
 
54446
 
54447
 
54448
 
54449
 
54450
 
54451
 
54452
 
54453
 
54454
 
54455
 
54456
 
54457
 
54458
 
54459
 
54460
 
54461
 
54462
 
54463
 
54464
 
54465
 
54466
 
54467
 
54468
 
54469
 
54470
 
54471
 
54472
 
54473
 
54474
 
54475
 
54476
 
54477
 
54478
 
54479
 
54480
 
54481
 
54482
 
54483
 
54484
 
54485
 
54486
 
54487
 
54488
 
54489
 
54490
 
54491
 
54492
 
54493
 
54494
 
54495
 
54496
 
54497
 
54498
 
54499
 
54500
 
54501
 
54502
 
54503
 
54504
 
54505
 
54506
 
54507
 
54508
 
54509
 
54510
 
54511
 
54512
 
54513
 
54514
 
54515
 
54516
 
54517
 
54518
 
54519
 
54520
 
54521
 
54522
 
54523
 
54524
 
54525
 
54526
 
54527
 
54528
 
54529
 
54530
 
54531
 
54532
 
54533
 
54534
 
54535
 
54536
 
54537
 
54538
 
54539
 
54540
 
54541
 
54542
 
54543
 
54544
 
54545
 
54546
 
54547
 
54548
 
54549
 
54550
 
54551
 
54552
 
54553
 
54554
 
54555
 
54556
 
54557
 
54558
 
54559
 
54560
 
54561
 
54562
 
54563
 
54564
 
54565
 
54566
 
54567
 
54568
 
54569
 
54570
 
54571
 
54572
 
54573
 
54574
 
54575
 
54576
 
54577
 
54578
 
54579
 
54580
 
54581
 
54582
 
54583
 
54584
 
54585
 
54586
 
54587
 
54588
 
54589
 
54590
 
54591
 
54592
 
54593
 
54594
 
54595
 
54596
 
54597
 
54598
 
54599
 
54600
 
54601
 
54602
 
54603
 
54604
 
54605
 
54606
 
54607
 
54608
 
54609
 
54610
 
54611
 
54612
 
54613
 
54614
 
54615
 
54616
 
54617
 
54618
 
54619
 
54620
 
54621
 
54622
 
54623
 
54624
 
54625
 
54626
 
54627
 
54628
 
54629
 
54630
 
54631
 
54632
 
54633
 
54634
 
54635
 
54636
 
54637
 
54638
 
54639
 
54640
 
54641
 
54642
 
54643
 
54644
 
54645
 
54646
 
54647
 
54648
 
54649
 
54650
 
54651
 
54652
 
54653
 
54654
 
54655
 
54656
 
54657
 
54658
 
54659
 
54660
 
54661
 
54662
 
54663
 
54664
 
54665
 
54666
 
54667
 
54668
 
54669
 
54670
 
54671
 
54672
 
54673
 
54674
 
54675
 
54676
 
54677
 
54678
 
54679
 
54680
 
54681
 
54682
 
54683
 
54684
 
54685
 
54686
 
54687
 
54688
 
54689
 
54690
 
54691
 
54692
 
54693
 
54694
 
54695
 
54696
 
54697
 
54698
 
54699
 
54700
 
54701
 
54702
 
54703
 
54704
 
54705
 
54706
 
54707
 
54708
 
54709
 
54710
 
54711
 
54712
 
54713
 
54714
 
54715
 
54716
 
54717
 
54718
 
54719
 
54720
 
54721
 
54722
 
54723
 
54724
 
54725
 
54726
 
54727
 
54728
 
54729
 
54730
 
54731
 
54732
 
54733
 
54734
 
54735
 
54736
 
54737
 
54738
 
54739
 
54740
 
54741
 
54742
 
54743
 
54744
 
54745
 
54746
 
54747
 
54748
 
54749
 
54750
 
54751
 
54752
 
54753
 
54754
 
54755
 
54756
 
54757
 
54758
 
54759
 
54760
 
54761
 
54762
 
54763
 
54764
 
54765
 
54766
 
54767
 
54768
 
54769
 
54770
 
54771
 
54772
 
54773
 
54774
 
54775
 
54776
 
54777
 
54778
 
54779
 
54780
 
54781
 
54782
 
54783
 
54784
 
54785
 
54786
 
54787
 
54788
 
54789
 
54790
 
54791
 
54792
 
54793
 
54794
 
54795
 
54796
 
54797
 
54798
 
54799
 
54800
 
54801
 
54802
 
54803
 
54804
 
54805
 
54806
 
54807
 
54808
 
54809
 
54810
 
54811
 
54812
 
54813
 
54814
 
54815
 
54816
 
54817
 
54818
 
54819
 
54820
 
54821
 
54822
 
54823
 
54824
 
54825
 
54826
 
54827
 
54828
 
54829
 
54830
 
54831
 
54832
 
54833
 
54834
 
54835
 
54836
 
54837
 
54838
 
54839
 
54840
 
54841
 
54842
 
54843
 
54844
 
54845
 
54846
 
54847
 
54848
 
54849
 
54850
 
54851
 
54852
 
54853
 
54854
 
54855
 
54856
 
54857
 
54858
 
54859
 
54860
 
54861
 
54862
 
54863
 
54864
 
54865
 
54866
 
54867
 
54868
 
54869
 
54870
 
54871
 
54872
 
54873
 
54874
 
54875
 
54876
 
54877
 
54878
 
54879
 
54880
 
54881
 
54882
 
54883
 
54884
 
54885
 
54886
 
54887
 
54888
 
54889
 
54890
 
54891
 
54892
 
54893
 
54894
 
54895
 
54896
 
54897
 
54898
 
54899
 
54900
 
54901
 
54902
 
54903
 
54904
 
54905
 
54906
 
54907
 
54908
 
54909
 
54910
 
54911
 
54912
 
54913
 
54914
 
54915
 
54916
 
54917
 
54918
 
54919
 
54920
 
54921
 
54922
 
54923
 
54924
 
54925
 
54926
 
54927
 
54928
 
54929
 
54930
 
54931
 
54932
 
54933
 
54934
 
54935
 
54936
 
54937
 
54938
 
54939
 
54940
 
54941
 
54942
 
54943
 
54944
 
54945
 
54946
 
54947
 
54948
 
54949
 
54950
 
54951
 
54952
 
54953
 
54954
 
54955
 
54956
 
54957
 
54958
 
54959
 
54960
 
54961
 
54962
 
54963
 
54964
 
54965
 
54966
 
54967
 
54968
 
54969
 
54970
 
54971
 
54972
 
54973
 
54974
 
54975
 
54976
 
54977
 
54978
 
54979
 
54980
 
54981
 
54982
 
54983
 
54984
 
54985
 
54986
 
54987
 
54988
 
54989
 
54990
 
54991
 
54992
 
54993
 
54994
 
54995
 
54996
 
54997
 
54998
 
54999
 
55000
 
55001
 
55002
 
55003
 
55004
 
55005
 
55006
 
55007
 
55008
 
55009
 
55010
 
55011
 
55012
 
55013
 
55014
 
55015
 
55016
 
55017
 
55018
 
55019
 
55020
 
55021
 
55022
 
55023
 
55024
 
55025
 
55026
 
55027
 
55028
 
55029
 
55030
 
55031
 
55032
 
55033
 
55034
 
55035
 
55036
 
55037
 
55038
 
55039
 
55040
 
55041
 
55042
 
55043
 
55044
 
55045
 
55046
 
55047
 
55048
 
55049
 
55050
 
55051
 
55052
 
55053
 
55054
 
55055
 
55056
 
55057
 
55058
 
55059
 
55060
 
55061
 
55062
 
55063
 
55064
 
55065
 
55066
 
55067
 
55068
 
55069
 
55070
 
55071
 
55072
 
55073
 
55074
 
55075
 
55076
 
55077
 
55078
 
55079
 
55080
 
55081
 
55082
 
55083
 
55084
 
55085
 
55086
 
55087
 
55088
 
55089
 
55090
 
55091
 
55092
 
55093
 
55094
 
55095
 
55096
 
55097
 
55098
 
55099
 
55100
 
55101
 
55102
 
55103
 
55104
 
55105
 
55106
 
55107
 
55108
 
55109
 
55110
 
55111
 
55112
 
55113
 
55114
 
55115
 
55116
 
55117
 
55118
 
55119
 
55120
 
55121
 
55122
 
55123
 
55124
 
55125
 
55126
 
55127
 
55128
 
55129
 
55130
 
55131
 
55132
 
55133
 
55134
 
55135
 
55136
 
55137
 
55138
 
55139
 
55140
 
55141
 
55142
 
55143
 
55144
 
55145
 
55146
 
55147
 
55148
 
55149
 
55150
 
55151
 
55152
 
55153
 
55154
 
55155
 
55156
 
55157
 
55158
 
55159
 
55160
 
55161
 
55162
 
55163
 
55164
 
55165
 
55166
 
55167
 
55168
 
55169
 
55170
 
55171
 
55172
 
55173
 
55174
 
55175
 
55176
 
55177
 
55178
 
55179
 
55180
 
55181
 
55182
 
55183
 
55184
 
55185
 
55186
 
55187
 
55188
 
55189
 
55190
 
55191
 
55192
 
55193
 
55194
 
55195
 
55196
 
55197
 
55198
 
55199
 
55200
 
55201
 
55202
 
55203
 
55204
 
55205
 
55206
 
55207
 
55208
 
55209
 
55210
 
55211
 
55212
 
55213
 
55214
 
55215
 
55216
 
55217
 
55218
 
55219
 
55220
 
55221
 
55222
 
55223
 
55224
 
55225
 
55226
 
55227
 
55228
 
55229
 
55230
 
55231
 
55232
 
55233
 
55234
 
55235
 
55236
 
55237
 
55238
 
55239
 
55240
 
55241
 
55242
 
55243
 
55244
 
55245
 
55246
 
55247
 
55248
 
55249
 
55250
 
55251
 
55252
 
55253
 
55254
 
55255
 
55256
 
55257
 
55258
 
55259
 
55260
 
55261
 
55262
 
55263
 
55264
 
55265
 
55266
 
55267
 
55268
 
55269
 
55270
 
55271
 
55272
 
55273
 
55274
 
55275
 
55276
 
55277
 
55278
 
55279
 
55280
 
55281
 
55282
 
55283
 
55284
 
55285
 
55286
 
55287
 
55288
 
55289
 
55290
 
55291
 
55292
 
55293
 
55294
 
55295
 
55296
 
55297
 
55298
 
55299
 
55300
 
55301
 
55302
 
55303
 
55304
 
55305
 
55306
 
55307
 
55308
 
55309
 
55310
 
55311
 
55312
 
55313
 
55314
 
55315
 
55316
 
55317
 
55318
 
55319
 
55320
 
55321
 
55322
 
55323
 
55324
 
55325
 
55326
 
55327
 
55328
 
55329
 
55330
 
55331
 
55332
 
55333
 
55334
 
55335
 
55336
 
55337
 
55338
 
55339
 
55340
 
55341
 
55342
 
55343
 
55344
 
55345
 
55346
 
55347
 
55348
 
55349
 
55350
 
55351
 
55352
 
55353
 
55354
 
55355
 
55356
 
55357
 
55358
 
55359
 
55360
 
55361
 
55362
 
55363
 
55364
 
55365
 
55366
 
55367
 
55368
 
55369
 
55370
 
55371
 
55372
 
55373
 
55374
 
55375
 
55376
 
55377
 
55378
 
55379
 
55380
 
55381
 
55382
 
55383
 
55384
 
55385
 
55386
 
55387
 
55388
 
55389
 
55390
 
55391
 
55392
 
55393
 
55394
 
55395
 
55396
 
55397
 
55398
 
55399
 
55400
 
55401
 
55402
 
55403
 
55404
 
55405
 
55406
 
55407
 
55408
 
55409
 
55410
 
55411
 
55412
 
55413
 
55414
 
55415
 
55416
 
55417
 
55418
 
55419
 
55420
 
55421
 
55422
 
55423
 
55424
 
55425
 
55426
 
55427
 
55428
 
55429
 
55430
 
55431
 
55432
 
55433
 
55434
 
55435
 
55436
 
55437
 
55438
 
55439
 
55440
 
55441
 
55442
 
55443
 
55444
 
55445
 
55446
 
55447
 
55448
 
55449
 
55450
 
55451
 
55452
 
55453
 
55454
 
55455
 
55456
 
55457
 
55458
 
55459
 
55460
 
55461
 
55462
 
55463
 
55464
 
55465
 
55466
 
55467
 
55468
 
55469
 
55470
 
55471
 
55472
 
55473
 
55474
 
55475
 
55476
 
55477
 
55478
 
55479
 
55480
 
55481
 
55482
 
55483
 
55484
 
55485
 
55486
 
55487
 
55488
 
55489
 
55490
 
55491
 
55492
 
55493
 
55494
 
55495
 
55496
 
55497
 
55498
 
55499
 
55500
 
55501
 
55502
 
55503
 
55504
 
55505
 
55506
 
55507
 
55508
 
55509
 
55510
 
55511
 
55512
 
55513
 
55514
 
55515
 
55516
 
55517
 
55518
 
55519
 
55520
 
55521
 
55522
 
55523
 
55524
 
55525
 
55526
 
55527
 
55528
 
55529
 
55530
 
55531
 
55532
 
55533
 
55534
 
55535
 
55536
 
55537
 
55538
 
55539
 
55540
 
55541
 
55542
 
55543
 
55544
 
55545
 
55546
 
55547
 
55548
 
55549
 
55550
 
55551
 
55552
 
55553
 
55554
 
55555
 
55556
 
55557
 
55558
 
55559
 
55560
 
55561
 
55562
 
55563
 
55564
 
55565
 
55566
 
55567
 
55568
 
55569
 
55570
 
55571
 
55572
 
55573
 
55574
 
55575
 
55576
 
55577
 
55578
 
55579
 
55580
 
55581
 
55582
 
55583
 
55584
 
55585
 
55586
 
55587
 
55588
 
55589
 
55590
 
55591
 
55592
 
55593
 
55594
 
55595
 
55596
 
55597
 
55598
 
55599
 
55600
 
55601
 
55602
 
55603
 
55604
 
55605
 
55606
 
55607
 
55608
 
55609
 
55610
 
55611
 
55612
 
55613
 
55614
 
55615
 
55616
 
55617
 
55618
 
55619
 
55620
 
55621
 
55622
 
55623
 
55624
 
55625
 
55626
 
55627
 
55628
 
55629
 
55630
 
55631
 
55632
 
55633
 
55634
 
55635
 
55636
 
55637
 
55638
 
55639
 
55640
 
55641
 
55642
 
55643
 
55644
 
55645
 
55646
 
55647
 
55648
 
55649
 
55650
 
55651
 
55652
 
55653
 
55654
 
55655
 
55656
 
55657
 
55658
 
55659
 
55660
 
55661
 
55662
 
55663
 
55664
 
55665
 
55666
 
55667
 
55668
 
55669
 
55670
 
55671
 
55672
 
55673
 
55674
 
55675
 
55676
 
55677
 
55678
 
55679
 
55680
 
55681
 
55682
 
55683
 
55684
 
55685
 
55686
 
55687
 
55688
 
55689
 
55690
 
55691
 
55692
 
55693
 
55694
 
55695
 
55696
 
55697
 
55698
 
55699
 
55700
 
55701
 
55702
 
55703
 
55704
 
55705
 
55706
 
55707
 
55708
 
55709
 
55710
 
55711
 
55712
 
55713
 
55714
 
55715
 
55716
 
55717
 
55718
 
55719
 
55720
 
55721
 
55722
 
55723
 
55724
 
55725
 
55726
 
55727
 
55728
 
55729
 
55730
 
55731
 
55732
 
55733
 
55734
 
55735
 
55736
 
55737
 
55738
 
55739
 
55740
 
55741
 
55742
 
55743
 
55744
 
55745
 
55746
 
55747
 
55748
 
55749
 
55750
 
55751
 
55752
 
55753
 
55754
 
55755
 
55756
 
55757
 
55758
 
55759
 
55760
 
55761
 
55762
 
55763
 
55764
 
55765
 
55766
 
55767
 
55768
 
55769
 
55770
 
55771
 
55772
 
55773
 
55774
 
55775
 
55776
 
55777
 
55778
 
55779
 
55780
 
55781
 
55782
 
55783
 
55784
 
55785
 
55786
 
55787
 
55788
 
55789
 
55790
 
55791
 
55792
 
55793
 
55794
 
55795
 
55796
 
55797
 
55798
 
55799
 
55800
 
55801
 
55802
 
55803
 
55804
 
55805
 
55806
 
55807
 
55808
 
55809
 
55810
 
55811
 
55812
 
55813
 
55814
 
55815
 
55816
 
55817
 
55818
 
55819
 
55820
 
55821
 
55822
 
55823
 
55824
 
55825
 
55826
 
55827
 
55828
 
55829
 
55830
 
55831
 
55832
 
55833
 
55834
 
55835
 
55836
 
55837
 
55838
 
55839
 
55840
 
55841
 
55842
 
55843
 
55844
 
55845
 
55846
 
55847
 
55848
 
55849
 
55850
 
55851
 
55852
 
55853
 
55854
 
55855
 
55856
 
55857
 
55858
 
55859
 
55860
 
55861
 
55862
 
55863
 
55864
 
55865
 
55866
 
55867
 
55868
 
55869
 
55870
 
55871
 
55872
 
55873
 
55874
 
55875
 
55876
 
55877
 
55878
 
55879
 
55880
 
55881
 
55882
 
55883
 
55884
 
55885
 
55886
 
55887
 
55888
 
55889
 
55890
 
55891
 
55892
 
55893
 
55894
 
55895
 
55896
 
55897
 
55898
 
55899
 
55900
 
55901
 
55902
 
55903
 
55904
 
55905
 
55906
 
55907
 
55908
 
55909
 
55910
 
55911
 
55912
 
55913
 
55914
 
55915
 
55916
 
55917
 
55918
 
55919
 
55920
 
55921
 
55922
 
55923
 
55924
 
55925
 
55926
 
55927
 
55928
 
55929
 
55930
 
55931
 
55932
 
55933
 
55934
 
55935
 
55936
 
55937
 
55938
 
55939
 
55940
 
55941
 
55942
 
55943
 
55944
 
55945
 
55946
 
55947
 
55948
 
55949
 
55950
 
55951
 
55952
 
55953
 
55954
 
55955
 
55956
 
55957
 
55958
 
55959
 
55960
 
55961
 
55962
 
55963
 
55964
 
55965
 
55966
 
55967
 
55968
 
55969
 
55970
 
55971
 
55972
 
55973
 
55974
 
55975
 
55976
 
55977
 
55978
 
55979
 
55980
 
55981
 
55982
 
55983
 
55984
 
55985
 
55986
 
55987
 
55988
 
55989
 
55990
 
55991
 
55992
 
55993
 
55994
 
55995
 
55996
 
55997
 
55998
 
55999
 
56000
 
56001
 
56002
 
56003
 
56004
 
56005
 
56006
 
56007
 
56008
 
56009
 
56010
 
56011
 
56012
 
56013
 
56014
 
56015
 
56016
 
56017
 
56018
 
56019
 
56020
 
56021
 
56022
 
56023
 
56024
 
56025
 
56026
 
56027
 
56028
 
56029
 
56030
 
56031
 
56032
 
56033
 
56034
 
56035
 
56036
 
56037
 
56038
 
56039
 
56040
 
56041
 
56042
 
56043
 
56044
 
56045
 
56046
 
56047
 
56048
 
56049
 
56050
 
56051
 
56052
 
56053
 
56054
 
56055
 
56056
 
56057
 
56058
 
56059
 
56060
 
56061
 
56062
 
56063
 
56064
 
56065
 
56066
 
56067
 
56068
 
56069
 
56070
 
56071
 
56072
 
56073
 
56074
 
56075
 
56076
 
56077
 
56078
 
56079
 
56080
 
56081
 
56082
 
56083
 
56084
 
56085
 
56086
 
56087
 
56088
 
56089
 
56090
 
56091
 
56092
 
56093
 
56094
 
56095
 
56096
 
56097
 
56098
 
56099
 
56100
 
56101
 
56102
 
56103
 
56104
 
56105
 
56106
 
56107
 
56108
 
56109
 
56110
 
56111
 
56112
 
56113
 
56114
 
56115
 
56116
 
56117
 
56118
 
56119
 
56120
 
56121
 
56122
 
56123
 
56124
 
56125
 
56126
 
56127
 
56128
 
56129
 
56130
 
56131
 
56132
 
56133
 
56134
 
56135
 
56136
 
56137
 
56138
 
56139
 
56140
 
56141
 
56142
 
56143
 
56144
 
56145
 
56146
 
56147
 
56148
 
56149
 
56150
 
56151
 
56152
 
56153
 
56154
 
56155
 
56156
 
56157
 
56158
 
56159
 
56160
 
56161
 
56162
 
56163
 
56164
 
56165
 
56166
 
56167
 
56168
 
56169
 
56170
 
56171
 
56172
 
56173
 
56174
 
56175
 
56176
 
56177
 
56178
 
56179
 
56180
 
56181
 
56182
 
56183
 
56184
 
56185
 
56186
 
56187
 
56188
 
56189
 
56190
 
56191
 
56192
 
56193
 
56194
 
56195
 
56196
 
56197
 
56198
 
56199
 
56200
 
56201
 
56202
 
56203
 
56204
 
56205
 
56206
 
56207
 
56208
 
56209
 
56210
 
56211
 
56212
 
56213
 
56214
 
56215
 
56216
 
56217
 
56218
 
56219
 
56220
 
56221
 
56222
 
56223
 
56224
 
56225
 
56226
 
56227
 
56228
 
56229
 
56230
 
56231
 
56232
 
56233
 
56234
 
56235
 
56236
 
56237
 
56238
 
56239
 
56240
 
56241
 
56242
 
56243
 
56244
 
56245
 
56246
 
56247
 
56248
 
56249
 
56250
 
56251
 
56252
 
56253
 
56254
 
56255
 
56256
 
56257
 
56258
 
56259
 
56260
 
56261
 
56262
 
56263
 
56264
 
56265
 
56266
 
56267
 
56268
 
56269
 
56270
 
56271
 
56272
 
56273
 
56274
 
56275
 
56276
 
56277
 
56278
 
56279
 
56280
 
56281
 
56282
 
56283
 
56284
 
56285
 
56286
 
56287
 
56288
 
56289
 
56290
 
56291
 
56292
 
56293
 
56294
 
56295
 
56296
 
56297
 
56298
 
56299
 
56300
 
56301
 
56302
 
56303
 
56304
 
56305
 
56306
 
56307
 
56308
 
56309
 
56310
 
56311
 
56312
 
56313
 
56314
 
56315
 
56316
 
56317
 
56318
 
56319
 
56320
 
56321
 
56322
 
56323
 
56324
 
56325
 
56326
 
56327
 
56328
 
56329
 
56330
 
56331
 
56332
 
56333
 
56334
 
56335
 
56336
 
56337
 
56338
 
56339
 
56340
 
56341
 
56342
 
56343
 
56344
 
56345
 
56346
 
56347
 
56348
 
56349
 
56350
 
56351
 
56352
 
56353
 
56354
 
56355
 
56356
 
56357
 
56358
 
56359
 
56360
 
56361
 
56362
 
56363
 
56364
 
56365
 
56366
 
56367
 
56368
 
56369
 
56370
 
56371
 
56372
 
56373
 
56374
 
56375
 
56376
 
56377
 
56378
 
56379
 
56380
 
56381
 
56382
 
56383
 
56384
 
56385
 
56386
 
56387
 
56388
 
56389
 
56390
 
56391
 
56392
 
56393
 
56394
 
56395
 
56396
 
56397
 
56398
 
56399
 
56400
 
56401
 
56402
 
56403
 
56404
 
56405
 
56406
 
56407
 
56408
 
56409
 
56410
 
56411
 
56412
 
56413
 
56414
 
56415
 
56416
 
56417
 
56418
 
56419
 
56420
 
56421
 
56422
 
56423
 
56424
 
56425
 
56426
 
56427
 
56428
 
56429
 
56430
 
56431
 
56432
 
56433
 
56434
 
56435
 
56436
 
56437
 
56438
 
56439
 
56440
 
56441
 
56442
 
56443
 
56444
 
56445
 
56446
 
56447
 
56448
 
56449
 
56450
 
56451
 
56452
 
56453
 
56454
 
56455
 
56456
 
56457
 
56458
 
56459
 
56460
 
56461
 
56462
 
56463
 
56464
 
56465
 
56466
 
56467
 
56468
 
56469
 
56470
 
56471
 
56472
 
56473
 
56474
 
56475
 
56476
 
56477
 
56478
 
56479
 
56480
 
56481
 
56482
 
56483
 
56484
 
56485
 
56486
 
56487
 
56488
 
56489
 
56490
 
56491
 
56492
 
56493
 
56494
 
56495
 
56496
 
56497
 
56498
 
56499
 
56500
 
56501
 
56502
 
56503
 
56504
 
56505
 
56506
 
56507
 
56508
 
56509
 
56510
 
56511
 
56512
 
56513
 
56514
 
56515
 
56516
 
56517
 
56518
 
56519
 
56520
 
56521
 
56522
 
56523
 
56524
 
56525
 
56526
 
56527
 
56528
 
56529
 
56530
 
56531
 
56532
 
56533
 
56534
 
56535
 
56536
 
56537
 
56538
 
56539
 
56540
 
56541
 
56542
 
56543
 
56544
 
56545
 
56546
 
56547
 
56548
 
56549
 
56550
 
56551
 
56552
 
56553
 
56554
 
56555
 
56556
 
56557
 
56558
 
56559
 
56560
 
56561
 
56562
 
56563
 
56564
 
56565
 
56566
 
56567
 
56568
 
56569
 
56570
 
56571
 
56572
 
56573
 
56574
 
56575
 
56576
 
56577
 
56578
 
56579
 
56580
 
56581
 
56582
 
56583
 
56584
 
56585
 
56586
 
56587
 
56588
 
56589
 
56590
 
56591
 
56592
 
56593
 
56594
 
56595
 
56596
 
56597
 
56598
 
56599
 
56600
 
56601
 
56602
 
56603
 
56604
 
56605
 
56606
 
56607
 
56608
 
56609
 
56610
 
56611
 
56612
 
56613
 
56614
 
56615
 
56616
 
56617
 
56618
 
56619
 
56620
 
56621
 
56622
 
56623
 
56624
 
56625
 
56626
 
56627
 
56628
 
56629
 
56630
 
56631
 
56632
 
56633
 
56634
 
56635
 
56636
 
56637
 
56638
 
56639
 
56640
 
56641
 
56642
 
56643
 
56644
 
56645
 
56646
 
56647
 
56648
 
56649
 
56650
 
56651
 
56652
 
56653
 
56654
 
56655
 
56656
 
56657
 
56658
 
56659
 
56660
 
56661
 
56662
 
56663
 
56664
 
56665
 
56666
 
56667
 
56668
 
56669
 
56670
 
56671
 
56672
 
56673
 
56674
 
56675
 
56676
 
56677
 
56678
 
56679
 
56680
 
56681
 
56682
 
56683
 
56684
 
56685
 
56686
 
56687
 
56688
 
56689
 
56690
 
56691
 
56692
 
56693
 
56694
 
56695
 
56696
 
56697
 
56698
 
56699
 
56700
 
56701
 
56702
 
56703
 
56704
 
56705
 
56706
 
56707
 
56708
 
56709
 
56710
 
56711
 
56712
 
56713
 
56714
 
56715
 
56716
 
56717
 
56718
 
56719
 
56720
 
56721
 
56722
 
56723
 
56724
 
56725
 
56726
 
56727
 
56728
 
56729
 
56730
 
56731
 
56732
 
56733
 
56734
 
56735
 
56736
 
56737
 
56738
 
56739
 
56740
 
56741
 
56742
 
56743
 
56744
 
56745
 
56746
 
56747
 
56748
 
56749
 
56750
 
56751
 
56752
 
56753
 
56754
 
56755
 
56756
 
56757
 
56758
 
56759
 
56760
 
56761
 
56762
 
56763
 
56764
 
56765
 
56766
 
56767
 
56768
 
56769
 
56770
 
56771
 
56772
 
56773
 
56774
 
56775
 
56776
 
56777
 
56778
 
56779
 
56780
 
56781
 
56782
 
56783
 
56784
 
56785
 
56786
 
56787
 
56788
 
56789
 
56790
 
56791
 
56792
 
56793
 
56794
 
56795
 
56796
 
56797
 
56798
 
56799
 
56800
 
56801
 
56802
 
56803
 
56804
 
56805
 
56806
 
56807
 
56808
 
56809
 
56810
 
56811
 
56812
 
56813
 
56814
 
56815
 
56816
 
56817
 
56818
 
56819
 
56820
 
56821
 
56822
 
56823
 
56824
 
56825
 
56826
 
56827
 
56828
 
56829
 
56830
 
56831
 
56832
 
56833
 
56834
 
56835
 
56836
 
56837
 
56838
 
56839
 
56840
 
56841
 
56842
 
56843
 
56844
 
56845
 
56846
 
56847
 
56848
 
56849
 
56850
 
56851
 
56852
 
56853
 
56854
 
56855
 
56856
 
56857
 
56858
 
56859
 
56860
 
56861
 
56862
 
56863
 
56864
 
56865
 
56866
 
56867
 
56868
 
56869
 
56870
 
56871
 
56872
 
56873
 
56874
 
56875
 
56876
 
56877
 
56878
 
56879
 
56880
 
56881
 
56882
 
56883
 
56884
 
56885
 
56886
 
56887
 
56888
 
56889
 
56890
 
56891
 
56892
 
56893
 
56894
 
56895
 
56896
 
56897
 
56898
 
56899
 
56900
 
56901
 
56902
 
56903
 
56904
 
56905
 
56906
 
56907
 
56908
 
56909
 
56910
 
56911
 
56912
 
56913
 
56914
 
56915
 
56916
 
56917
 
56918
 
56919
 
56920
 
56921
 
56922
 
56923
 
56924
 
56925
 
56926
 
56927
 
56928
 
56929
 
56930
 
56931
 
56932
 
56933
 
56934
 
56935
 
56936
 
56937
 
56938
 
56939
 
56940
 
56941
 
56942
 
56943
 
56944
 
56945
 
56946
 
56947
 
56948
 
56949
 
56950
 
56951
 
56952
 
56953
 
56954
 
56955
 
56956
 
56957
 
56958
 
56959
 
56960
 
56961
 
56962
 
56963
 
56964
 
56965
 
56966
 
56967
 
56968
 
56969
 
56970
 
56971
 
56972
 
56973
 
56974
 
56975
 
56976
 
56977
 
56978
 
56979
 
56980
 
56981
 
56982
 
56983
 
56984
 
56985
 
56986
 
56987
 
56988
 
56989
 
56990
 
56991
 
56992
 
56993
 
56994
 
56995
 
56996
 
56997
 
56998
 
56999
 
57000
 
57001
 
57002
 
57003
 
57004
 
57005
 
57006
 
57007
 
57008
 
57009
 
57010
 
57011
 
57012
 
57013
 
57014
 
57015
 
57016
 
57017
 
57018
 
57019
 
57020
 
57021
 
57022
 
57023
 
57024
 
57025
 
57026
 
57027
 
57028
 
57029
 
57030
 
57031
 
57032
 
57033
 
57034
 
57035
 
57036
 
57037
 
57038
 
57039
 
57040
 
57041
 
57042
 
57043
 
57044
 
57045
 
57046
 
57047
 
57048
 
57049
 
57050
 
57051
 
57052
 
57053
 
57054
 
57055
 
57056
 
57057
 
57058
 
57059
 
57060
 
57061
 
57062
 
57063
 
57064
 
57065
 
57066
 
57067
 
57068
 
57069
 
57070
 
57071
 
57072
 
57073
 
57074
 
57075
 
57076
 
57077
 
57078
 
57079
 
57080
 
57081
 
57082
 
57083
 
57084
 
57085
 
57086
 
57087
 
57088
 
57089
 
57090
 
57091
 
57092
 
57093
 
57094
 
57095
 
57096
 
57097
 
57098
 
57099
 
57100
 
57101
 
57102
 
57103
 
57104
 
57105
 
57106
 
57107
 
57108
 
57109
 
57110
 
57111
 
57112
 
57113
 
57114
 
57115
 
57116
 
57117
 
57118
 
57119
 
57120
 
57121
 
57122
 
57123
 
57124
 
57125
 
57126
 
57127
 
57128
 
57129
 
57130
 
57131
 
57132
 
57133
 
57134
 
57135
 
57136
 
57137
 
57138
 
57139
 
57140
 
57141
 
57142
 
57143
 
57144
 
57145
 
57146
 
57147
 
57148
 
57149
 
57150
 
57151
 
57152
 
57153
 
57154
 
57155
 
57156
 
57157
 
57158
 
57159
 
57160
 
57161
 
57162
 
57163
 
57164
 
57165
 
57166
 
57167
 
57168
 
57169
 
57170
 
57171
 
57172
 
57173
 
57174
 
57175
 
57176
 
57177
 
57178
 
57179
 
57180
 
57181
 
57182
 
57183
 
57184
 
57185
 
57186
 
57187
 
57188
 
57189
 
57190
 
57191
 
57192
 
57193
 
57194
 
57195
 
57196
 
57197
 
57198
 
57199
 
57200
 
57201
 
57202
 
57203
 
57204
 
57205
 
57206
 
57207
 
57208
 
57209
 
57210
 
57211
 
57212
 
57213
 
57214
 
57215
 
57216
 
57217
 
57218
 
57219
 
57220
 
57221
 
57222
 
57223
 
57224
 
57225
 
57226
 
57227
 
57228
 
57229
 
57230
 
57231
 
57232
 
57233
 
57234
 
57235
 
57236
 
57237
 
57238
 
57239
 
57240
 
57241
 
57242
 
57243
 
57244
 
57245
 
57246
 
57247
 
57248
 
57249
 
57250
 
57251
 
57252
 
57253
 
57254
 
57255
 
57256
 
57257
 
57258
 
57259
 
57260
 
57261
 
57262
 
57263
 
57264
 
57265
 
57266
 
57267
 
57268
 
57269
 
57270
 
57271
 
57272
 
57273
 
57274
 
57275
 
57276
 
57277
 
57278
 
57279
 
57280
 
57281
 
57282
 
57283
 
57284
 
57285
 
57286
 
57287
 
57288
 
57289
 
57290
 
57291
 
57292
 
57293
 
57294
 
57295
 
57296
 
57297
 
57298
 
57299
 
57300
 
57301
 
57302
 
57303
 
57304
 
57305
 
57306
 
57307
 
57308
 
57309
 
57310
 
57311
 
57312
 
57313
 
57314
 
57315
 
57316
 
57317
 
57318
 
57319
 
57320
 
57321
 
57322
 
57323
 
57324
 
57325
 
57326
 
57327
 
57328
 
57329
 
57330
 
57331
 
57332
 
57333
 
57334
 
57335
 
57336
 
57337
 
57338
 
57339
 
57340
 
57341
 
57342
 
57343
 
57344
 
57345
 
57346
 
57347
 
57348
 
57349
 
57350
 
57351
 
57352
 
57353
 
57354
 
57355
 
57356
 
57357
 
57358
 
57359
 
57360
 
57361
 
57362
 
57363
 
57364
 
57365
 
57366
 
57367
 
57368
 
57369
 
57370
 
57371
 
57372
 
57373
 
57374
 
57375
 
57376
 
57377
 
57378
 
57379
 
57380
 
57381
 
57382
 
57383
 
57384
 
57385
 
57386
 
57387
 
57388
 
57389
 
57390
 
57391
 
57392
 
57393
 
57394
 
57395
 
57396
 
57397
 
57398
 
57399
 
57400
 
57401
 
57402
 
57403
 
57404
 
57405
 
57406
 
57407
 
57408
 
57409
 
57410
 
57411
 
57412
 
57413
 
57414
 
57415
 
57416
 
57417
 
57418
 
57419
 
57420
 
57421
 
57422
 
57423
 
57424
 
57425
 
57426
 
57427
 
57428
 
57429
 
57430
 
57431
 
57432
 
57433
 
57434
 
57435
 
57436
 
57437
 
57438
 
57439
 
57440
 
57441
 
57442
 
57443
 
57444
 
57445
 
57446
 
57447
 
57448
 
57449
 
57450
 
57451
 
57452
 
57453
 
57454
 
57455
 
57456
 
57457
 
57458
 
57459
 
57460
 
57461
 
57462
 
57463
 
57464
 
57465
 
57466
 
57467
 
57468
 
57469
 
57470
 
57471
 
57472
 
57473
 
57474
 
57475
 
57476
 
57477
 
57478
 
57479
 
57480
 
57481
 
57482
 
57483
 
57484
 
57485
 
57486
 
57487
 
57488
 
57489
 
57490
 
57491
 
57492
 
57493
 
57494
 
57495
 
57496
 
57497
 
57498
 
57499
 
57500
 
57501
 
57502
 
57503
 
57504
 
57505
 
57506
 
57507
 
57508
 
57509
 
57510
 
57511
 
57512
 
57513
 
57514
 
57515
 
57516
 
57517
 
57518
 
57519
 
57520
 
57521
 
57522
 
57523
 
57524
 
57525
 
57526
 
57527
 
57528
 
57529
 
57530
 
57531
 
57532
 
57533
 
57534
 
57535
 
57536
 
57537
 
57538
 
57539
 
57540
 
57541
 
57542
 
57543
 
57544
 
57545
 
57546
 
57547
 
57548
 
57549
 
57550
 
57551
 
57552
 
57553
 
57554
 
57555
 
57556
 
57557
 
57558
 
57559
 
57560
 
57561
 
57562
 
57563
 
57564
 
57565
 
57566
 
57567
 
57568
 
57569
 
57570
 
57571
 
57572
 
57573
 
57574
 
57575
 
57576
 
57577
 
57578
 
57579
 
57580
 
57581
 
57582
 
57583
 
57584
 
57585
 
57586
 
57587
 
57588
 
57589
 
57590
 
57591
 
57592
 
57593
 
57594
 
57595
 
57596
 
57597
 
57598
 
57599
 
57600
 
57601
 
57602
 
57603
 
57604
 
57605
 
57606
 
57607
 
57608
 
57609
 
57610
 
57611
 
57612
 
57613
 
57614
 
57615
 
57616
 
57617
 
57618
 
57619
 
57620
 
57621
 
57622
 
57623
 
57624
 
57625
 
57626
 
57627
 
57628
 
57629
 
57630
 
57631
 
57632
 
57633
 
57634
 
57635
 
57636
 
57637
 
57638
 
57639
 
57640
 
57641
 
57642
 
57643
 
57644
 
57645
 
57646
 
57647
 
57648
 
57649
 
57650
 
57651
 
57652
 
57653
 
57654
 
57655
 
57656
 
57657
 
57658
 
57659
 
57660
 
57661
 
57662
 
57663
 
57664
 
57665
 
57666
 
57667
 
57668
 
57669
 
57670
 
57671
 
57672
 
57673
 
57674
 
57675
 
57676
 
57677
 
57678
 
57679
 
57680
 
57681
 
57682
 
57683
 
57684
 
57685
 
57686
 
57687
 
57688
 
57689
 
57690
 
57691
 
57692
 
57693
 
57694
 
57695
 
57696
 
57697
 
57698
 
57699
 
57700
 
57701
 
57702
 
57703
 
57704
 
57705
 
57706
 
57707
 
57708
 
57709
 
57710
 
57711
 
57712
 
57713
 
57714
 
57715
 
57716
 
57717
 
57718
 
57719
 
57720
 
57721
 
57722
 
57723
 
57724
 
57725
 
57726
 
57727
 
57728
 
57729
 
57730
 
57731
 
57732
 
57733
 
57734
 
57735
 
57736
 
57737
 
57738
 
57739
 
57740
 
57741
 
57742
 
57743
 
57744
 
57745
 
57746
 
57747
 
57748
 
57749
 
57750
 
57751
 
57752
 
57753
 
57754
 
57755
 
57756
 
57757
 
57758
 
57759
 
57760
 
57761
 
57762
 
57763
 
57764
 
57765
 
57766
 
57767
 
57768
 
57769
 
57770
 
57771
 
57772
 
57773
 
57774
 
57775
 
57776
 
57777
 
57778
 
57779
 
57780
 
57781
 
57782
 
57783
 
57784
 
57785
 
57786
 
57787
 
57788
 
57789
 
57790
 
57791
 
57792
 
57793
 
57794
 
57795
 
57796
 
57797
 
57798
 
57799
 
57800
 
57801
 
57802
 
57803
 
57804
 
57805
 
57806
 
57807
 
57808
 
57809
 
57810
 
57811
 
57812
 
57813
 
57814
 
57815
 
57816
 
57817
 
57818
 
57819
 
57820
 
57821
 
57822
 
57823
 
57824
 
57825
 
57826
 
57827
 
57828
 
57829
 
57830
 
57831
 
57832
 
57833
 
57834
 
57835
 
57836
 
57837
 
57838
 
57839
 
57840
 
57841
 
57842
 
57843
 
57844
 
57845
 
57846
 
57847
 
57848
 
57849
 
57850
 
57851
 
57852
 
57853
 
57854
 
57855
 
57856
 
57857
 
57858
 
57859
 
57860
 
57861
 
57862
 
57863
 
57864
 
57865
 
57866
 
57867
 
57868
 
57869
 
57870
 
57871
 
57872
 
57873
 
57874
 
57875
 
57876
 
57877
 
57878
 
57879
 
57880
 
57881
 
57882
 
57883
 
57884
 
57885
 
57886
 
57887
 
57888
 
57889
 
57890
 
57891
 
57892
 
57893
 
57894
 
57895
 
57896
 
57897
 
57898
 
57899
 
57900
 
57901
 
57902
 
57903
 
57904
 
57905
 
57906
 
57907
 
57908
 
57909
 
57910
 
57911
 
57912
 
57913
 
57914
 
57915
 
57916
 
57917
 
57918
 
57919
 
57920
 
57921
 
57922
 
57923
 
57924
 
57925
 
57926
 
57927
 
57928
 
57929
 
57930
 
57931
 
57932
 
57933
 
57934
 
57935
 
57936
 
57937
 
57938
 
57939
 
57940
 
57941
 
57942
 
57943
 
57944
 
57945
 
57946
 
57947
 
57948
 
57949
 
57950
 
57951
 
57952
 
57953
 
57954
 
57955
 
57956
 
57957
 
57958
 
57959
 
57960
 
57961
 
57962
 
57963
 
57964
 
57965
 
57966
 
57967
 
57968
 
57969
 
57970
 
57971
 
57972
 
57973
 
57974
 
57975
 
57976
 
57977
 
57978
 
57979
 
57980
 
57981
 
57982
 
57983
 
57984
 
57985
 
57986
 
57987
 
57988
 
57989
 
57990
 
57991
 
57992
 
57993
 
57994
 
57995
 
57996
 
57997
 
57998
 
57999
 
58000
 
58001
 
58002
 
58003
 
58004
 
58005
 
58006
 
58007
 
58008
 
58009
 
58010
 
58011
 
58012
 
58013
 
58014
 
58015
 
58016
 
58017
 
58018
 
58019
 
58020
 
58021
 
58022
 
58023
 
58024
 
58025
 
58026
 
58027
 
58028
 
58029
 
58030
 
58031
 
58032
 
58033
 
58034
 
58035
 
58036
 
58037
 
58038
 
58039
 
58040
 
58041
 
58042
 
58043
 
58044
 
58045
 
58046
 
58047
 
58048
 
58049
 
58050
 
58051
 
58052
 
58053
 
58054
 
58055
 
58056
 
58057
 
58058
 
58059
 
58060
 
58061
 
58062
 
58063
 
58064
 
58065
 
58066
 
58067
 
58068
 
58069
 
58070
 
58071
 
58072
 
58073
 
58074
 
58075
 
58076
 
58077
 
58078
 
58079
 
58080
 
58081
 
58082
 
58083
 
58084
 
58085
 
58086
 
58087
 
58088
 
58089
 
58090
 
58091
 
58092
 
58093
 
58094
 
58095
 
58096
 
58097
 
58098
 
58099
 
58100
 
58101
 
58102
 
58103
 
58104
 
58105
 
58106
 
58107
 
58108
 
58109
 
58110
 
58111
 
58112
 
58113
 
58114
 
58115
 
58116
 
58117
 
58118
 
58119
 
58120
 
58121
 
58122
 
58123
 
58124
 
58125
 
58126
 
58127
 
58128
 
58129
 
58130
 
58131
 
58132
 
58133
 
58134
 
58135
 
58136
 
58137
 
58138
 
58139
 
58140
 
58141
 
58142
 
58143
 
58144
 
58145
 
58146
 
58147
 
58148
 
58149
 
58150
 
58151
 
58152
 
58153
 
58154
 
58155
 
58156
 
58157
 
58158
 
58159
 
58160
 
58161
 
58162
 
58163
 
58164
 
58165
 
58166
 
58167
 
58168
 
58169
 
58170
 
58171
 
58172
 
58173
 
58174
 
58175
 
58176
 
58177
 
58178
 
58179
 
58180
 
58181
 
58182
 
58183
 
58184
 
58185
 
58186
 
58187
 
58188
 
58189
 
58190
 
58191
 
58192
 
58193
 
58194
 
58195
 
58196
 
58197
 
58198
 
58199
 
58200
 
58201
 
58202
 
58203
 
58204
 
58205
 
58206
 
58207
 
58208
 
58209
 
58210
 
58211
 
58212
 
58213
 
58214
 
58215
 
58216
 
58217
 
58218
 
58219
 
58220
 
58221
 
58222
 
58223
 
58224
 
58225
 
58226
 
58227
 
58228
 
58229
 
58230
 
58231
 
58232
 
58233
 
58234
 
58235
 
58236
 
58237
 
58238
 
58239
 
58240
 
58241
 
58242
 
58243
 
58244
 
58245
 
58246
 
58247
 
58248
 
58249
 
58250
 
58251
 
58252
 
58253
 
58254
 
58255
 
58256
 
58257
 
58258
 
58259
 
58260
 
58261
 
58262
 
58263
 
58264
 
58265
 
58266
 
58267
 
58268
 
58269
 
58270
 
58271
 
58272
 
58273
 
58274
 
58275
 
58276
 
58277
 
58278
 
58279
 
58280
 
58281
 
58282
 
58283
 
58284
 
58285
 
58286
 
58287
 
58288
 
58289
 
58290
 
58291
 
58292
 
58293
 
58294
 
58295
 
58296
 
58297
 
58298
 
58299
 
58300
 
58301
 
58302
 
58303
 
58304
 
58305
 
58306
 
58307
 
58308
 
58309
 
58310
 
58311
 
58312
 
58313
 
58314
 
58315
 
58316
 
58317
 
58318
 
58319
 
58320
 
58321
 
58322
 
58323
 
58324
 
58325
 
58326
 
58327
 
58328
 
58329
 
58330
 
58331
 
58332
 
58333
 
58334
 
58335
 
58336
 
58337
 
58338
 
58339
 
58340
 
58341
 
58342
 
58343
 
58344
 
58345
 
58346
 
58347
 
58348
 
58349
 
58350
 
58351
 
58352
 
58353
 
58354
 
58355
 
58356
 
58357
 
58358
 
58359
 
58360
 
58361
 
58362
 
58363
 
58364
 
58365
 
58366
 
58367
 
58368
 
58369
 
58370
 
58371
 
58372
 
58373
 
58374
 
58375
 
58376
 
58377
 
58378
 
58379
 
58380
 
58381
 
58382
 
58383
 
58384
 
58385
 
58386
 
58387
 
58388
 
58389
 
58390
 
58391
 
58392
 
58393
 
58394
 
58395
 
58396
 
58397
 
58398
 
58399
 
58400
 
58401
 
58402
 
58403
 
58404
 
58405
 
58406
 
58407
 
58408
 
58409
 
58410
 
58411
 
58412
 
58413
 
58414
 
58415
 
58416
 
58417
 
58418
 
58419
 
58420
 
58421
 
58422
 
58423
 
58424
 
58425
 
58426
 
58427
 
58428
 
58429
 
58430
 
58431
 
58432
 
58433
 
58434
 
58435
 
58436
 
58437
 
58438
 
58439
 
58440
 
58441
 
58442
 
58443
 
58444
 
58445
 
58446
 
58447
 
58448
 
58449
 
58450
 
58451
 
58452
 
58453
 
58454
 
58455
 
58456
 
58457
 
58458
 
58459
 
58460
 
58461
 
58462
 
58463
 
58464
 
58465
 
58466
 
58467
 
58468
 
58469
 
58470
 
58471
 
58472
 
58473
 
58474
 
58475
 
58476
 
58477
 
58478
 
58479
 
58480
 
58481
 
58482
 
58483
 
58484
 
58485
 
58486
 
58487
 
58488
 
58489
 
58490
 
58491
 
58492
 
58493
 
58494
 
58495
 
58496
 
58497
 
58498
 
58499
 
58500
 
58501
 
58502
 
58503
 
58504
 
58505
 
58506
 
58507
 
58508
 
58509
 
58510
 
58511
 
58512
 
58513
 
58514
 
58515
 
58516
 
58517
 
58518
 
58519
 
58520
 
58521
 
58522
 
58523
 
58524
 
58525
 
58526
 
58527
 
58528
 
58529
 
58530
 
58531
 
58532
 
58533
 
58534
 
58535
 
58536
 
58537
 
58538
 
58539
 
58540
 
58541
 
58542
 
58543
 
58544
 
58545
 
58546
 
58547
 
58548
 
58549
 
58550
 
58551
 
58552
 
58553
 
58554
 
58555
 
58556
 
58557
 
58558
 
58559
 
58560
 
58561
 
58562
 
58563
 
58564
 
58565
 
58566
 
58567
 
58568
 
58569
 
58570
 
58571
 
58572
 
58573
 
58574
 
58575
 
58576
 
58577
 
58578
 
58579
 
58580
 
58581
 
58582
 
58583
 
58584
 
58585
 
58586
 
58587
 
58588
 
58589
 
58590
 
58591
 
58592
 
58593
 
58594
 
58595
 
58596
 
58597
 
58598
 
58599
 
58600
 
58601
 
58602
 
58603
 
58604
 
58605
 
58606
 
58607
 
58608
 
58609
 
58610
 
58611
 
58612
 
58613
 
58614
 
58615
 
58616
 
58617
 
58618
 
58619
 
58620
 
58621
 
58622
 
58623
 
58624
 
58625
 
58626
 
58627
 
58628
 
58629
 
58630
 
58631
 
58632
 
58633
 
58634
 
58635
 
58636
 
58637
 
58638
 
58639
 
58640
 
58641
 
58642
 
58643
 
58644
 
58645
 
58646
 
58647
 
58648
 
58649
 
58650
 
58651
 
58652
 
58653
 
58654
 
58655
 
58656
 
58657
 
58658
 
58659
 
58660
 
58661
 
58662
 
58663
 
58664
 
58665
 
58666
 
58667
 
58668
 
58669
 
58670
 
58671
 
58672
 
58673
 
58674
 
58675
 
58676
 
58677
 
58678
 
58679
 
58680
 
58681
 
58682
 
58683
 
58684
 
58685
 
58686
 
58687
 
58688
 
58689
 
58690
 
58691
 
58692
 
58693
 
58694
 
58695
 
58696
 
58697
 
58698
 
58699
 
58700
 
58701
 
58702
 
58703
 
58704
 
58705
 
58706
 
58707
 
58708
 
58709
 
58710
 
58711
 
58712
 
58713
 
58714
 
58715
 
58716
 
58717
 
58718
 
58719
 
58720
 
58721
 
58722
 
58723
 
58724
 
58725
 
58726
 
58727
 
58728
 
58729
 
58730
 
58731
 
58732
 
58733
 
58734
 
58735
 
58736
 
58737
 
58738
 
58739
 
58740
 
58741
 
58742
 
58743
 
58744
 
58745
 
58746
 
58747
 
58748
 
58749
 
58750
 
58751
 
58752
 
58753
 
58754
 
58755
 
58756
 
58757
 
58758
 
58759
 
58760
 
58761
 
58762
 
58763
 
58764
 
58765
 
58766
 
58767
 
58768
 
58769
 
58770
 
58771
 
58772
 
58773
 
58774
 
58775
 
58776
 
58777
 
58778
 
58779
 
58780
 
58781
 
58782
 
58783
 
58784
 
58785
 
58786
 
58787
 
58788
 
58789
 
58790
 
58791
 
58792
 
58793
 
58794
 
58795
 
58796
 
58797
 
58798
 
58799
 
58800
 
58801
 
58802
 
58803
 
58804
 
58805
 
58806
 
58807
 
58808
 
58809
 
58810
 
58811
 
58812
 
58813
 
58814
 
58815
 
58816
 
58817
 
58818
 
58819
 
58820
 
58821
 
58822
 
58823
 
58824
 
58825
 
58826
 
58827
 
58828
 
58829
 
58830
 
58831
 
58832
 
58833
 
58834
 
58835
 
58836
 
58837
 
58838
 
58839
 
58840
 
58841
 
58842
 
58843
 
58844
 
58845
 
58846
 
58847
 
58848
 
58849
 
58850
 
58851
 
58852
 
58853
 
58854
 
58855
 
58856
 
58857
 
58858
 
58859
 
58860
 
58861
 
58862
 
58863
 
58864
 
58865
 
58866
 
58867
 
58868
 
58869
 
58870
 
58871
 
58872
 
58873
 
58874
 
58875
 
58876
 
58877
 
58878
 
58879
 
58880
 
58881
 
58882
 
58883
 
58884
 
58885
 
58886
 
58887
 
58888
 
58889
 
58890
 
58891
 
58892
 
58893
 
58894
 
58895
 
58896
 
58897
 
58898
 
58899
 
58900
 
58901
 
58902
 
58903
 
58904
 
58905
 
58906
 
58907
 
58908
 
58909
 
58910
 
58911
 
58912
 
58913
 
58914
 
58915
 
58916
 
58917
 
58918
 
58919
 
58920
 
58921
 
58922
 
58923
 
58924
 
58925
 
58926
 
58927
 
58928
 
58929
 
58930
 
58931
 
58932
 
58933
 
58934
 
58935
 
58936
 
58937
 
58938
 
58939
 
58940
 
58941
 
58942
 
58943
 
58944
 
58945
 
58946
 
58947
 
58948
 
58949
 
58950
 
58951
 
58952
 
58953
 
58954
 
58955
 
58956
 
58957
 
58958
 
58959
 
58960
 
58961
 
58962
 
58963
 
58964
 
58965
 
58966
 
58967
 
58968
 
58969
 
58970
 
58971
 
58972
 
58973
 
58974
 
58975
 
58976
 
58977
 
58978
 
58979
 
58980
 
58981
 
58982
 
58983
 
58984
 
58985
 
58986
 
58987
 
58988
 
58989
 
58990
 
58991
 
58992
 
58993
 
58994
 
58995
 
58996
 
58997
 
58998
 
58999
 
59000
 
59001
 
59002
 
59003
 
59004
 
59005
 
59006
 
59007
 
59008
 
59009
 
59010
 
59011
 
59012
 
59013
 
59014
 
59015
 
59016
 
59017
 
59018
 
59019
 
59020
 
59021
 
59022
 
59023
 
59024
 
59025
 
59026
 
59027
 
59028
 
59029
 
59030
 
59031
 
59032
 
59033
 
59034
 
59035
 
59036
 
59037
 
59038
 
59039
 
59040
 
59041
 
59042
 
59043
 
59044
 
59045
 
59046
 
59047
 
59048
 
59049
 
59050
 
59051
 
59052
 
59053
 
59054
 
59055
 
59056
 
59057
 
59058
 
59059
 
59060
 
59061
 
59062
 
59063
 
59064
 
59065
 
59066
 
59067
 
59068
 
59069
 
59070
 
59071
 
59072
 
59073
 
59074
 
59075
 
59076
 
59077
 
59078
 
59079
 
59080
 
59081
 
59082
 
59083
 
59084
 
59085
 
59086
 
59087
 
59088
 
59089
 
59090
 
59091
 
59092
 
59093
 
59094
 
59095
 
59096
 
59097
 
59098
 
59099
 
59100
 
59101
 
59102
 
59103
 
59104
 
59105
 
59106
 
59107
 
59108
 
59109
 
59110
 
59111
 
59112
 
59113
 
59114
 
59115
 
59116
 
59117
 
59118
 
59119
 
59120
 
59121
 
59122
 
59123
 
59124
 
59125
 
59126
 
59127
 
59128
 
59129
 
59130
 
59131
 
59132
 
59133
 
59134
 
59135
 
59136
 
59137
 
59138
 
59139
 
59140
 
59141
 
59142
 
59143
 
59144
 
59145
 
59146
 
59147
 
59148
 
59149
 
59150
 
59151
 
59152
 
59153
 
59154
 
59155
 
59156
 
59157
 
59158
 
59159
 
59160
 
59161
 
59162
 
59163
 
59164
 
59165
 
59166
 
59167
 
59168
 
59169
 
59170
 
59171
 
59172
 
59173
 
59174
 
59175
 
59176
 
59177
 
59178
 
59179
 
59180
 
59181
 
59182
 
59183
 
59184
 
59185
 
59186
 
59187
 
59188
 
59189
 
59190
 
59191
 
59192
 
59193
 
59194
 
59195
 
59196
 
59197
 
59198
 
59199
 
59200
 
59201
 
59202
 
59203
 
59204
 
59205
 
59206
 
59207
 
59208
 
59209
 
59210
 
59211
 
59212
 
59213
 
59214
 
59215
 
59216
 
59217
 
59218
 
59219
 
59220
 
59221
 
59222
 
59223
 
59224
 
59225
 
59226
 
59227
 
59228
 
59229
 
59230
 
59231
 
59232
 
59233
 
59234
 
59235
 
59236
 
59237
 
59238
 
59239
 
59240
 
59241
 
59242
 
59243
 
59244
 
59245
 
59246
 
59247
 
59248
 
59249
 
59250
 
59251
 
59252
 
59253
 
59254
 
59255
 
59256
 
59257
 
59258
 
59259
 
59260
 
59261
 
59262
 
59263
 
59264
 
59265
 
59266
 
59267
 
59268
 
59269
 
59270
 
59271
 
59272
 
59273
 
59274
 
59275
 
59276
 
59277
 
59278
 
59279
 
59280
 
59281
 
59282
 
59283
 
59284
 
59285
 
59286
 
59287
 
59288
 
59289
 
59290
 
59291
 
59292
 
59293
 
59294
 
59295
 
59296
 
59297
 
59298
 
59299
 
59300
 
59301
 
59302
 
59303
 
59304
 
59305
 
59306
 
59307
 
59308
 
59309
 
59310
 
59311
 
59312
 
59313
 
59314
 
59315
 
59316
 
59317
 
59318
 
59319
 
59320
 
59321
 
59322
 
59323
 
59324
 
59325
 
59326
 
59327
 
59328
 
59329
 
59330
 
59331
 
59332
 
59333
 
59334
 
59335
 
59336
 
59337
 
59338
 
59339
 
59340
 
59341
 
59342
 
59343
 
59344
 
59345
 
59346
 
59347
 
59348
 
59349
 
59350
 
59351
 
59352
 
59353
 
59354
 
59355
 
59356
 
59357
 
59358
 
59359
 
59360
 
59361
 
59362
 
59363
 
59364
 
59365
 
59366
 
59367
 
59368
 
59369
 
59370
 
59371
 
59372
 
59373
 
59374
 
59375
 
59376
 
59377
 
59378
 
59379
 
59380
 
59381
 
59382
 
59383
 
59384
 
59385
 
59386
 
59387
 
59388
 
59389
 
59390
 
59391
 
59392
 
59393
 
59394
 
59395
 
59396
 
59397
 
59398
 
59399
 
59400
 
59401
 
59402
 
59403
 
59404
 
59405
 
59406
 
59407
 
59408
 
59409
 
59410
 
59411
 
59412
 
59413
 
59414
 
59415
 
59416
 
59417
 
59418
 
59419
 
59420
 
59421
 
59422
 
59423
 
59424
 
59425
 
59426
 
59427
 
59428
 
59429
 
59430
 
59431
 
59432
 
59433
 
59434
 
59435
 
59436
 
59437
 
59438
 
59439
 
59440
 
59441
 
59442
 
59443
 
59444
 
59445
 
59446
 
59447
 
59448
 
59449
 
59450
 
59451
 
59452
 
59453
 
59454
 
59455
 
59456
 
59457
 
59458
 
59459
 
59460
 
59461
 
59462
 
59463
 
59464
 
59465
 
59466
 
59467
 
59468
 
59469
 
59470
 
59471
 
59472
 
59473
 
59474
 
59475
 
59476
 
59477
 
59478
 
59479
 
59480
 
59481
 
59482
 
59483
 
59484
 
59485
 
59486
 
59487
 
59488
 
59489
 
59490
 
59491
 
59492
 
59493
 
59494
 
59495
 
59496
 
59497
 
59498
 
59499
 
59500
 
59501
 
59502
 
59503
 
59504
 
59505
 
59506
 
59507
 
59508
 
59509
 
59510
 
59511
 
59512
 
59513
 
59514
 
59515
 
59516
 
59517
 
59518
 
59519
 
59520
 
59521
 
59522
 
59523
 
59524
 
59525
 
59526
 
59527
 
59528
 
59529
 
59530
 
59531
 
59532
 
59533
 
59534
 
59535
 
59536
 
59537
 
59538
 
59539
 
59540
 
59541
 
59542
 
59543
 
59544
 
59545
 
59546
 
59547
 
59548
 
59549
 
59550
 
59551
 
59552
 
59553
 
59554
 
59555
 
59556
 
59557
 
59558
 
59559
 
59560
 
59561
 
59562
 
59563
 
59564
 
59565
 
59566
 
59567
 
59568
 
59569
 
59570
 
59571
 
59572
 
59573
 
59574
 
59575
 
59576
 
59577
 
59578
 
59579
 
59580
 
59581
 
59582
 
59583
 
59584
 
59585
 
59586
 
59587
 
59588
 
59589
 
59590
 
59591
 
59592
 
59593
 
59594
 
59595
 
59596
 
59597
 
59598
 
59599
 
59600
 
59601
 
59602
 
59603
 
59604
 
59605
 
59606
 
59607
 
59608
 
59609
 
59610
 
59611
 
59612
 
59613
 
59614
 
59615
 
59616
 
59617
 
59618
 
59619
 
59620
 
59621
 
59622
 
59623
 
59624
 
59625
 
59626
 
59627
 
59628
 
59629
 
59630
 
59631
 
59632
 
59633
 
59634
 
59635
 
59636
 
59637
 
59638
 
59639
 
59640
 
59641
 
59642
 
59643
 
59644
 
59645
 
59646
 
59647
 
59648
 
59649
 
59650
 
59651
 
59652
 
59653
 
59654
 
59655
 
59656
 
59657
 
59658
 
59659
 
59660
 
59661
 
59662
 
59663
 
59664
 
59665
 
59666
 
59667
 
59668
 
59669
 
59670
 
59671
 
59672
 
59673
 
59674
 
59675
 
59676
 
59677
 
59678
 
59679
 
59680
 
59681
 
59682
 
59683
 
59684
 
59685
 
59686
 
59687
 
59688
 
59689
 
59690
 
59691
 
59692
 
59693
 
59694
 
59695
 
59696
 
59697
 
59698
 
59699
 
59700
 
59701
 
59702
 
59703
 
59704
 
59705
 
59706
 
59707
 
59708
 
59709
 
59710
 
59711
 
59712
 
59713
 
59714
 
59715
 
59716
 
59717
 
59718
 
59719
 
59720
 
59721
 
59722
 
59723
 
59724
 
59725
 
59726
 
59727
 
59728
 
59729
 
59730
 
59731
 
59732
 
59733
 
59734
 
59735
 
59736
 
59737
 
59738
 
59739
 
59740
 
59741
 
59742
 
59743
 
59744
 
59745
 
59746
 
59747
 
59748
 
59749
 
59750
 
59751
 
59752
 
59753
 
59754
 
59755
 
59756
 
59757
 
59758
 
59759
 
59760
 
59761
 
59762
 
59763
 
59764
 
59765
 
59766
 
59767
 
59768
 
59769
 
59770
 
59771
 
59772
 
59773
 
59774
 
59775
 
59776
 
59777
 
59778
 
59779
 
59780
 
59781
 
59782
 
59783
 
59784
 
59785
 
59786
 
59787
 
59788
 
59789
 
59790
 
59791
 
59792
 
59793
 
59794
 
59795
 
59796
 
59797
 
59798
 
59799
 
59800
 
59801
 
59802
 
59803
 
59804
 
59805
 
59806
 
59807
 
59808
 
59809
 
59810
 
59811
 
59812
 
59813
 
59814
 
59815
 
59816
 
59817
 
59818
 
59819
 
59820
 
59821
 
59822
 
59823
 
59824
 
59825
 
59826
 
59827
 
59828
 
59829
 
59830
 
59831
 
59832
 
59833
 
59834
 
59835
 
59836
 
59837
 
59838
 
59839
 
59840
 
59841
 
59842
 
59843
 
59844
 
59845
 
59846
 
59847
 
59848
 
59849
 
59850
 
59851
 
59852
 
59853
 
59854
 
59855
 
59856
 
59857
 
59858
 
59859
 
59860
 
59861
 
59862
 
59863
 
59864
 
59865
 
59866
 
59867
 
59868
 
59869
 
59870
 
59871
 
59872
 
59873
 
59874
 
59875
 
59876
 
59877
 
59878
 
59879
 
59880
 
59881
 
59882
 
59883
 
59884
 
59885
 
59886
 
59887
 
59888
 
59889
 
59890
 
59891
 
59892
 
59893
 
59894
 
59895
 
59896
 
59897
 
59898
 
59899
 
59900
 
59901
 
59902
 
59903
 
59904
 
59905
 
59906
 
59907
 
59908
 
59909
 
59910
 
59911
 
59912
 
59913
 
59914
 
59915
 
59916
 
59917
 
59918
 
59919
 
59920
 
59921
 
59922
 
59923
 
59924
 
59925
 
59926
 
59927
 
59928
 
59929
 
59930
 
59931
 
59932
 
59933
 
59934
 
59935
 
59936
 
59937
 
59938
 
59939
 
59940
 
59941
 
59942
 
59943
 
59944
 
59945
 
59946
 
59947
 
59948
 
59949
 
59950
 
59951
 
59952
 
59953
 
59954
 
59955
 
59956
 
59957
 
59958
 
59959
 
59960
 
59961
 
59962
 
59963
 
59964
 
59965
 
59966
 
59967
 
59968
 
59969
 
59970
 
59971
 
59972
 
59973
 
59974
 
59975
 
59976
 
59977
 
59978
 
59979
 
59980
 
59981
 
59982
 
59983
 
59984
 
59985
 
59986
 
59987
 
59988
 
59989
 
59990
 
59991
 
59992
 
59993
 
59994
 
59995
 
59996
 
59997
 
59998
 
59999
 
60000
 
60001
 
60002
 
60003
 
60004
 
60005
 
60006
 
60007
 
60008
 
60009
 
60010
 
60011
 
60012
 
60013
 
60014
 
60015
 
60016
 
60017
 
60018
 
60019
 
60020
 
60021
 
60022
 
60023
 
60024
 
60025
 
60026
 
60027
 
60028
 
60029
 
60030
 
60031
 
60032
 
60033
 
60034
 
60035
 
60036
 
60037
 
60038
 
60039
 
60040
 
60041
 
60042
 
60043
 
60044
 
60045
 
60046
 
60047
 
60048
 
60049
 
60050
 
60051
 
60052
 
60053
 
60054
 
60055
 
60056
 
60057
 
60058
 
60059
 
60060
 
60061
 
60062
 
60063
 
60064
 
60065
 
60066
 
60067
 
60068
 
60069
 
60070
 
60071
 
60072
 
60073
 
60074
 
60075
 
60076
 
60077
 
60078
 
60079
 
60080
 
60081
 
60082
 
60083
 
60084
 
60085
 
60086
 
60087
 
60088
 
60089
 
60090
 
60091
 
60092
 
60093
 
60094
 
60095
 
60096
 
60097
 
60098
 
60099
 
60100
 
60101
 
60102
 
60103
 
60104
 
60105
 
60106
 
60107
 
60108
 
60109
 
60110
 
60111
 
60112
 
60113
 
60114
 
60115
 
60116
 
60117
 
60118
 
60119
 
60120
 
60121
 
60122
 
60123
 
60124
 
60125
 
60126
 
60127
 
60128
 
60129
 
60130
 
60131
 
60132
 
60133
 
60134
 
60135
 
60136
 
60137
 
60138
 
60139
 
60140
 
60141
 
60142
 
60143
 
60144
 
60145
 
60146
 
60147
 
60148
 
60149
 
60150
 
60151
 
60152
 
60153
 
60154
 
60155
 
60156
 
60157
 
60158
 
60159
 
60160
 
60161
 
60162
 
60163
 
60164
 
60165
 
60166
 
60167
 
60168
 
60169
 
60170
 
60171
 
60172
 
60173
 
60174
 
60175
 
60176
 
60177
 
60178
 
60179
 
60180
 
60181
 
60182
 
60183
 
60184
 
60185
 
60186
 
60187
 
60188
 
60189
 
60190
 
60191
 
60192
 
60193
 
60194
 
60195
 
60196
 
60197
 
60198
 
60199
 
60200
 
60201
 
60202
 
60203
 
60204
 
60205
 
60206
 
60207
 
60208
 
60209
 
60210
 
60211
 
60212
 
60213
 
60214
 
60215
 
60216
 
60217
 
60218
 
60219
 
60220
 
60221
 
60222
 
60223
 
60224
 
60225
 
60226
 
60227
 
60228
 
60229
 
60230
 
60231
 
60232
 
60233
 
60234
 
60235
 
60236
 
60237
 
60238
 
60239
 
60240
 
60241
 
60242
 
60243
 
60244
 
60245
 
60246
 
60247
 
60248
 
60249
 
60250
 
60251
 
60252
 
60253
 
60254
 
60255
 
60256
 
60257
 
60258
 
60259
 
60260
 
60261
 
60262
 
60263
 
60264
 
60265
 
60266
 
60267
 
60268
 
60269
 
60270
 
60271
 
60272
 
60273
 
60274
 
60275
 
60276
 
60277
 
60278
 
60279
 
60280
 
60281
 
60282
 
60283
 
60284
 
60285
 
60286
 
60287
 
60288
 
60289
 
60290
 
60291
 
60292
 
60293
 
60294
 
60295
 
60296
 
60297
 
60298
 
60299
 
60300
 
60301
 
60302
 
60303
 
60304
 
60305
 
60306
 
60307
 
60308
 
60309
 
60310
 
60311
 
60312
 
60313
 
60314
 
60315
 
60316
 
60317
 
60318
 
60319
 
60320
 
60321
 
60322
 
60323
 
60324
 
60325
 
60326
 
60327
 
60328
 
60329
 
60330
 
60331
 
60332
 
60333
 
60334
 
60335
 
60336
 
60337
 
60338
 
60339
 
60340
 
60341
 
60342
 
60343
 
60344
 
60345
 
60346
 
60347
 
60348
 
60349
 
60350
 
60351
 
60352
 
60353
 
60354
 
60355
 
60356
 
60357
 
60358
 
60359
 
60360
 
60361
 
60362
 
60363
 
60364
 
60365
 
60366
 
60367
 
60368
 
60369
 
60370
 
60371
 
60372
 
60373
 
60374
 
60375
 
60376
 
60377
 
60378
 
60379
 
60380
 
60381
 
60382
 
60383
 
60384
 
60385
 
60386
 
60387
 
60388
 
60389
 
60390
 
60391
 
60392
 
60393
 
60394
 
60395
 
60396
 
60397
 
60398
 
60399
 
60400
 
60401
 
60402
 
60403
 
60404
 
60405
 
60406
 
60407
 
60408
 
60409
 
60410
 
60411
 
60412
 
60413
 
60414
 
60415
 
60416
 
60417
 
60418
 
60419
 
60420
 
60421
 
60422
 
60423
 
60424
 
60425
 
60426
 
60427
 
60428
 
60429
 
60430
 
60431
 
60432
 
60433
 
60434
 
60435
 
60436
 
60437
 
60438
 
60439
 
60440
 
60441
 
60442
 
60443
 
60444
 
60445
 
60446
 
60447
 
60448
 
60449
 
60450
 
60451
 
60452
 
60453
 
60454
 
60455
 
60456
 
60457
 
60458
 
60459
 
60460
 
60461
 
60462
 
60463
 
60464
 
60465
 
60466
 
60467
 
60468
 
60469
 
60470
 
60471
 
60472
 
60473
 
60474
 
60475
 
60476
 
60477
 
60478
 
60479
 
60480
 
60481
 
60482
 
60483
 
60484
 
60485
 
60486
 
60487
 
60488
 
60489
 
60490
 
60491
 
60492
 
60493
 
60494
 
60495
 
60496
 
60497
 
60498
 
60499
 
60500
 
60501
 
60502
 
60503
 
60504
 
60505
 
60506
 
60507
 
60508
 
60509
 
60510
 
60511
 
60512
 
60513
 
60514
 
60515
 
60516
 
60517
 
60518
 
60519
 
60520
 
60521
 
60522
 
60523
 
60524
 
60525
 
60526
 
60527
 
60528
 
60529
 
60530
 
60531
 
60532
 
60533
 
60534
 
60535
 
60536
 
60537
 
60538
 
60539
 
60540
 
60541
 
60542
 
60543
 
60544
 
60545
 
60546
 
60547
 
60548
 
60549
 
60550
 
60551
 
60552
 
60553
 
60554
 
60555
 
60556
 
60557
 
60558
 
60559
 
60560
 
60561
 
60562
 
60563
 
60564
 
60565
 
60566
 
60567
 
60568
 
60569
 
60570
 
60571
 
60572
 
60573
 
60574
 
60575
 
60576
 
60577
 
60578
 
60579
 
60580
 
60581
 
60582
 
60583
 
60584
 
60585
 
60586
 
60587
 
60588
 
60589
 
60590
 
60591
 
60592
 
60593
 
60594
 
60595
 
60596
 
60597
 
60598
 
60599
 
60600
 
60601
 
60602
 
60603
 
60604
 
60605
 
60606
 
60607
 
60608
 
60609
 
60610
 
60611
 
60612
 
60613
 
60614
 
60615
 
60616
 
60617
 
60618
 
60619
 
60620
 
60621
 
60622
 
60623
 
60624
 
60625
 
60626
 
60627
 
60628
 
60629
 
60630
 
60631
 
60632
 
60633
 
60634
 
60635
 
60636
 
60637
 
60638
 
60639
 
60640
 
60641
 
60642
 
60643
 
60644
 
60645
 
60646
 
60647
 
60648
 
60649
 
60650
 
60651
 
60652
 
60653
 
60654
 
60655
 
60656
 
60657
 
60658
 
60659
 
60660
 
60661
 
60662
 
60663
 
60664
 
60665
 
60666
 
60667
 
60668
 
60669
 
60670
 
60671
 
60672
 
60673
 
60674
 
60675
 
60676
 
60677
 
60678
 
60679
 
60680
 
60681
 
60682
 
60683
 
60684
 
60685
 
60686
 
60687
 
60688
 
60689
 
60690
 
60691
 
60692
 
60693
 
60694
 
60695
 
60696
 
60697
 
60698
 
60699
 
60700
 
60701
 
60702
 
60703
 
60704
 
60705
 
60706
 
60707
 
60708
 
60709
 
60710
 
60711
 
60712
 
60713
 
60714
 
60715
 
60716
 
60717
 
60718
 
60719
 
60720
 
60721
 
60722
 
60723
 
60724
 
60725
 
60726
 
60727
 
60728
 
60729
 
60730
 
60731
 
60732
 
60733
 
60734
 
60735
 
60736
 
60737
 
60738
 
60739
 
60740
 
60741
 
60742
 
60743
 
60744
 
60745
 
60746
 
60747
 
60748
 
60749
 
60750
 
60751
 
60752
 
60753
 
60754
 
60755
 
60756
 
60757
 
60758
 
60759
 
60760
 
60761
 
60762
 
60763
 
60764
 
60765
 
60766
 
60767
 
60768
 
60769
 
60770
 
60771
 
60772
 
60773
 
60774
 
60775
 
60776
 
60777
 
60778
 
60779
 
60780
 
60781
 
60782
 
60783
 
60784
 
60785
 
60786
 
60787
 
60788
 
60789
 
60790
 
60791
 
60792
 
60793
 
60794
 
60795
 
60796
 
60797
 
60798
 
60799
 
60800
 
60801
 
60802
 
60803
 
60804
 
60805
 
60806
 
60807
 
60808
 
60809
 
60810
 
60811
 
60812
 
60813
 
60814
 
60815
 
60816
 
60817
 
60818
 
60819
 
60820
 
60821
 
60822
 
60823
 
60824
 
60825
 
60826
 
60827
 
60828
 
60829
 
60830
 
60831
 
60832
 
60833
 
60834
 
60835
 
60836
 
60837
 
60838
 
60839
 
60840
 
60841
 
60842
 
60843
 
60844
 
60845
 
60846
 
60847
 
60848
 
60849
 
60850
 
60851
 
60852
 
60853
 
60854
 
60855
 
60856
 
60857
 
60858
 
60859
 
60860
 
60861
 
60862
 
60863
 
60864
 
60865
 
60866
 
60867
 
60868
 
60869
 
60870
 
60871
 
60872
 
60873
 
60874
 
60875
 
60876
 
60877
 
60878
 
60879
 
60880
 
60881
 
60882
 
60883
 
60884
 
60885
 
60886
 
60887
 
60888
 
60889
 
60890
 
60891
 
60892
 
60893
 
60894
 
60895
 
60896
 
60897
 
60898
 
60899
 
60900
 
60901
 
60902
 
60903
 
60904
 
60905
 
60906
 
60907
 
60908
 
60909
 
60910
 
60911
 
60912
 
60913
 
60914
 
60915
 
60916
 
60917
 
60918
 
60919
 
60920
 
60921
 
60922
 
60923
 
60924
 
60925
 
60926
 
60927
 
60928
 
60929
 
60930
 
60931
 
60932
 
60933
 
60934
 
60935
 
60936
 
60937
 
60938
 
60939
 
60940
 
60941
 
60942
 
60943
 
60944
 
60945
 
60946
 
60947
 
60948
 
60949
 
60950
 
60951
 
60952
 
60953
 
60954
 
60955
 
60956
 
60957
 
60958
 
60959
 
60960
 
60961
 
60962
 
60963
 
60964
 
60965
 
60966
 
60967
 
60968
 
60969
 
60970
 
60971
 
60972
 
60973
 
60974
 
60975
 
60976
 
60977
 
60978
 
60979
 
60980
 
60981
 
60982
 
60983
 
60984
 
60985
 
60986
 
60987
 
60988
 
60989
 
60990
 
60991
 
60992
 
60993
 
60994
 
60995
 
60996
 
60997
 
60998
 
60999
 
61000
 
61001
 
61002
 
61003
 
61004
 
61005
 
61006
 
61007
 
61008
 
61009
 
61010
 
61011
 
61012
 
61013
 
61014
 
61015
 
61016
 
61017
 
61018
 
61019
 
61020
 
61021
 
61022
 
61023
 
61024
 
61025
 
61026
 
61027
 
61028
 
61029
 
61030
 
61031
 
61032
 
61033
 
61034
 
61035
 
61036
 
61037
 
61038
 
61039
 
61040
 
61041
 
61042
 
61043
 
61044
 
61045
 
61046
 
61047
 
61048
 
61049
 
61050
 
61051
 
61052
 
61053
 
61054
 
61055
 
61056
 
61057
 
61058
 
61059
 
61060
 
61061
 
61062
 
61063
 
61064
 
61065
 
61066
 
61067
 
61068
 
61069
 
61070
 
61071
 
61072
 
61073
 
61074
 
61075
 
61076
 
61077
 
61078
 
61079
 
61080
 
61081
 
61082
 
61083
 
61084
 
61085
 
61086
 
61087
 
61088
 
61089
 
61090
 
61091
 
61092
 
61093
 
61094
 
61095
 
61096
 
61097
 
61098
 
61099
 
61100
 
61101
 
61102
 
61103
 
61104
 
61105
 
61106
 
61107
 
61108
 
61109
 
61110
 
61111
 
61112
 
61113
 
61114
 
61115
 
61116
 
61117
 
61118
 
61119
 
61120
 
61121
 
61122
 
61123
 
61124
 
61125
 
61126
 
61127
 
61128
 
61129
 
61130
 
61131
 
61132
 
61133
 
61134
 
61135
 
61136
 
61137
 
61138
 
61139
 
61140
 
61141
 
61142
 
61143
 
61144
 
61145
 
61146
 
61147
 
61148
 
61149
 
61150
 
61151
 
61152
 
61153
 
61154
 
61155
 
61156
 
61157
 
61158
 
61159
 
61160
 
61161
 
61162
 
61163
 
61164
 
61165
 
61166
 
61167
 
61168
 
61169
 
61170
 
61171
 
61172
 
61173
 
61174
 
61175
 
61176
 
61177
 
61178
 
61179
 
61180
 
61181
 
61182
 
61183
 
61184
 
61185
 
61186
 
61187
 
61188
 
61189
 
61190
 
61191
 
61192
 
61193
 
61194
 
61195
 
61196
 
61197
 
61198
 
61199
 
61200
 
61201
 
61202
 
61203
 
61204
 
61205
 
61206
 
61207
 
61208
 
61209
 
61210
 
61211
 
61212
 
61213
 
61214
 
61215
 
61216
 
61217
 
61218
 
61219
 
61220
 
61221
 
61222
 
61223
 
61224
 
61225
 
61226
 
61227
 
61228
 
61229
 
61230
 
61231
 
61232
 
61233
 
61234
 
61235
 
61236
 
61237
 
61238
 
61239
 
61240
 
61241
 
61242
 
61243
 
61244
 
61245
 
61246
 
61247
 
61248
 
61249
 
61250
 
61251
 
61252
 
61253
 
61254
 
61255
 
61256
 
61257
 
61258
 
61259
 
61260
 
61261
 
61262
 
61263
 
61264
 
61265
 
61266
 
61267
 
61268
 
61269
 
61270
 
61271
 
61272
 
61273
 
61274
 
61275
 
61276
 
61277
 
61278
 
61279
 
61280
 
61281
 
61282
 
61283
 
61284
 
61285
 
61286
 
61287
 
61288
 
61289
 
61290
 
61291
 
61292
 
61293
 
61294
 
61295
 
61296
 
61297
 
61298
 
61299
 
61300
 
61301
 
61302
 
61303
 
61304
 
61305
 
61306
 
61307
 
61308
 
61309
 
61310
 
61311
 
61312
 
61313
 
61314
 
61315
 
61316
 
61317
 
61318
 
61319
 
61320
 
61321
 
61322
 
61323
 
61324
 
61325
 
61326
 
61327
 
61328
 
61329
 
61330
 
61331
 
61332
 
61333
 
61334
 
61335
 
61336
 
61337
 
61338
 
61339
 
61340
 
61341
 
61342
 
61343
 
61344
 
61345
 
61346
 
61347
 
61348
 
61349
 
61350
 
61351
 
61352
 
61353
 
61354
 
61355
 
61356
 
61357
 
61358
 
61359
 
61360
 
61361
 
61362
 
61363
 
61364
 
61365
 
61366
 
61367
 
61368
 
61369
 
61370
 
61371
 
61372
 
61373
 
61374
 
61375
 
61376
 
61377
 
61378
 
61379
 
61380
 
61381
 
61382
 
61383
 
61384
 
61385
 
61386
 
61387
 
61388
 
61389
 
61390
 
61391
 
61392
 
61393
 
61394
 
61395
 
61396
 
61397
 
61398
 
61399
 
61400
 
61401
 
61402
 
61403
 
61404
 
61405
 
61406
 
61407
 
61408
 
61409
 
61410
 
61411
 
61412
 
61413
 
61414
 
61415
 
61416
 
61417
 
61418
 
61419
 
61420
 
61421
 
61422
 
61423
 
61424
 
61425
 
61426
 
61427
 
61428
 
61429
 
61430
 
61431
 
61432
 
61433
 
61434
 
61435
 
61436
 
61437
 
61438
 
61439
 
61440
 
61441
 
61442
 
61443
 
61444
 
61445
 
61446
 
61447
 
61448
 
61449
 
61450
 
61451
 
61452
 
61453
 
61454
 
61455
 
61456
 
61457
 
61458
 
61459
 
61460
 
61461
 
61462
 
61463
 
61464
 
61465
 
61466
 
61467
 
61468
 
61469
 
61470
 
61471
 
61472
 
61473
 
61474
 
61475
 
61476
 
61477
 
61478
 
61479
 
61480
 
61481
 
61482
 
61483
 
61484
 
61485
 
61486
 
61487
 
61488
 
61489
 
61490
 
61491
 
61492
 
61493
 
61494
 
61495
 
61496
 
61497
 
61498
 
61499
 
61500
 
61501
 
61502
 
61503
 
61504
 
61505
 
61506
 
61507
 
61508
 
61509
 
61510
 
61511
 
61512
 
61513
 
61514
 
61515
 
61516
 
61517
 
61518
 
61519
 
61520
 
61521
 
61522
 
61523
 
61524
 
61525
 
61526
 
61527
 
61528
 
61529
 
61530
 
61531
 
61532
 
61533
 
61534
 
61535
 
61536
 
61537
 
61538
 
61539
 
61540
 
61541
 
61542
 
61543
 
61544
 
61545
 
61546
 
61547
 
61548
 
61549
 
61550
 
61551
 
61552
 
61553
 
61554
 
61555
 
61556
 
61557
 
61558
 
61559
 
61560
 
61561
 
61562
 
61563
 
61564
 
61565
 
61566
 
61567
 
61568
 
61569
 
61570
 
61571
 
61572
 
61573
 
61574
 
61575
 
61576
 
61577
 
61578
 
61579
 
61580
 
61581
 
61582
 
61583
 
61584
 
61585
 
61586
 
61587
 
61588
 
61589
 
61590
 
61591
 
61592
 
61593
 
61594
 
61595
 
61596
 
61597
 
61598
 
61599
 
61600
 
61601
 
61602
 
61603
 
61604
 
61605
 
61606
 
61607
 
61608
 
61609
 
61610
 
61611
 
61612
 
61613
 
61614
 
61615
 
61616
 
61617
 
61618
 
61619
 
61620
 
61621
 
61622
 
61623
 
61624
 
61625
 
61626
 
61627
 
61628
 
61629
 
61630
 
61631
 
61632
 
61633
 
61634
 
61635
 
61636
 
61637
 
61638
 
61639
 
61640
 
61641
 
61642
 
61643
 
61644
 
61645
 
61646
 
61647
 
61648
 
61649
 
61650
 
61651
 
61652
 
61653
 
61654
 
61655
 
61656
 
61657
 
61658
 
61659
 
61660
 
61661
 
61662
 
61663
 
61664
 
61665
 
61666
 
61667
 
61668
 
61669
 
61670
 
61671
 
61672
 
61673
 
61674
 
61675
 
61676
 
61677
 
61678
 
61679
 
61680
 
61681
 
61682
 
61683
 
61684
 
61685
 
61686
 
61687
 
61688
 
61689
 
61690
 
61691
 
61692
 
61693
 
61694
 
61695
 
61696
 
61697
 
61698
 
61699
 
61700
 
61701
 
61702
 
61703
 
61704
 
61705
 
61706
 
61707
 
61708
 
61709
 
61710
 
61711
 
61712
 
61713
 
61714
 
61715
 
61716
 
61717
 
61718
 
61719
 
61720
 
61721
 
61722
 
61723
 
61724
 
61725
 
61726
 
61727
 
61728
 
61729
 
61730
 
61731
 
61732
 
61733
 
61734
 
61735
 
61736
 
61737
 
61738
 
61739
 
61740
 
61741
 
61742
 
61743
 
61744
 
61745
 
61746
 
61747
 
61748
 
61749
 
61750
 
61751
 
61752
 
61753
 
61754
 
61755
 
61756
 
61757
 
61758
 
61759
 
61760
 
61761
 
61762
 
61763
 
61764
 
61765
 
61766
 
61767
 
61768
 
61769
 
61770
 
61771
 
61772
 
61773
 
61774
 
61775
 
61776
 
61777
 
61778
 
61779
 
61780
 
61781
 
61782
 
61783
 
61784
 
61785
 
61786
 
61787
 
61788
 
61789
 
61790
 
61791
 
61792
 
61793
 
61794
 
61795
 
61796
 
61797
 
61798
 
61799
 
61800
 
61801
 
61802
 
61803
 
61804
 
61805
 
61806
 
61807
 
61808
 
61809
 
61810
 
61811
 
61812
 
61813
 
61814
 
61815
 
61816
 
61817
 
61818
 
61819
 
61820
 
61821
 
61822
 
61823
 
61824
 
61825
 
61826
 
61827
 
61828
 
61829
 
61830
 
61831
 
61832
 
61833
 
61834
 
61835
 
61836
 
61837
 
61838
 
61839
 
61840
 
61841
 
61842
 
61843
 
61844
 
61845
 
61846
 
61847
 
61848
 
61849
 
61850
 
61851
 
61852
 
61853
 
61854
 
61855
 
61856
 
61857
 
61858
 
61859
 
61860
 
61861
 
61862
 
61863
 
61864
 
61865
 
61866
 
61867
 
61868
 
61869
 
61870
 
61871
 
61872
 
61873
 
61874
 
61875
 
61876
 
61877
 
61878
 
61879
 
61880
 
61881
 
61882
 
61883
 
61884
 
61885
 
61886
 
61887
 
61888
 
61889
 
61890
 
61891
 
61892
 
61893
 
61894
 
61895
 
61896
 
61897
 
61898
 
61899
 
61900
 
61901
 
61902
 
61903
 
61904
 
61905
 
61906
 
61907
 
61908
 
61909
 
61910
 
61911
 
61912
 
61913
 
61914
 
61915
 
61916
 
61917
 
61918
 
61919
 
61920
 
61921
 
61922
 
61923
 
61924
 
61925
 
61926
 
61927
 
61928
 
61929
 
61930
 
61931
 
61932
 
61933
 
61934
 
61935
 
61936
 
61937
 
61938
 
61939
 
61940
 
61941
 
61942
 
61943
 
61944
 
61945
 
61946
 
61947
 
61948
 
61949
 
61950
 
61951
 
61952
 
61953
 
61954
 
61955
 
61956
 
61957
 
61958
 
61959
 
61960
 
61961
 
61962
 
61963
 
61964
 
61965
 
61966
 
61967
 
61968
 
61969
 
61970
 
61971
 
61972
 
61973
 
61974
 
61975
 
61976
 
61977
 
61978
 
61979
 
61980
 
61981
 
61982
 
61983
 
61984
 
61985
 
61986
 
61987
 
61988
 
61989
 
61990
 
61991
 
61992
 
61993
 
61994
 
61995
 
61996
 
61997
 
61998
 
61999
 
62000
 
62001
 
62002
 
62003
 
62004
 
62005
 
62006
 
62007
 
62008
 
62009
 
62010
 
62011
 
62012
 
62013
 
62014
 
62015
 
62016
 
62017
 
62018
 
62019
 
62020
 
62021
 
62022
 
62023
 
62024
 
62025
 
62026
 
62027
 
62028
 
62029
 
62030
 
62031
 
62032
 
62033
 
62034
 
62035
 
62036
 
62037
 
62038
 
62039
 
62040
 
62041
 
62042
 
62043
 
62044
 
62045
 
62046
 
62047
 
62048
 
62049
 
62050
 
62051
 
62052
 
62053
 
62054
 
62055
 
62056
 
62057
 
62058
 
62059
 
62060
 
62061
 
62062
 
62063
 
62064
 
62065
 
62066
 
62067
 
62068
 
62069
 
62070
 
62071
 
62072
 
62073
 
62074
 
62075
 
62076
 
62077
 
62078
 
62079
 
62080
 
62081
 
62082
 
62083
 
62084
 
62085
 
62086
 
62087
 
62088
 
62089
 
62090
 
62091
 
62092
 
62093
 
62094
 
62095
 
62096
 
62097
 
62098
 
62099
 
62100
 
62101
 
62102
 
62103
 
62104
 
62105
 
62106
 
62107
 
62108
 
62109
 
62110
 
62111
 
62112
 
62113
 
62114
 
62115
 
62116
 
62117
 
62118
 
62119
 
62120
 
62121
 
62122
 
62123
 
62124
 
62125
 
62126
 
62127
 
62128
 
62129
 
62130
 
62131
 
62132
 
62133
 
62134
 
62135
 
62136
 
62137
 
62138
 
62139
 
62140
 
62141
 
62142
 
62143
 
62144
 
62145
 
62146
 
62147
 
62148
 
62149
 
62150
 
62151
 
62152
 
62153
 
62154
 
62155
 
62156
 
62157
 
62158
 
62159
 
62160
 
62161
 
62162
 
62163
 
62164
 
62165
 
62166
 
62167
 
62168
 
62169
 
62170
 
62171
 
62172
 
62173
 
62174
 
62175
 
62176
 
62177
 
62178
 
62179
 
62180
 
62181
 
62182
 
62183
 
62184
 
62185
 
62186
 
62187
 
62188
 
62189
 
62190
 
62191
 
62192
 
62193
 
62194
 
62195
 
62196
 
62197
 
62198
 
62199
 
62200
 
62201
 
62202
 
62203
 
62204
 
62205
 
62206
 
62207
 
62208
 
62209
 
62210
 
62211
 
62212
 
62213
 
62214
 
62215
 
62216
 
62217
 
62218
 
62219
 
62220
 
62221
 
62222
 
62223
 
62224
 
62225
 
62226
 
62227
 
62228
 
62229
 
62230
 
62231
 
62232
 
62233
 
62234
 
62235
 
62236
 
62237
 
62238
 
62239
 
62240
 
62241
 
62242
 
62243
 
62244
 
62245
 
62246
 
62247
 
62248
 
62249
 
62250
 
62251
 
62252
 
62253
 
62254
 
62255
 
62256
 
62257
 
62258
 
62259
 
62260
 
62261
 
62262
 
62263
 
62264
 
62265
 
62266
 
62267
 
62268
 
62269
 
62270
 
62271
 
62272
 
62273
 
62274
 
62275
 
62276
 
62277
 
62278
 
62279
 
62280
 
62281
 
62282
 
62283
 
62284
 
62285
 
62286
 
62287
 
62288
 
62289
 
62290
 
62291
 
62292
 
62293
 
62294
 
62295
 
62296
 
62297
 
62298
 
62299
 
62300
 
62301
 
62302
 
62303
 
62304
 
62305
 
62306
 
62307
 
62308
 
62309
 
62310
 
62311
 
62312
 
62313
 
62314
 
62315
 
62316
 
62317
 
62318
 
62319
 
62320
 
62321
 
62322
 
62323
 
62324
 
62325
 
62326
 
62327
 
62328
 
62329
 
62330
 
62331
 
62332
 
62333
 
62334
 
62335
 
62336
 
62337
 
62338
 
62339
 
62340
 
62341
 
62342
 
62343
 
62344
 
62345
 
62346
 
62347
 
62348
 
62349
 
62350
 
62351
 
62352
 
62353
 
62354
 
62355
 
62356
 
62357
 
62358
 
62359
 
62360
 
62361
 
62362
 
62363
 
62364
 
62365
 
62366
 
62367
 
62368
 
62369
 
62370
 
62371
 
62372
 
62373
 
62374
 
62375
 
62376
 
62377
 
62378
 
62379
 
62380
 
62381
 
62382
 
62383
 
62384
 
62385
 
62386
 
62387
 
62388
 
62389
 
62390
 
62391
 
62392
 
62393
 
62394
 
62395
 
62396
 
62397
 
62398
 
62399
 
62400
 
62401
 
62402
 
62403
 
62404
 
62405
 
62406
 
62407
 
62408
 
62409
 
62410
 
62411
 
62412
 
62413
 
62414
 
62415
 
62416
 
62417
 
62418
 
62419
 
62420
 
62421
 
62422
 
62423
 
62424
 
62425
 
62426
 
62427
 
62428
 
62429
 
62430
 
62431
 
62432
 
62433
 
62434
 
62435
 
62436
 
62437
 
62438
 
62439
 
62440
 
62441
 
62442
 
62443
 
62444
 
62445
 
62446
 
62447
 
62448
 
62449
 
62450
 
62451
 
62452
 
62453
 
62454
 
62455
 
62456
 
62457
 
62458
 
62459
 
62460
 
62461
 
62462
 
62463
 
62464
 
62465
 
62466
 
62467
 
62468
 
62469
 
62470
 
62471
 
62472
 
62473
 
62474
 
62475
 
62476
 
62477
 
62478
 
62479
 
62480
 
62481
 
62482
 
62483
 
62484
 
62485
 
62486
 
62487
 
62488
 
62489
 
62490
 
62491
 
62492
 
62493
 
62494
 
62495
 
62496
 
62497
 
62498
 
62499
 
62500
 
62501
 
62502
 
62503
 
62504
 
62505
 
62506
 
62507
 
62508
 
62509
 
62510
 
62511
 
62512
 
62513
 
62514
 
62515
 
62516
 
62517
 
62518
 
62519
 
62520
 
62521
 
62522
 
62523
 
62524
 
62525
 
62526
 
62527
 
62528
 
62529
 
62530
 
62531
 
62532
 
62533
 
62534
 
62535
 
62536
 
62537
 
62538
 
62539
 
62540
 
62541
 
62542
 
62543
 
62544
 
62545
 
62546
 
62547
 
62548
 
62549
 
62550
 
62551
 
62552
 
62553
 
62554
 
62555
 
62556
 
62557
 
62558
 
62559
 
62560
 
62561
 
62562
 
62563
 
62564
 
62565
 
62566
 
62567
 
62568
 
62569
 
62570
 
62571
 
62572
 
62573
 
62574
 
62575
 
62576
 
62577
 
62578
 
62579
 
62580
 
62581
 
62582
 
62583
 
62584
 
62585
 
62586
 
62587
 
62588
 
62589
 
62590
 
62591
 
62592
 
62593
 
62594
 
62595
 
62596
 
62597
 
62598
 
62599
 
62600
 
62601
 
62602
 
62603
 
62604
 
62605
 
62606
 
62607
 
62608
 
62609
 
62610
 
62611
 
62612
 
62613
 
62614
 
62615
 
62616
 
62617
 
62618
 
62619
 
62620
 
62621
 
62622
 
62623
 
62624
 
62625
 
62626
 
62627
 
62628
 
62629
 
62630
 
62631
 
62632
 
62633
 
62634
 
62635
 
62636
 
62637
 
62638
 
62639
 
62640
 
62641
 
62642
 
62643
 
62644
 
62645
 
62646
 
62647
 
62648
 
62649
 
62650
 
62651
 
62652
 
62653
 
62654
 
62655
 
62656
 
62657
 
62658
 
62659
 
62660
 
62661
 
62662
 
62663
 
62664
 
62665
 
62666
 
62667
 
62668
 
62669
 
62670
 
62671
 
62672
 
62673
 
62674
 
62675
 
62676
 
62677
 
62678
 
62679
 
62680
 
62681
 
62682
 
62683
 
62684
 
62685
 
62686
 
62687
 
62688
 
62689
 
62690
 
62691
 
62692
 
62693
 
62694
 
62695
 
62696
 
62697
 
62698
 
62699
 
62700
 
62701
 
62702
 
62703
 
62704
 
62705
 
62706
 
62707
 
62708
 
62709
 
62710
 
62711
 
62712
 
62713
 
62714
 
62715
 
62716
 
62717
 
62718
 
62719
 
62720
 
62721
 
62722
 
62723
 
62724
 
62725
 
62726
 
62727
 
62728
 
62729
 
62730
 
62731
 
62732
 
62733
 
62734
 
62735
 
62736
 
62737
 
62738
 
62739
 
62740
 
62741
 
62742
 
62743
 
62744
 
62745
 
62746
 
62747
 
62748
 
62749
 
62750
 
62751
 
62752
 
62753
 
62754
 
62755
 
62756
 
62757
 
62758
 
62759
 
62760
 
62761
 
62762
 
62763
 
62764
 
62765
 
62766
 
62767
 
62768
 
62769
 
62770
 
62771
 
62772
 
62773
 
62774
 
62775
 
62776
 
62777
 
62778
 
62779
 
62780
 
62781
 
62782
 
62783
 
62784
 
62785
 
62786
 
62787
 
62788
 
62789
 
62790
 
62791
 
62792
 
62793
 
62794
 
62795
 
62796
 
62797
 
62798
 
62799
 
62800
 
62801
 
62802
 
62803
 
62804
 
62805
 
62806
 
62807
 
62808
 
62809
 
62810
 
62811
 
62812
 
62813
 
62814
 
62815
 
62816
 
62817
 
62818
 
62819
 
62820
 
62821
 
62822
 
62823
 
62824
 
62825
 
62826
 
62827
 
62828
 
62829
 
62830
 
62831
 
62832
 
62833
 
62834
 
62835
 
62836
 
62837
 
62838
 
62839
 
62840
 
62841
 
62842
 
62843
 
62844
 
62845
 
62846
 
62847
 
62848
 
62849
 
62850
 
62851
 
62852
 
62853
 
62854
 
62855
 
62856
 
62857
 
62858
 
62859
 
62860
 
62861
 
62862
 
62863
 
62864
 
62865
 
62866
 
62867
 
62868
 
62869
 
62870
 
62871
 
62872
 
62873
 
62874
 
62875
 
62876
 
62877
 
62878
 
62879
 
62880
 
62881
 
62882
 
62883
 
62884
 
62885
 
62886
 
62887
 
62888
 
62889
 
62890
 
62891
 
62892
 
62893
 
62894
 
62895
 
62896
 
62897
 
62898
 
62899
 
62900
 
62901
 
62902
 
62903
 
62904
 
62905
 
62906
 
62907
 
62908
 
62909
 
62910
 
62911
 
62912
 
62913
 
62914
 
62915
 
62916
 
62917
 
62918
 
62919
 
62920
 
62921
 
62922
 
62923
 
62924
 
62925
 
62926
 
62927
 
62928
 
62929
 
62930
 
62931
 
62932
 
62933
 
62934
 
62935
 
62936
 
62937
 
62938
 
62939
 
62940
 
62941
 
62942
 
62943
 
62944
 
62945
 
62946
 
62947
 
62948
 
62949
 
62950
 
62951
 
62952
 
62953
 
62954
 
62955
 
62956
 
62957
 
62958
 
62959
 
62960
 
62961
 
62962
 
62963
 
62964
 
62965
 
62966
 
62967
 
62968
 
62969
 
62970
 
62971
 
62972
 
62973
 
62974
 
62975
 
62976
 
62977
 
62978
 
62979
 
62980
 
62981
 
62982
 
62983
 
62984
 
62985
 
62986
 
62987
 
62988
 
62989
 
62990
 
62991
 
62992
 
62993
 
62994
 
62995
 
62996
 
62997
 
62998
 
62999
 
63000
 
63001
 
63002
 
63003
 
63004
 
63005
 
63006
 
63007
 
63008
 
63009
 
63010
 
63011
 
63012
 
63013
 
63014
 
63015
 
63016
 
63017
 
63018
 
63019
 
63020
 
63021
 
63022
 
63023
 
63024
 
63025
 
63026
 
63027
 
63028
 
63029
 
63030
 
63031
 
63032
 
63033
 
63034
 
63035
 
63036
 
63037
 
63038
 
63039
 
63040
 
63041
 
63042
 
63043
 
63044
 
63045
 
63046
 
63047
 
63048
 
63049
 
63050
 
63051
 
63052
 
63053
 
63054
 
63055
 
63056
 
63057
 
63058
 
63059
 
63060
 
63061
 
63062
 
63063
 
63064
 
63065
 
63066
 
63067
 
63068
 
63069
 
63070
 
63071
 
63072
 
63073
 
63074
 
63075
 
63076
 
63077
 
63078
 
63079
 
63080
 
63081
 
63082
 
63083
 
63084
 
63085
 
63086
 
63087
 
63088
 
63089
 
63090
 
63091
 
63092
 
63093
 
63094
 
63095
 
63096
 
63097
 
63098
 
63099
 
63100
 
63101
 
63102
 
63103
 
63104
 
63105
 
63106
 
63107
 
63108
 
63109
 
63110
 
63111
 
63112
 
63113
 
63114
 
63115
 
63116
 
63117
 
63118
 
63119
 
63120
 
63121
 
63122
 
63123
 
63124
 
63125
 
63126
 
63127
 
63128
 
63129
 
63130
 
63131
 
63132
 
63133
 
63134
 
63135
 
63136
 
63137
 
63138
 
63139
 
63140
 
63141
 
63142
 
63143
 
63144
 
63145
 
63146
 
63147
 
63148
 
63149
 
63150
 
63151
 
63152
 
63153
 
63154
 
63155
 
63156
 
63157
 
63158
 
63159
 
63160
 
63161
 
63162
 
63163
 
63164
 
63165
 
63166
 
63167
 
63168
 
63169
 
63170
 
63171
 
63172
 
63173
 
63174
 
63175
 
63176
 
63177
 
63178
 
63179
 
63180
 
63181
 
63182
 
63183
 
63184
 
63185
 
63186
 
63187
 
63188
 
63189
 
63190
 
63191
 
63192
 
63193
 
63194
 
63195
 
63196
 
63197
 
63198
 
63199
 
63200
 
63201
 
63202
 
63203
 
63204
 
63205
 
63206
 
63207
 
63208
 
63209
 
63210
 
63211
 
63212
 
63213
 
63214
 
63215
 
63216
 
63217
 
63218
 
63219
 
63220
 
63221
 
63222
 
63223
 
63224
 
63225
 
63226
 
63227
 
63228
 
63229
 
63230
 
63231
 
63232
 
63233
 
63234
 
63235
 
63236
 
63237
 
63238
 
63239
 
63240
 
63241
 
63242
 
63243
 
63244
 
63245
 
63246
 
63247
 
63248
 
63249
 
63250
 
63251
 
63252
 
63253
 
63254
 
63255
 
63256
 
63257
 
63258
 
63259
 
63260
 
63261
 
63262
 
63263
 
63264
 
63265
 
63266
 
63267
 
63268
 
63269
 
63270
 
63271
 
63272
 
63273
 
63274
 
63275
 
63276
 
63277
 
63278
 
63279
 
63280
 
63281
 
63282
 
63283
 
63284
 
63285
 
63286
 
63287
 
63288
 
63289
 
63290
 
63291
 
63292
 
63293
 
63294
 
63295
 
63296
 
63297
 
63298
 
63299
 
63300
 
63301
 
63302
 
63303
 
63304
 
63305
 
63306
 
63307
 
63308
 
63309
 
63310
 
63311
 
63312
 
63313
 
63314
 
63315
 
63316
 
63317
 
63318
 
63319
 
63320
 
63321
 
63322
 
63323
 
63324
 
63325
 
63326
 
63327
 
63328
 
63329
 
63330
 
63331
 
63332
 
63333
 
63334
 
63335
 
63336
 
63337
 
63338
 
63339
 
63340
 
63341
 
63342
 
63343
 
63344
 
63345
 
63346
 
63347
 
63348
 
63349
 
63350
 
63351
 
63352
 
63353
 
63354
 
63355
 
63356
 
63357
 
63358
 
63359
 
63360
 
63361
 
63362
 
63363
 
63364
 
63365
 
63366
 
63367
 
63368
 
63369
 
63370
 
63371
 
63372
 
63373
 
63374
 
63375
 
63376
 
63377
 
63378
 
63379
 
63380
 
63381
 
63382
 
63383
 
63384
 
63385
 
63386
 
63387
 
63388
 
63389
 
63390
 
63391
 
63392
 
63393
 
63394
 
63395
 
63396
 
63397
 
63398
 
63399
 
63400
 
63401
 
63402
 
63403
 
63404
 
63405
 
63406
 
63407
 
63408
 
63409
 
63410
 
63411
 
63412
 
63413
 
63414
 
63415
 
63416
 
63417
 
63418
 
63419
 
63420
 
63421
 
63422
 
63423
 
63424
 
63425
 
63426
 
63427
 
63428
 
63429
 
63430
 
63431
 
63432
 
63433
 
63434
 
63435
 
63436
 
63437
 
63438
 
63439
 
63440
 
63441
 
63442
 
63443
 
63444
 
63445
 
63446
 
63447
 
63448
 
63449
 
63450
 
63451
 
63452
 
63453
 
63454
 
63455
 
63456
 
63457
 
63458
 
63459
 
63460
 
63461
 
63462
 
63463
 
63464
 
63465
 
63466
 
63467
 
63468
 
63469
 
63470
 
63471
 
63472
 
63473
 
63474
 
63475
 
63476
 
63477
 
63478
 
63479
 
63480
 
63481
 
63482
 
63483
 
63484
 
63485
 
63486
 
63487
 
63488
 
63489
 
63490
 
63491
 
63492
 
63493
 
63494
 
63495
 
63496
 
63497
 
63498
 
63499
 
63500
 
63501
 
63502
 
63503
 
63504
 
63505
 
63506
 
63507
 
63508
 
63509
 
63510
 
63511
 
63512
 
63513
 
63514
 
63515
 
63516
 
63517
 
63518
 
63519
 
63520
 
63521
 
63522
 
63523
 
63524
 
63525
 
63526
 
63527
 
63528
 
63529
 
63530
 
63531
 
63532
 
63533
 
63534
 
63535
 
63536
 
63537
 
63538
 
63539
 
63540
 
63541
 
63542
 
63543
 
63544
 
63545
 
63546
 
63547
 
63548
 
63549
 
63550
 
63551
 
63552
 
63553
 
63554
 
63555
 
63556
 
63557
 
63558
 
63559
 
63560
 
63561
 
63562
 
63563
 
63564
 
63565
 
63566
 
63567
 
63568
 
63569
 
63570
 
63571
 
63572
 
63573
 
63574
 
63575
 
63576
 
63577
 
63578
 
63579
 
63580
 
63581
 
63582
 
63583
 
63584
 
63585
 
63586
 
63587
 
63588
 
63589
 
63590
 
63591
 
63592
 
63593
 
63594
 
63595
 
63596
 
63597
 
63598
 
63599
 
63600
 
63601
 
63602
 
63603
 
63604
 
63605
 
63606
 
63607
 
63608
 
63609
 
63610
 
63611
 
63612
 
63613
 
63614
 
63615
 
63616
 
63617
 
63618
 
63619
 
63620
 
63621
 
63622
 
63623
 
63624
 
63625
 
63626
 
63627
 
63628
 
63629
 
63630
 
63631
 
63632
 
63633
 
63634
 
63635
 
63636
 
63637
 
63638
 
63639
 
63640
 
63641
 
63642
 
63643
 
63644
 
63645
 
63646
 
63647
 
63648
 
63649
 
63650
 
63651
 
63652
 
63653
 
63654
 
63655
 
63656
 
63657
 
63658
 
63659
 
63660
 
63661
 
63662
 
63663
 
63664
 
63665
 
63666
 
63667
 
63668
 
63669
 
63670
 
63671
 
63672
 
63673
 
63674
 
63675
 
63676
 
63677
 
63678
 
63679
 
63680
 
63681
 
63682
 
63683
 
63684
 
63685
 
63686
 
63687
 
63688
 
63689
 
63690
 
63691
 
63692
 
63693
 
63694
 
63695
 
63696
 
63697
 
63698
 
63699
 
63700
 
63701
 
63702
 
63703
 
63704
 
63705
 
63706
 
63707
 
63708
 
63709
 
63710
 
63711
 
63712
 
63713
 
63714
 
63715
 
63716
 
63717
 
63718
 
63719
 
63720
 
63721
 
63722
 
63723
 
63724
 
63725
 
63726
 
63727
 
63728
 
63729
 
63730
 
63731
 
63732
 
63733
 
63734
 
63735
 
63736
 
63737
 
63738
 
63739
 
63740
 
63741
 
63742
 
63743
 
63744
 
63745
 
63746
 
63747
 
63748
 
63749
 
63750
 
63751
 
63752
 
63753
 
63754
 
63755
 
63756
 
63757
 
63758
 
63759
 
63760
 
63761
 
63762
 
63763
 
63764
 
63765
 
63766
 
63767
 
63768
 
63769
 
63770
 
63771
 
63772
 
63773
 
63774
 
63775
 
63776
 
63777
 
63778
 
63779
 
63780
 
63781
 
63782
 
63783
 
63784
 
63785
 
63786
 
63787
 
63788
 
63789
 
63790
 
63791
 
63792
 
63793
 
63794
 
63795
 
63796
 
63797
 
63798
 
63799
 
63800
 
63801
 
63802
 
63803
 
63804
 
63805
 
63806
 
63807
 
63808
 
63809
 
63810
 
63811
 
63812
 
63813
 
63814
 
63815
 
63816
 
63817
 
63818
 
63819
 
63820
 
63821
 
63822
 
63823
 
63824
 
63825
 
63826
 
63827
 
63828
 
63829
 
63830
 
63831
 
63832
 
63833
 
63834
 
63835
 
63836
 
63837
 
63838
 
63839
 
63840
 
63841
 
63842
 
63843
 
63844
 
63845
 
63846
 
63847
 
63848
 
63849
 
63850
 
63851
 
63852
 
63853
 
63854
 
63855
 
63856
 
63857
 
63858
 
63859
 
63860
 
63861
 
63862
 
63863
 
63864
 
63865
 
63866
 
63867
 
63868
 
63869
 
63870
 
63871
 
63872
 
63873
 
63874
 
63875
 
63876
 
63877
 
63878
 
63879
 
63880
 
63881
 
63882
 
63883
 
63884
 
63885
 
63886
 
63887
 
63888
 
63889
 
63890
 
63891
 
63892
 
63893
 
63894
 
63895
 
63896
 
63897
 
63898
 
63899
 
63900
 
63901
 
63902
 
63903
 
63904
 
63905
 
63906
 
63907
 
63908
 
63909
 
63910
 
63911
 
63912
 
63913
 
63914
 
63915
 
63916
 
63917
 
63918
 
63919
 
63920
 
63921
 
63922
 
63923
 
63924
 
63925
 
63926
 
63927
 
63928
 
63929
 
63930
 
63931
 
63932
 
63933
 
63934
 
63935
 
63936
 
63937
 
63938
 
63939
 
63940
 
63941
 
63942
 
63943
 
63944
 
63945
 
63946
 
63947
 
63948
 
63949
 
63950
 
63951
 
63952
 
63953
 
63954
 
63955
 
63956
 
63957
 
63958
 
63959
 
63960
 
63961
 
63962
 
63963
 
63964
 
63965
 
63966
 
63967
 
63968
 
63969
 
63970
 
63971
 
63972
 
63973
 
63974
 
63975
 
63976
 
63977
 
63978
 
63979
 
63980
 
63981
 
63982
 
63983
 
63984
 
63985
 
63986
 
63987
 
63988
 
63989
 
63990
 
63991
 
63992
 
63993
 
63994
 
63995
 
63996
 
63997
 
63998
 
63999
 
64000
 
64001
 
64002
 
64003
 
64004
 
64005
 
64006
 
64007
 
64008
 
64009
 
64010
 
64011
 
64012
 
64013
 
64014
 
64015
 
64016
 
64017
 
64018
 
64019
 
64020
 
64021
 
64022
 
64023
 
64024
 
64025
 
64026
 
64027
 
64028
 
64029
 
64030
 
64031
 
64032
 
64033
 
64034
 
64035
 
64036
 
64037
 
64038
 
64039
 
64040
 
64041
 
64042
 
64043
 
64044
 
64045
 
64046
 
64047
 
64048
 
64049
 
64050
 
64051
 
64052
 
64053
 
64054
 
64055
 
64056
 
64057
 
64058
 
64059
 
64060
 
64061
 
64062
 
64063
 
64064
 
64065
 
64066
 
64067
 
64068
 
64069
 
64070
 
64071
 
64072
 
64073
 
64074
 
64075
 
64076
 
64077
 
64078
 
64079
 
64080
 
64081
 
64082
 
64083
 
64084
 
64085
 
64086
 
64087
 
64088
 
64089
 
64090
 
64091
 
64092
 
64093
 
64094
 
64095
 
64096
 
64097
 
64098
 
64099
 
64100
 
64101
 
64102
 
64103
 
64104
 
64105
 
64106
 
64107
 
64108
 
64109
 
64110
 
64111
 
64112
 
64113
 
64114
 
64115
 
64116
 
64117
 
64118
 
64119
 
64120
 
64121
 
64122
 
64123
 
64124
 
64125
 
64126
 
64127
 
64128
 
64129
 
64130
 
64131
 
64132
 
64133
 
64134
 
64135
 
64136
 
64137
 
64138
 
64139
 
64140
 
64141
 
64142
 
64143
 
64144
 
64145
 
64146
 
64147
 
64148
 
64149
 
64150
 
64151
 
64152
 
64153
 
64154
 
64155
 
64156
 
64157
 
64158
 
64159
 
64160
 
64161
 
64162
 
64163
 
64164
 
64165
 
64166
 
64167
 
64168
 
64169
 
64170
 
64171
 
64172
 
64173
 
64174
 
64175
 
64176
 
64177
 
64178
 
64179
 
64180
 
64181
 
64182
 
64183
 
64184
 
64185
 
64186
 
64187
 
64188
 
64189
 
64190
 
64191
 
64192
 
64193
 
64194
 
64195
 
64196
 
64197
 
64198
 
64199
 
64200
 
64201
 
64202
 
64203
 
64204
 
64205
 
64206
 
64207
 
64208
 
64209
 
64210
 
64211
 
64212
 
64213
 
64214
 
64215
 
64216
 
64217
 
64218
 
64219
 
64220
 
64221
 
64222
 
64223
 
64224
 
64225
 
64226
 
64227
 
64228
 
64229
 
64230
 
64231
 
64232
 
64233
 
64234
 
64235
 
64236
 
64237
 
64238
 
64239
 
64240
 
64241
 
64242
 
64243
 
64244
 
64245
 
64246
 
64247
 
64248
 
64249
 
64250
 
64251
 
64252
 
64253
 
64254
 
64255
 
64256
 
64257
 
64258
 
64259
 
64260
 
64261
 
64262
 
64263
 
64264
 
64265
 
64266
 
64267
 
64268
 
64269
 
64270
 
64271
 
64272
 
64273
 
64274
 
64275
 
64276
 
64277
 
64278
 
64279
 
64280
 
64281
 
64282
 
64283
 
64284
 
64285
 
64286
 
64287
 
64288
 
64289
 
64290
 
64291
 
64292
 
64293
 
64294
 
64295
 
64296
 
64297
 
64298
 
64299
 
64300
 
64301
 
64302
 
64303
 
64304
 
64305
 
64306
 
64307
 
64308
 
64309
 
64310
 
64311
 
64312
 
64313
 
64314
 
64315
 
64316
 
64317
 
64318
 
64319
 
64320
 
64321
 
64322
 
64323
 
64324
 
64325
 
64326
 
64327
 
64328
 
64329
 
64330
 
64331
 
64332
 
64333
 
64334
 
64335
 
64336
 
64337
 
64338
 
64339
 
64340
 
64341
 
64342
 
64343
 
64344
 
64345
 
64346
 
64347
 
64348
 
64349
 
64350
 
64351
 
64352
 
64353
 
64354
 
64355
 
64356
 
64357
 
64358
 
64359
 
64360
 
64361
 
64362
 
64363
 
64364
 
64365
 
64366
 
64367
 
64368
 
64369
 
64370
 
64371
 
64372
 
64373
 
64374
 
64375
 
64376
 
64377
 
64378
 
64379
 
64380
 
64381
 
64382
 
64383
 
64384
 
64385
 
64386
 
64387
 
64388
 
64389
 
64390
 
64391
 
64392
 
64393
 
64394
 
64395
 
64396
 
64397
 
64398
 
64399
 
64400
 
64401
 
64402
 
64403
 
64404
 
64405
 
64406
 
64407
 
64408
 
64409
 
64410
 
64411
 
64412
 
64413
 
64414
 
64415
 
64416
 
64417
 
64418
 
64419
 
64420
 
64421
 
64422
 
64423
 
64424
 
64425
 
64426
 
64427
 
64428
 
64429
 
64430
 
64431
 
64432
 
64433
 
64434
 
64435
 
64436
 
64437
 
64438
 
64439
 
64440
 
64441
 
64442
 
64443
 
64444
 
64445
 
64446
 
64447
 
64448
 
64449
 
64450
 
64451
 
64452
 
64453
 
64454
 
64455
 
64456
 
64457
 
64458
 
64459
 
64460
 
64461
 
64462
 
64463
 
64464
 
64465
 
64466
 
64467
 
64468
 
64469
 
64470
 
64471
 
64472
 
64473
 
64474
 
64475
 
64476
 
64477
 
64478
 
64479
 
64480
 
64481
 
64482
 
64483
 
64484
 
64485
 
64486
 
64487
 
64488
 
64489
 
64490
 
64491
 
64492
 
64493
 
64494
 
64495
 
64496
 
64497
 
64498
 
64499
 
64500
 
64501
 
64502
 
64503
 
64504
 
64505
 
64506
 
64507
 
64508
 
64509
 
64510
 
64511
 
64512
 
64513
 
64514
 
64515
 
64516
 
64517
 
64518
 
64519
 
64520
 
64521
 
64522
 
64523
 
64524
 
64525
 
64526
 
64527
 
64528
 
64529
 
64530
 
64531
 
64532
 
64533
 
64534
 
64535
 
64536
 
64537
 
64538
 
64539
 
64540
 
64541
 
64542
 
64543
 
64544
 
64545
 
64546
 
64547
 
64548
 
64549
 
64550
 
64551
 
64552
 
64553
 
64554
 
64555
 
64556
 
64557
 
64558
 
64559
 
64560
 
64561
 
64562
 
64563
 
64564
 
64565
 
64566
 
64567
 
64568
 
64569
 
64570
 
64571
 
64572
 
64573
 
64574
 
64575
 
64576
 
64577
 
64578
 
64579
 
64580
 
64581
 
64582
 
64583
 
64584
 
64585
 
64586
 
64587
 
64588
 
64589
 
64590
 
64591
 
64592
 
64593
 
64594
 
64595
 
64596
 
64597
 
64598
 
64599
 
64600
 
64601
 
64602
 
64603
 
64604
 
64605
 
64606
 
64607
 
64608
 
64609
 
64610
 
64611
 
64612
 
64613
 
64614
 
64615
 
64616
 
64617
 
64618
 
64619
 
64620
 
64621
 
64622
 
64623
 
64624
 
64625
 
64626
 
64627
 
64628
 
64629
 
64630
 
64631
 
64632
 
64633
 
64634
 
64635
 
64636
 
64637
 
64638
 
64639
 
64640
 
64641
 
64642
 
64643
 
64644
 
64645
 
64646
 
64647
 
64648
 
64649
 
64650
 
64651
 
64652
 
64653
 
64654
 
64655
 
64656
 
64657
 
64658
 
64659
 
64660
 
64661
 
64662
 
64663
 
64664
 
64665
 
64666
 
64667
 
64668
 
64669
 
64670
 
64671
 
64672
 
64673
 
64674
 
64675
 
64676
 
64677
 
64678
 
64679
 
64680
 
64681
 
64682
 
64683
 
64684
 
64685
 
64686
 
64687
 
64688
 
64689
 
64690
 
64691
 
64692
 
64693
 
64694
 
64695
 
64696
 
64697
 
64698
 
64699
 
64700
 
64701
 
64702
 
64703
 
64704
 
64705
 
64706
 
64707
 
64708
 
64709
 
64710
 
64711
 
64712
 
64713
 
64714
 
64715
 
64716
 
64717
 
64718
 
64719
 
64720
 
64721
 
64722
 
64723
 
64724
 
64725
 
64726
 
64727
 
64728
 
64729
 
64730
 
64731
 
64732
 
64733
 
64734
 
64735
 
64736
 
64737
 
64738
 
64739
 
64740
 
64741
 
64742
 
64743
 
64744
 
64745
 
64746
 
64747
 
64748
 
64749
 
64750
 
64751
 
64752
 
64753
 
64754
 
64755
 
64756
 
64757
 
64758
 
64759
 
64760
 
64761
 
64762
 
64763
 
64764
 
64765
 
64766
 
64767
 
64768
 
64769
 
64770
 
64771
 
64772
 
64773
 
64774
 
64775
 
64776
 
64777
 
64778
 
64779
 
64780
 
64781
 
64782
 
64783
 
64784
 
64785
 
64786
 
64787
 
64788
 
64789
 
64790
 
64791
 
64792
 
64793
 
64794
 
64795
 
64796
 
64797
 
64798
 
64799
 
64800
 
64801
 
64802
 
64803
 
64804
 
64805
 
64806
 
64807
 
64808
 
64809
 
64810
 
64811
 
64812
 
64813
 
64814
 
64815
 
64816
 
64817
 
64818
 
64819
 
64820
 
64821
 
64822
 
64823
 
64824
 
64825
 
64826
 
64827
 
64828
 
64829
 
64830
 
64831
 
64832
 
64833
 
64834
 
64835
 
64836
 
64837
 
64838
 
64839
 
64840
 
64841
 
64842
 
64843
 
64844
 
64845
 
64846
 
64847
 
64848
 
64849
 
64850
 
64851
 
64852
 
64853
 
64854
 
64855
 
64856
 
64857
 
64858
 
64859
 
64860
 
64861
 
64862
 
64863
 
64864
 
64865
 
64866
 
64867
 
64868
 
64869
 
64870
 
64871
 
64872
 
64873
 
64874
 
64875
 
64876
 
64877
 
64878
 
64879
 
64880
 
64881
 
64882
 
64883
 
64884
 
64885
 
64886
 
64887
 
64888
 
64889
 
64890
 
64891
 
64892
 
64893
 
64894
 
64895
 
64896
 
64897
 
64898
 
64899
 
64900
 
64901
 
64902
 
64903
 
64904
 
64905
 
64906
 
64907
 
64908
 
64909
 
64910
 
64911
 
64912
 
64913
 
64914
 
64915
 
64916
 
64917
 
64918
 
64919
 
64920
 
64921
 
64922
 
64923
 
64924
 
64925
 
64926
 
64927
 
64928
 
64929
 
64930
 
64931
 
64932
 
64933
 
64934
 
64935
 
64936
 
64937
 
64938
 
64939
 
64940
 
64941
 
64942
 
64943
 
64944
 
64945
 
64946
 
64947
 
64948
 
64949
 
64950
 
64951
 
64952
 
64953
 
64954
 
64955
 
64956
 
64957
 
64958
 
64959
 
64960
 
64961
 
64962
 
64963
 
64964
 
64965
 
64966
 
64967
 
64968
 
64969
 
64970
 
64971
 
64972
 
64973
 
64974
 
64975
 
64976
 
64977
 
64978
 
64979
 
64980
 
64981
 
64982
 
64983
 
64984
 
64985
 
64986
 
64987
 
64988
 
64989
 
64990
 
64991
 
64992
 
64993
 
64994
 
64995
 
64996
 
64997
 
64998
 
64999
 
65000
 
65001
 
65002
 
65003
 
65004
 
65005
 
65006
 
65007
 
65008
 
65009
 
65010
 
65011
 
65012
 
65013
 
65014
 
65015
 
65016
 
65017
 
65018
 
65019
 
65020
 
65021
 
65022
 
65023
 
65024
 
65025
 
65026
 
65027
 
65028
 
65029
 
65030
 
65031
 
65032
 
65033
 
65034
 
65035
 
65036
 
65037
 
65038
 
65039
 
65040
 
65041
 
65042
 
65043
 
65044
 
65045
 
65046
 
65047
 
65048
 
65049
 
65050
 
65051
 
65052
 
65053
 
65054
 
65055
 
65056
 
65057
 
65058
 
65059
 
65060
 
65061
 
65062
 
65063
 
65064
 
65065
 
65066
 
65067
 
65068
 
65069
 
65070
 
65071
 
65072
 
65073
 
65074
 
65075
 
65076
 
65077
 
65078
 
65079
 
65080
 
65081
 
65082
 
65083
 
65084
 
65085
 
65086
 
65087
 
65088
 
65089
 
65090
 
65091
 
65092
 
65093
 
65094
 
65095
 
65096
 
65097
 
65098
 
65099
 
65100
 
65101
 
65102
 
65103
 
65104
 
65105
 
65106
 
65107
 
65108
 
65109
 
65110
 
65111
 
65112
 
65113
 
65114
 
65115
 
65116
 
65117
 
65118
 
65119
 
65120
 
65121
 
65122
 
65123
 
65124
 
65125
 
65126
 
65127
 
65128
 
65129
 
65130
 
65131
 
65132
 
65133
 
65134
 
65135
 
65136
 
65137
 
65138
 
65139
 
65140
 
65141
 
65142
 
65143
 
65144
 
65145
 
65146
 
65147
 
65148
 
65149
 
65150
 
65151
 
65152
 
65153
 
65154
 
65155
 
65156
 
65157
 
65158
 
65159
 
65160
 
65161
 
65162
 
65163
 
65164
 
65165
 
65166
 
65167
 
65168
 
65169
 
65170
 
65171
 
65172
 
65173
 
65174
 
65175
 
65176
 
65177
 
65178
 
65179
 
65180
 
65181
 
65182
 
65183
 
65184
 
65185
 
65186
 
65187
 
65188
 
65189
 
65190
 
65191
 
65192
 
65193
 
65194
 
65195
 
65196
 
65197
 
65198
 
65199
 
65200
 
65201
 
65202
 
65203
 
65204
 
65205
 
65206
 
65207
 
65208
 
65209
 
65210
 
65211
 
65212
 
65213
 
65214
 
65215
 
65216
 
65217
 
65218
 
65219
 
65220
 
65221
 
65222
 
65223
 
65224
 
65225
 
65226
 
65227
 
65228
 
65229
 
65230
 
65231
 
65232
 
65233
 
65234
 
65235
 
65236
 
65237
 
65238
 
65239
 
65240
 
65241
 
65242
 
65243
 
65244
 
65245
 
65246
 
65247
 
65248
 
65249
 
65250
 
65251
 
65252
 
65253
 
65254
 
65255
 
65256
 
65257
 
65258
 
65259
 
65260
 
65261
 
65262
 
65263
 
65264
 
65265
 
65266
 
65267
 
65268
 
65269
 
65270
 
65271
 
65272
 
65273
 
65274
 
65275
 
65276
 
65277
 
65278
 
65279
 
65280
 
65281
 
65282
 
65283
 
65284
 
65285
 
65286
 
65287
 
65288
 
65289
 
65290
 
65291
 
65292
 
65293
 
65294
 
65295
 
65296
 
65297
 
65298
 
65299
 
65300
 
65301
 
65302
 
65303
 
65304
 
65305
 
65306
 
65307
 
65308
 
65309
 
65310
 
65311
 
65312
 
65313
 
65314
 
65315
 
65316
 
65317
 
65318
 
65319
 
65320
 
65321
 
65322
 
65323
 
65324
 
65325
 
65326
 
65327
 
65328
 
65329
 
65330
 
65331
 
65332
 
65333
 
65334
 
65335
 
65336
 
65337
 
65338
 
65339
 
65340
 
65341
 
65342
 
65343
 
65344
 
65345
 
65346
 
65347
 
65348
 
65349
 
65350
 
65351
 
65352
 
65353
 
65354
 
65355
 
65356
 
65357
 
65358
 
65359
 
65360
 
65361
 
65362
 
65363
 
65364
 
65365
 
65366
 
65367
 
65368
 
65369
 
65370
 
65371
 
65372
 
65373
 
65374
 
65375
 
65376
 
65377
 
65378
 
65379
 
65380
 
65381
 
65382
 
65383
 
65384
 
65385
 
65386
 
65387
 
65388
 
65389
 
65390
 
65391
 
65392
 
65393
 
65394
 
65395
 
65396
 
65397
 
65398
 
65399
 
65400
 
65401
 
65402
 
65403
 
65404
 
65405
 
65406
 
65407
 
65408
 
65409
 
65410
 
65411
 
65412
 
65413
 
65414
 
65415
 
65416
 
65417
 
65418
 
65419
 
65420
 
65421
 
65422
 
65423
 
65424
 
65425
 
65426
 
65427
 
65428
 
65429
 
65430
 
65431
 
65432
 
65433
 
65434
 
65435
 
65436
 
65437
 
65438
 
65439
 
65440
 
65441
 
65442
 
65443
 
65444
 
65445
 
65446
 
65447
 
65448
 
65449
 
65450
 
65451
 
65452
 
65453
 
65454
 
65455
 
65456
 
65457
 
65458
 
65459
 
65460
 
65461
 
65462
 
65463
 
65464
 
65465
 
65466
 
65467
 
65468
 
65469
 
65470
 
65471
 
65472
 
65473
 
65474
 
65475
 
65476
 
65477
 
65478
 
65479
 
65480
 
65481
 
65482
 
65483
 
65484
 
65485
 
65486
 
65487
 
65488
 
65489
 
65490
 
65491
 
65492
 
65493
 
65494
 
65495
 
65496
 
65497
 
65498
 
65499
 
65500
 
65501
 
65502
 
65503
 
65504
 
65505
 
65506
 
65507
 
65508
 
65509
 
65510
 
65511
 
65512
 
65513
 
65514
 
65515
 
65516
 
65517
 
65518
 
65519
 
65520
 
65521
 
65522
 
65523
 
65524
 
65525
 
65526
 
65527
 
65528
 
65529
 
65530
 
65531
 
65532
 
65533
 
65534
 
65535
 
65536
 
65537
 
65538
 
65539
 
65540
 
65541
 
65542
 
65543
 
65544
 
65545
 
65546
 
65547
 
65548
 
65549
 
65550
 
65551
 
65552
 
65553
 
65554
 
65555
 
65556
 
65557
 
65558
 
65559
 
65560
 
65561
 
65562
 
65563
 
65564
 
65565
 
65566
 
65567
 
65568
 
65569
 
65570
 
65571
 
65572
 
65573
 
65574
 
65575
 
65576
 
65577
 
65578
 
65579
 
65580
 
65581
 
65582
 
65583
 
65584
 
65585
 
65586
 
65587
 
65588
 
65589
 
65590
 
65591
 
65592
 
65593
 
65594
 
65595
 
65596
 
65597
 
65598
 
65599
 
65600
 
65601
 
65602
 
65603
 
65604
 
65605
 
65606
 
65607
 
65608
 
65609
 
65610
 
65611
 
65612
 
65613
 
65614
 
65615
 
65616
 
65617
 
65618
 
65619
 
65620
 
65621
 
65622
 
65623
 
65624
 
65625
 
65626
 
65627
 
65628
 
65629
 
65630
 
65631
 
65632
 
65633
 
65634
 
65635
 
65636
 
65637
 
65638
 
65639
 
65640
 
65641
 
65642
 
65643
 
65644
 
65645
 
65646
 
65647
 
65648
 
65649
 
65650
 
65651
 
65652
 
65653
 
65654
 
65655
 
65656
 
65657
 
65658
 
65659
 
65660
 
65661
 
65662
 
65663
 
65664
 
65665
 
65666
 
65667
 
65668
 
65669
 
65670
 
65671
 
65672
 
65673
 
65674
 
65675
 
65676
 
65677
 
65678
 
65679
 
65680
 
65681
 
65682
 
65683
 
65684
 
65685
 
65686
 
65687
 
65688
 
65689
 
65690
 
65691
 
65692
 
65693
 
65694
 
65695
 
65696
 
65697
 
65698
 
65699
 
65700
 
65701
 
65702
 
65703
 
65704
 
65705
 
65706
 
65707
 
65708
 
65709
 
65710
 
65711
 
65712
 
65713
 
65714
 
65715
 
65716
 
65717
 
65718
 
65719
 
65720
 
65721
 
65722
 
65723
 
65724
 
65725
 
65726
 
65727
 
65728
 
65729
 
65730
 
65731
 
65732
 
65733
 
65734
 
65735
 
65736
 
65737
 
65738
 
65739
 
65740
 
65741
 
65742
 
65743
 
65744
 
65745
 
65746
 
65747
 
65748
 
65749
 
65750
 
65751
 
65752
 
65753
 
65754
 
65755
 
65756
 
65757
 
65758
 
65759
 
65760
 
65761
 
65762
 
65763
 
65764
 
65765
 
65766
 
65767
 
65768
 
65769
 
65770
 
65771
 
65772
 
65773
 
65774
 
65775
 
65776
 
65777
 
65778
 
65779
 
65780
 
65781
 
65782
 
65783
 
65784
 
65785
 
65786
 
65787
 
65788
 
65789
 
65790
 
65791
 
65792
 
65793
 
65794
 
65795
 
65796
 
65797
 
65798
 
65799
 
65800
 
65801
 
65802
 
65803
 
65804
 
65805
 
65806
 
65807
 
65808
 
65809
 
65810
 
65811
 
65812
 
65813
 
65814
 
65815
 
65816
 
65817
 
65818
 
65819
 
65820
 
65821
 
65822
 
65823
 
65824
 
65825
 
65826
 
65827
 
65828
 
65829
 
65830
 
65831
 
65832
 
65833
 
65834
 
65835
 
65836
 
65837
 
65838
 
65839
 
65840
 
65841
 
65842
 
65843
 
65844
 
65845
 
65846
 
65847
 
65848
 
65849
 
65850
 
65851
 
65852
 
65853
 
65854
 
65855
 
65856
 
65857
 
65858
 
65859
 
65860
 
65861
 
65862
 
65863
 
65864
 
65865
 
65866
 
65867
 
65868
 
65869
 
65870
 
65871
 
65872
 
65873
 
65874
 
65875
 
65876
 
65877
 
65878
 
65879
 
65880
 
65881
 
65882
 
65883
 
65884
 
65885
 
65886
 
65887
 
65888
 
65889
 
65890
 
65891
 
65892
 
65893
 
65894
 
65895
 
65896
 
65897
 
65898
 
65899
 
65900
 
65901
 
65902
 
65903
 
65904
 
65905
 
65906
 
65907
 
65908
 
65909
 
65910
 
65911
 
65912
 
65913
 
65914
 
65915
 
65916
 
65917
 
65918
 
65919
 
65920
 
65921
 
65922
 
65923
 
65924
 
65925
 
65926
 
65927
 
65928
 
65929
 
65930
 
65931
 
65932
 
65933
 
65934
 
65935
 
65936
 
65937
 
65938
 
65939
 
65940
 
65941
 
65942
 
65943
 
65944
 
65945
 
65946
 
65947
 
65948
 
65949
 
65950
 
65951
 
65952
 
65953
 
65954
 
65955
 
65956
 
65957
 
65958
 
65959
 
65960
 
65961
 
65962
 
65963
 
65964
 
65965
 
65966
 
65967
 
65968
 
65969
 
65970
 
65971
 
65972
 
65973
 
65974
 
65975
 
65976
 
65977
 
65978
 
65979
 
65980
 
65981
 
65982
 
65983
 
65984
 
65985
 
65986
 
65987
 
65988
 
65989
 
65990
 
65991
 
65992
 
65993
 
65994
 
65995
 
65996
 
65997
 
65998
 
65999
 
66000
 
66001
 
66002
 
66003
 
66004
 
66005
 
66006
 
66007
 
66008
 
66009
 
66010
 
66011
 
66012
 
66013
 
66014
 
66015
 
66016
 
66017
 
66018
 
66019
 
66020
 
66021
 
66022
 
66023
 
66024
 
66025
 
66026
 
66027
 
66028
 
66029
 
66030
 
66031
 
66032
 
66033
 
66034
 
66035
 
66036
 
66037
 
66038
 
66039
 
66040
 
66041
 
66042
 
66043
 
66044
 
66045
 
66046
 
66047
 
66048
 
66049
 
66050
 
66051
 
66052
 
66053
 
66054
 
66055
 
66056
 
66057
 
66058
 
66059
 
66060
 
66061
 
66062
 
66063
 
66064
 
66065
 
66066
 
66067
 
66068
 
66069
 
66070
 
66071
 
66072
 
66073
 
66074
 
66075
 
66076
 
66077
 
66078
 
66079
 
66080
 
66081
 
66082
 
66083
 
66084
 
66085
 
66086
 
66087
 
66088
 
66089
 
66090
 
66091
 
66092
 
66093
 
66094
 
66095
 
66096
 
66097
 
66098
 
66099
 
66100
 
66101
 
66102
 
66103
 
66104
 
66105
 
66106
 
66107
 
66108
 
66109
 
66110
 
66111
 
66112
 
66113
 
66114
 
66115
 
66116
 
66117
 
66118
 
66119
 
66120
 
66121
 
66122
 
66123
 
66124
 
66125
 
66126
 
66127
 
66128
 
66129
 
66130
 
66131
 
66132
 
66133
 
66134
 
66135
 
66136
 
66137
 
66138
 
66139
 
66140
 
66141
 
66142
 
66143
 
66144
 
66145
 
66146
 
66147
 
66148
 
66149
 
66150
 
66151
 
66152
 
66153
 
66154
 
66155
 
66156
 
66157
 
66158
 
66159
 
66160
 
66161
 
66162
 
66163
 
66164
 
66165
 
66166
 
66167
 
66168
 
66169
 
66170
 
66171
 
66172
 
66173
 
66174
 
66175
 
66176
 
66177
 
66178
 
66179
 
66180
 
66181
 
66182
 
66183
 
66184
 
66185
 
66186
 
66187
 
66188
 
66189
 
66190
 
66191
 
66192
 
66193
 
66194
 
66195
 
66196
 
66197
 
66198
 
66199
 
66200
 
66201
 
66202
 
66203
 
66204
 
66205
 
66206
 
66207
 
66208
 
66209
 
66210
 
66211
 
66212
 
66213
 
66214
 
66215
 
66216
 
66217
 
66218
 
66219
 
66220
 
66221
 
66222
 
66223
 
66224
 
66225
 
66226
 
66227
 
66228
 
66229
 
66230
 
66231
 
66232
 
66233
 
66234
 
66235
 
66236
 
66237
 
66238
 
66239
 
66240
 
66241
 
66242
 
66243
 
66244
 
66245
 
66246
 
66247
 
66248
 
66249
 
66250
 
66251
 
66252
 
66253
 
66254
 
66255
 
66256
 
66257
 
66258
 
66259
 
66260
 
66261
 
66262
 
66263
 
66264
 
66265
 
66266
 
66267
 
66268
 
66269
 
66270
 
66271
 
66272
 
66273
 
66274
 
66275
 
66276
 
66277
 
66278
 
66279
 
66280
 
66281
 
66282
 
66283
 
66284
 
66285
 
66286
 
66287
 
66288
 
66289
 
66290
 
66291
 
66292
 
66293
 
66294
 
66295
 
66296
 
66297
 
66298
 
66299
 
66300
 
66301
 
66302
 
66303
 
66304
 
66305
 
66306
 
66307
 
66308
 
66309
 
66310
 
66311
 
66312
 
66313
 
66314
 
66315
 
66316
 
66317
 
66318
 
66319
 
66320
 
66321
 
66322
 
66323
 
66324
 
66325
 
66326
 
66327
 
66328
 
66329
 
66330
 
66331
 
66332
 
66333
 
66334
 
66335
 
66336
 
66337
 
66338
 
66339
 
66340
 
66341
 
66342
 
66343
 
66344
 
66345
 
66346
 
66347
 
66348
 
66349
 
66350
 
66351
 
66352
 
66353
 
66354
 
66355
 
66356
 
66357
 
66358
 
66359
 
66360
 
66361
 
66362
 
66363
 
66364
 
66365
 
66366
 
66367
 
66368
 
66369
 
66370
 
66371
 
66372
 
66373
 
66374
 
66375
 
66376
 
66377
 
66378
 
66379
 
66380
 
66381
 
66382
 
66383
 
66384
 
66385
 
66386
 
66387
 
66388
 
66389
 
66390
 
66391
 
66392
 
66393
 
66394
 
66395
 
66396
 
66397
 
66398
 
66399
 
66400
 
66401
 
66402
 
66403
 
66404
 
66405
 
66406
 
66407
 
66408
 
66409
 
66410
 
66411
 
66412
 
66413
 
66414
 
66415
 
66416
 
66417
 
66418
 
66419
 
66420
 
66421
 
66422
 
66423
 
66424
 
66425
 
66426
 
66427
 
66428
 
66429
 
66430
 
66431
 
66432
 
66433
 
66434
 
66435
 
66436
 
66437
 
66438
 
66439
 
66440
 
66441
 
66442
 
66443
 
66444
 
66445
 
66446
 
66447
 
66448
 
66449
 
66450
 
66451
 
66452
 
66453
 
66454
 
66455
 
66456
 
66457
 
66458
 
66459
 
66460
 
66461
 
66462
 
66463
 
66464
 
66465
 
66466
 
66467
 
66468
 
66469
 
66470
 
66471
 
66472
 
66473
 
66474
 
66475
 
66476
 
66477
 
66478
 
66479
 
66480
 
66481
 
66482
 
66483
 
66484
 
66485
 
66486
 
66487
 
66488
 
66489
 
66490
 
66491
 
66492
 
66493
 
66494
 
66495
 
66496
 
66497
 
66498
 
66499
 
66500
 
66501
 
66502
 
66503
 
66504
 
66505
 
66506
 
66507
 
66508
 
66509
 
66510
 
66511
 
66512
 
66513
 
66514
 
66515
 
66516
 
66517
 
66518
 
66519
 
66520
 
66521
 
66522
 
66523
 
66524
 
66525
 
66526
 
66527
 
66528
 
66529
 
66530
 
66531
 
66532
 
66533
 
66534
 
66535
 
66536
 
66537
 
66538
 
66539
 
66540
 
66541
 
66542
 
66543
 
66544
 
66545
 
66546
 
66547
 
66548
 
66549
 
66550
 
66551
 
66552
 
66553
 
66554
 
66555
 
66556
 
66557
 
66558
 
66559
 
66560
 
66561
 
66562
 
66563
 
66564
 
66565
 
66566
 
66567
 
66568
 
66569
 
66570
 
66571
 
66572
 
66573
 
66574
 
66575
 
66576
 
66577
 
66578
 
66579
 
66580
 
66581
 
66582
 
66583
 
66584
 
66585
 
66586
 
66587
 
66588
 
66589
 
66590
 
66591
 
66592
 
66593
 
66594
 
66595
 
66596
 
66597
 
66598
 
66599
 
66600
 
66601
 
66602
 
66603
 
66604
 
66605
 
66606
 
66607
 
66608
 
66609
 
66610
 
66611
 
66612
 
66613
 
66614
 
66615
 
66616
 
66617
 
66618
 
66619
 
66620
 
66621
 
66622
 
66623
 
66624
 
66625
 
66626
 
66627
 
66628
 
66629
 
66630
 
66631
 
66632
 
66633
 
66634
 
66635
 
66636
 
66637
 
66638
 
66639
 
66640
 
66641
 
66642
 
66643
 
66644
 
66645
 
66646
 
66647
 
66648
 
66649
 
66650
 
66651
 
66652
 
66653
 
66654
 
66655
 
66656
 
66657
 
66658
 
66659
 
66660
 
66661
 
66662
 
66663
 
66664
 
66665
 
66666
 
66667
 
66668
 
66669
 
66670
 
66671
 
66672
 
66673
 
66674
 
66675
 
66676
 
66677
 
66678
 
66679
 
66680
 
66681
 
66682
 
66683
 
66684
 
66685
 
66686
 
66687
 
66688
 
66689
 
66690
 
66691
 
66692
 
66693
 
66694
 
66695
 
66696
 
66697
 
66698
 
66699
 
66700
 
66701
 
66702
 
66703
 
66704
 
66705
 
66706
 
66707
 
66708
 
66709
 
66710
 
66711
 
66712
 
66713
 
66714
 
66715
 
66716
 
66717
 
66718
 
66719
 
66720
 
66721
 
66722
 
66723
 
66724
 
66725
 
66726
 
66727
 
66728
 
66729
 
66730
 
66731
 
66732
 
66733
 
66734
 
66735
 
66736
 
66737
 
66738
 
66739
 
66740
 
66741
 
66742
 
66743
 
66744
 
66745
 
66746
 
66747
 
66748
 
66749
 
66750
 
66751
 
66752
 
66753
 
66754
 
66755
 
66756
 
66757
 
66758
 
66759
 
66760
 
66761
 
66762
 
66763
 
66764
 
66765
 
66766
 
66767
 
66768
 
66769
 
66770
 
66771
 
66772
 
66773
 
66774
 
66775
 
66776
 
66777
 
66778
 
66779
 
66780
 
66781
 
66782
 
66783
 
66784
 
66785
 
66786
 
66787
 
66788
 
66789
 
66790
 
66791
 
66792
 
66793
 
66794
 
66795
 
66796
 
66797
 
66798
 
66799
 
66800
 
66801
 
66802
 
66803
 
66804
 
66805
 
66806
 
66807
 
66808
 
66809
 
66810
 
66811
 
66812
 
66813
 
66814
 
66815
 
66816
 
66817
 
66818
 
66819
 
66820
 
66821
 
66822
 
66823
 
66824
 
66825
 
66826
 
66827
 
66828
 
66829
 
66830
 
66831
 
66832
 
66833
 
66834
 
66835
 
66836
 
66837
 
66838
 
66839
 
66840
 
66841
 
66842
 
66843
 
66844
 
66845
 
66846
 
66847
 
66848
 
66849
 
66850
 
66851
 
66852
 
66853
 
66854
 
66855
 
66856
 
66857
 
66858
 
66859
 
66860
 
66861
 
66862
 
66863
 
66864
 
66865
 
66866
 
66867
 
66868
 
66869
 
66870
 
66871
 
66872
 
66873
 
66874
 
66875
 
66876
 
66877
 
66878
 
66879
 
66880
 
66881
 
66882
 
66883
 
66884
 
66885
 
66886
 
66887
 
66888
 
66889
 
66890
 
66891
 
66892
 
66893
 
66894
 
66895
 
66896
 
66897
 
66898
 
66899
 
66900
 
66901
 
66902
 
66903
 
66904
 
66905
 
66906
 
66907
 
66908
 
66909
 
66910
 
66911
 
66912
 
66913
 
66914
 
66915
 
66916
 
66917
 
66918
 
66919
 
66920
 
66921
 
66922
 
66923
 
66924
 
66925
 
66926
 
66927
 
66928
 
66929
 
66930
 
66931
 
66932
 
66933
 
66934
 
66935
 
66936
 
66937
 
66938
 
66939
 
66940
 
66941
 
66942
 
66943
 
66944
 
66945
 
66946
 
66947
 
66948
 
66949
 
66950
 
66951
 
66952
 
66953
 
66954
 
66955
 
66956
 
66957
 
66958
 
66959
 
66960
 
66961
 
66962
 
66963
 
66964
 
66965
 
66966
 
66967
 
66968
 
66969
 
66970
 
66971
 
66972
 
66973
 
66974
 
66975
 
66976
 
66977
 
66978
 
66979
 
66980
 
66981
 
66982
 
66983
 
66984
 
66985
 
66986
 
66987
 
66988
 
66989
 
66990
 
66991
 
66992
 
66993
 
66994
 
66995
 
66996
 
66997
 
66998
 
66999
 
67000
 
67001
 
67002
 
67003
 
67004
 
67005
 
67006
 
67007
 
67008
 
67009
 
67010
 
67011
 
67012
 
67013
 
67014
 
67015
 
67016
 
67017
 
67018
 
67019
 
67020
 
67021
 
67022
 
67023
 
67024
 
67025
 
67026
 
67027
 
67028
 
67029
 
67030
 
67031
 
67032
 
67033
 
67034
 
67035
 
67036
 
67037
 
67038
 
67039
 
67040
 
67041
 
67042
 
67043
 
67044
 
67045
 
67046
 
67047
 
67048
 
67049
 
67050
 
67051
 
67052
 
67053
 
67054
 
67055
 
67056
 
67057
 
67058
 
67059
 
67060
 
67061
 
67062
 
67063
 
67064
 
67065
 
67066
 
67067
 
67068
 
67069
 
67070
 
67071
 
67072
 
67073
 
67074
 
67075
 
67076
 
67077
 
67078
 
67079
 
67080
 
67081
 
67082
 
67083
 
67084
 
67085
 
67086
 
67087
 
67088
 
67089
 
67090
 
67091
 
67092
 
67093
 
67094
 
67095
 
67096
 
67097
 
67098
 
67099
 
67100
 
67101
 
67102
 
67103
 
67104
 
67105
 
67106
 
67107
 
67108
 
67109
 
67110
 
67111
 
67112
 
67113
 
67114
 
67115
 
67116
 
67117
 
67118
 
67119
 
67120
 
67121
 
67122
 
67123
 
67124
 
67125
 
67126
 
67127
 
67128
 
67129
 
67130
 
67131
 
67132
 
67133
 
67134
 
67135
 
67136
 
67137
 
67138
 
67139
 
67140
 
67141
 
67142
 
67143
 
67144
 
67145
 
67146
 
67147
 
67148
 
67149
 
67150
 
67151
 
67152
 
67153
 
67154
 
67155
 
67156
 
67157
 
67158
 
67159
 
67160
 
67161
 
67162
 
67163
 
67164
 
67165
 
67166
 
67167
 
67168
 
67169
 
67170
 
67171
 
67172
 
67173
 
67174
 
67175
 
67176
 
67177
 
67178
 
67179
 
67180
 
67181
 
67182
 
67183
 
67184
 
67185
 
67186
 
67187
 
67188
 
67189
 
67190
 
67191
 
67192
 
67193
 
67194
 
67195
 
67196
 
67197
 
67198
 
67199
 
67200
 
67201
 
67202
 
67203
 
67204
 
67205
 
67206
 
67207
 
67208
 
67209
 
67210
 
67211
 
67212
 
67213
 
67214
 
67215
 
67216
 
67217
 
67218
 
67219
 
67220
 
67221
 
67222
 
67223
 
67224
 
67225
 
67226
 
67227
 
67228
 
67229
 
67230
 
67231
 
67232
 
67233
 
67234
 
67235
 
67236
 
67237
 
67238
 
67239
 
67240
 
67241
 
67242
 
67243
 
67244
 
67245
 
67246
 
67247
 
67248
 
67249
 
67250
 
67251
 
67252
 
67253
 
67254
 
67255
 
67256
 
67257
 
67258
 
67259
 
67260
 
67261
 
67262
 
67263
 
67264
 
67265
 
67266
 
67267
 
67268
 
67269
 
67270
 
67271
 
67272
 
67273
 
67274
 
67275
 
67276
 
67277
 
67278
 
67279
 
67280
 
67281
 
67282
 
67283
 
67284
 
67285
 
67286
 
67287
 
67288
 
67289
 
67290
 
67291
 
67292
 
67293
 
67294
 
67295
 
67296
 
67297
 
67298
 
67299
 
67300
 
67301
 
67302
 
67303
 
67304
 
67305
 
67306
 
67307
 
67308
 
67309
 
67310
 
67311
 
67312
 
67313
 
67314
 
67315
 
67316
 
67317
 
67318
 
67319
 
67320
 
67321
 
67322
 
67323
 
67324
 
67325
 
67326
 
67327
 
67328
 
67329
 
67330
 
67331
 
67332
 
67333
 
67334
 
67335
 
67336
 
67337
 
67338
 
67339
 
67340
 
67341
 
67342
 
67343
 
67344
 
67345
 
67346
 
67347
 
67348
 
67349
 
67350
 
67351
 
67352
 
67353
 
67354
 
67355
 
67356
 
67357
 
67358
 
67359
 
67360
 
67361
 
67362
 
67363
 
67364
 
67365
 
67366
 
67367
 
67368
 
67369
 
67370
 
67371
 
67372
 
67373
 
67374
 
67375
 
67376
 
67377
 
67378
 
67379
 
67380
 
67381
 
67382
 
67383
 
67384
 
67385
 
67386
 
67387
 
67388
 
67389
 
67390
 
67391
 
67392
 
67393
 
67394
 
67395
 
67396
 
67397
 
67398
 
67399
 
67400
 
67401
 
67402
 
67403
 
67404
 
67405
 
67406
 
67407
 
67408
 
67409
 
67410
 
67411
 
67412
 
67413
 
67414
 
67415
 
67416
 
67417
 
67418
 
67419
 
67420
 
67421
 
67422
 
67423
 
67424
 
67425
 
67426
 
67427
 
67428
 
67429
 
67430
 
67431
 
67432
 
67433
 
67434
 
67435
 
67436
 
67437
 
67438
 
67439
 
67440
 
67441
 
67442
 
67443
 
67444
 
67445
 
67446
 
67447
 
67448
 
67449
 
67450
 
67451
 
67452
 
67453
 
67454
 
67455
 
67456
 
67457
 
67458
 
67459
 
67460
 
67461
 
67462
 
67463
 
67464
 
67465
 
67466
 
67467
 
67468
 
67469
 
67470
 
67471
 
67472
 
67473
 
67474
 
67475
 
67476
 
67477
 
67478
 
67479
 
67480
 
67481
 
67482
 
67483
 
67484
 
67485
 
67486
 
67487
 
67488
 
67489
 
67490
 
67491
 
67492
 
67493
 
67494
 
67495
 
67496
 
67497
 
67498
 
67499
 
67500
 
67501
 
67502
 
67503
 
67504
 
67505
 
67506
 
67507
 
67508
 
67509
 
67510
 
67511
 
67512
 
67513
 
67514
 
67515
 
67516
 
67517
 
67518
 
67519
 
67520
 
67521
 
67522
 
67523
 
67524
 
67525
 
67526
 
67527
 
67528
 
67529
 
67530
 
67531
 
67532
 
67533
 
67534
 
67535
 
67536
 
67537
 
67538
 
67539
 
67540
 
67541
 
67542
 
67543
 
67544
 
67545
 
67546
 
67547
 
67548
 
67549
 
67550
 
67551
 
67552
 
67553
 
67554
 
67555
 
67556
 
67557
 
67558
 
67559
 
67560
 
67561
 
67562
 
67563
 
67564
 
67565
 
67566
 
67567
 
67568
 
67569
 
67570
 
67571
 
67572
 
67573
 
67574
 
67575
 
67576
 
67577
 
67578
 
67579
 
67580
 
67581
 
67582
 
67583
 
67584
 
67585
 
67586
 
67587
 
67588
 
67589
 
67590
 
67591
 
67592
 
67593
 
67594
 
67595
 
67596
 
67597
 
67598
 
67599
 
67600
 
67601
 
67602
 
67603
 
67604
 
67605
 
67606
 
67607
 
67608
 
67609
 
67610
 
67611
 
67612
 
67613
 
67614
 
67615
 
67616
 
67617
 
67618
 
67619
 
67620
 
67621
 
67622
 
67623
 
67624
 
67625
 
67626
 
67627
 
67628
 
67629
 
67630
 
67631
 
67632
 
67633
 
67634
 
67635
 
67636
 
67637
 
67638
 
67639
 
67640
 
67641
 
67642
 
67643
 
67644
 
67645
 
67646
 
67647
 
67648
 
67649
 
67650
 
67651
 
67652
 
67653
 
67654
 
67655
 
67656
 
67657
 
67658
 
67659
 
67660
 
67661
 
67662
 
67663
 
67664
 
67665
 
67666
 
67667
 
67668
 
67669
 
67670
 
67671
 
67672
 
67673
 
67674
 
67675
 
67676
 
67677
 
67678
 
67679
 
67680
 
67681
 
67682
 
67683
 
67684
 
67685
 
67686
 
67687
 
67688
 
67689
 
67690
 
67691
 
67692
 
67693
 
67694
 
67695
 
67696
 
67697
 
67698
 
67699
 
67700
 
67701
 
67702
 
67703
 
67704
 
67705
 
67706
 
67707
 
67708
 
67709
 
67710
 
67711
 
67712
 
67713
 
67714
 
67715
 
67716
 
67717
 
67718
 
67719
 
67720
 
67721
 
67722
 
67723
 
67724
 
67725
 
67726
 
67727
 
67728
 
67729
 
67730
 
67731
 
67732
 
67733
 
67734
 
67735
 
67736
 
67737
 
67738
 
67739
 
67740
 
67741
 
67742
 
67743
 
67744
 
67745
 
67746
 
67747
 
67748
 
67749
 
67750
 
67751
 
67752
 
67753
 
67754
 
67755
 
67756
 
67757
 
67758
 
67759
 
67760
 
67761
 
67762
 
67763
 
67764
 
67765
 
67766
 
67767
 
67768
 
67769
 
67770
 
67771
 
67772
 
67773
 
67774
 
67775
 
67776
 
67777
 
67778
 
67779
 
67780
 
67781
 
67782
 
67783
 
67784
 
67785
 
67786
 
67787
 
67788
 
67789
 
67790
 
67791
 
67792
 
67793
 
67794
 
67795
 
67796
 
67797
 
67798
 
67799
 
67800
 
67801
 
67802
 
67803
 
67804
 
67805
 
67806
 
67807
 
67808
 
67809
 
67810
 
67811
 
67812
 
67813
 
67814
 
67815
 
67816
 
67817
 
67818
 
67819
 
67820
 
67821
 
67822
 
67823
 
67824
 
67825
 
67826
 
67827
 
67828
 
67829
 
67830
 
67831
 
67832
 
67833
 
67834
 
67835
 
67836
 
67837
 
67838
 
67839
 
67840
 
67841
 
67842
 
67843
 
67844
 
67845
 
67846
 
67847
 
67848
 
67849
 
67850
 
67851
 
67852
 
67853
 
67854
 
67855
 
67856
 
67857
 
67858
 
67859
 
67860
 
67861
 
67862
 
67863
 
67864
 
67865
 
67866
 
67867
 
67868
 
67869
 
67870
 
67871
 
67872
 
67873
 
67874
 
67875
 
67876
 
67877
 
67878
 
67879
 
67880
 
67881
 
67882
 
67883
 
67884
 
67885
 
67886
 
67887
 
67888
 
67889
 
67890
 
67891
 
67892
 
67893
 
67894
 
67895
 
67896
 
67897
 
67898
 
67899
 
67900
 
67901
 
67902
 
67903
 
67904
 
67905
 
67906
 
67907
 
67908
 
67909
 
67910
 
67911
 
67912
 
67913
 
67914
 
67915
 
67916
 
67917
 
67918
 
67919
 
67920
 
67921
 
67922
 
67923
 
67924
 
67925
 
67926
 
67927
 
67928
 
67929
 
67930
 
67931
 
67932
 
67933
 
67934
 
67935
 
67936
 
67937
 
67938
 
67939
 
67940
 
67941
 
67942
 
67943
 
67944
 
67945
 
67946
 
67947
 
67948
 
67949
 
67950
 
67951
 
67952
 
67953
 
67954
 
67955
 
67956
 
67957
 
67958
 
67959
 
67960
 
67961
 
67962
 
67963
 
67964
 
67965
 
67966
 
67967
 
67968
 
67969
 
67970
 
67971
 
67972
 
67973
 
67974
 
67975
 
67976
 
67977
 
67978
 
67979
 
67980
 
67981
 
67982
 
67983
 
67984
 
67985
 
67986
 
67987
 
67988
 
67989
 
67990
 
67991
 
67992
 
67993
 
67994
 
67995
 
67996
 
67997
 
67998
 
67999
 
68000
 
68001
 
68002
 
68003
 
68004
 
68005
 
68006
 
68007
 
68008
 
68009
 
68010
 
68011
 
68012
 
68013
 
68014
 
68015
 
68016
 
68017
 
68018
 
68019
 
68020
 
68021
 
68022
 
68023
 
68024
 
68025
 
68026
 
68027
 
68028
 
68029
 
68030
 
68031
 
68032
 
68033
 
68034
 
68035
 
68036
 
68037
 
68038
 
68039
 
68040
 
68041
 
68042
 
68043
 
68044
 
68045
 
68046
 
68047
 
68048
 
68049
 
68050
 
68051
 
68052
 
68053
 
68054
 
68055
 
68056
 
68057
 
68058
 
68059
 
68060
 
68061
 
68062
 
68063
 
68064
 
68065
 
68066
 
68067
 
68068
 
68069
 
68070
 
68071
 
68072
 
68073
 
68074
 
68075
 
68076
 
68077
 
68078
 
68079
 
68080
 
68081
 
68082
 
68083
 
68084
 
68085
 
68086
 
68087
 
68088
 
68089
 
68090
 
68091
 
68092
 
68093
 
68094
 
68095
 
68096
 
68097
 
68098
 
68099
 
68100
 
68101
 
68102
 
68103
 
68104
 
68105
 
68106
 
68107
 
68108
 
68109
 
68110
 
68111
 
68112
 
68113
 
68114
 
68115
 
68116
 
68117
 
68118
 
68119
 
68120
 
68121
 
68122
 
68123
 
68124
 
68125
 
68126
 
68127
 
68128
 
68129
 
68130
 
68131
 
68132
 
68133
 
68134
 
68135
 
68136
 
68137
 
68138
 
68139
 
68140
 
68141
 
68142
 
68143
 
68144
 
68145
 
68146
 
68147
 
68148
 
68149
 
68150
 
68151
 
68152
 
68153
 
68154
 
68155
 
68156
 
68157
 
68158
 
68159
 
68160
 
68161
 
68162
 
68163
 
68164
 
68165
 
68166
 
68167
 
68168
 
68169
 
68170
 
68171
 
68172
 
68173
 
68174
 
68175
 
68176
 
68177
 
68178
 
68179
 
68180
 
68181
 
68182
 
68183
 
68184
 
68185
 
68186
 
68187
 
68188
 
68189
 
68190
 
68191
 
68192
 
68193
 
68194
 
68195
 
68196
 
68197
 
68198
 
68199
 
68200
 
68201
 
68202
 
68203
 
68204
 
68205
 
68206
 
68207
 
68208
 
68209
 
68210
 
68211
 
68212
 
68213
 
68214
 
68215
 
68216
 
68217
 
68218
 
68219
 
68220
 
68221
 
68222
 
68223
 
68224
 
68225
 
68226
 
68227
 
68228
 
68229
 
68230
 
68231
 
68232
 
68233
 
68234
 
68235
 
68236
 
68237
 
68238
 
68239
 
68240
 
68241
 
68242
 
68243
 
68244
 
68245
 
68246
 
68247
 
68248
 
68249
 
68250
 
68251
 
68252
 
68253
 
68254
 
68255
 
68256
 
68257
 
68258
 
68259
 
68260
 
68261
 
68262
 
68263
 
68264
 
68265
 
68266
 
68267
 
68268
 
68269
 
68270
 
68271
 
68272
 
68273
 
68274
 
68275
 
68276
 
68277
 
68278
 
68279
 
68280
 
68281
 
68282
 
68283
 
68284
 
68285
 
68286
 
68287
 
68288
 
68289
 
68290
 
68291
 
68292
 
68293
 
68294
 
68295
 
68296
 
68297
 
68298
 
68299
 
68300
 
68301
 
68302
 
68303
 
68304
 
68305
 
68306
 
68307
 
68308
 
68309
 
68310
 
68311
 
68312
 
68313
 
68314
 
68315
 
68316
 
68317
 
68318
 
68319
 
68320
 
68321
 
68322
 
68323
 
68324
 
68325
 
68326
 
68327
 
68328
 
68329
 
68330
 
68331
 
68332
 
68333
 
68334
 
68335
 
68336
 
68337
 
68338
 
68339
 
68340
 
68341
 
68342
 
68343
 
68344
 
68345
 
68346
 
68347
 
68348
 
68349
 
68350
 
68351
 
68352
 
68353
 
68354
 
68355
 
68356
 
68357
 
68358
 
68359
 
68360
 
68361
 
68362
 
68363
 
68364
 
68365
 
68366
 
68367
 
68368
 
68369
 
68370
 
68371
 
68372
 
68373
 
68374
 
68375
 
68376
 
68377
 
68378
 
68379
 
68380
 
68381
 
68382
 
68383
 
68384
 
68385
 
68386
 
68387
 
68388
 
68389
 
68390
 
68391
 
68392
 
68393
 
68394
 
68395
 
68396
 
68397
 
68398
 
68399
 
68400
 
68401
 
68402
 
68403
 
68404
 
68405
 
68406
 
68407
 
68408
 
68409
 
68410
 
68411
 
68412
 
68413
 
68414
 
68415
 
68416
 
68417
 
68418
 
68419
 
68420
 
68421
 
68422
 
68423
 
68424
 
68425
 
68426
 
68427
 
68428
 
68429
 
68430
 
68431
 
68432
 
68433
 
68434
 
68435
 
68436
 
68437
 
68438
 
68439
 
68440
 
68441
 
68442
 
68443
 
68444
 
68445
 
68446
 
68447
 
68448
 
68449
 
68450
 
68451
 
68452
 
68453
 
68454
 
68455
 
68456
 
68457
 
68458
 
68459
 
68460
 
68461
 
68462
 
68463
 
68464
 
68465
 
68466
 
68467
 
68468
 
68469
 
68470
 
68471
 
68472
 
68473
 
68474
 
68475
 
68476
 
68477
 
68478
 
68479
 
68480
 
68481
 
68482
 
68483
 
68484
 
68485
 
68486
 
68487
 
68488
 
68489
 
68490
 
68491
 
68492
 
68493
 
68494
 
68495
 
68496
 
68497
 
68498
 
68499
 
68500
 
68501
 
68502
 
68503
 
68504
 
68505
 
68506
 
68507
 
68508
 
68509
 
68510
 
68511
 
68512
 
68513
 
68514
 
68515
 
68516
 
68517
 
68518
 
68519
 
68520
 
68521
 
68522
 
68523
 
68524
 
68525
 
68526
 
68527
 
68528
 
68529
 
68530
 
68531
 
68532
 
68533
 
68534
 
68535
 
68536
 
68537
 
68538
 
68539
 
68540
 
68541
 
68542
 
68543
 
68544
 
68545
 
68546
 
68547
 
68548
 
68549
 
68550
 
68551
 
68552
 
68553
 
68554
 
68555
 
68556
 
68557
 
68558
 
68559
 
68560
 
68561
 
68562
 
68563
 
68564
 
68565
 
68566
 
68567
 
68568
 
68569
 
68570
 
68571
 
68572
 
68573
 
68574
 
68575
 
68576
 
68577
 
68578
 
68579
 
68580
 
68581
 
68582
 
68583
 
68584
 
68585
 
68586
 
68587
 
68588
 
68589
 
68590
 
68591
 
68592
 
68593
 
68594
 
68595
 
68596
 
68597
 
68598
 
68599
 
68600
 
68601
 
68602
 
68603
 
68604
 
68605
 
68606
 
68607
 
68608
 
68609
 
68610
 
68611
 
68612
 
68613
 
68614
 
68615
 
68616
 
68617
 
68618
 
68619
 
68620
 
68621
 
68622
 
68623
 
68624
 
68625
 
68626
 
68627
 
68628
 
68629
 
68630
 
68631
 
68632
 
68633
 
68634
 
68635
 
68636
 
68637
 
68638
 
68639
 
68640
 
68641
 
68642
 
68643
 
68644
 
68645
 
68646
 
68647
 
68648
 
68649
 
68650
 
68651
 
68652
 
68653
 
68654
 
68655
 
68656
 
68657
 
68658
 
68659
 
68660
 
68661
 
68662
 
68663
 
68664
 
68665
 
68666
 
68667
 
68668
 
68669
 
68670
 
68671
 
68672
 
68673
 
68674
 
68675
 
68676
 
68677
 
68678
 
68679
 
68680
 
68681
 
68682
 
68683
 
68684
 
68685
 
68686
 
68687
 
68688
 
68689
 
68690
 
68691
 
68692
 
68693
 
68694
 
68695
 
68696
 
68697
 
68698
 
68699
 
68700
 
68701
 
68702
 
68703
 
68704
 
68705
 
68706
 
68707
 
68708
 
68709
 
68710
 
68711
 
68712
 
68713
 
68714
 
68715
 
68716
 
68717
 
68718
 
68719
 
68720
 
68721
 
68722
 
68723
 
68724
 
68725
 
68726
 
68727
 
68728
 
68729
 
68730
 
68731
 
68732
 
68733
 
68734
 
68735
 
68736
 
68737
 
68738
 
68739
 
68740
 
68741
 
68742
 
68743
 
68744
 
68745
 
68746
 
68747
 
68748
 
68749
 
68750
 
68751
 
68752
 
68753
 
68754
 
68755
 
68756
 
68757
 
68758
 
68759
 
68760
 
68761
 
68762
 
68763
 
68764
 
68765
 
68766
 
68767
 
68768
 
68769
 
68770
 
68771
 
68772
 
68773
 
68774
 
68775
 
68776
 
68777
 
68778
 
68779
 
68780
 
68781
 
68782
 
68783
 
68784
 
68785
 
68786
 
68787
 
68788
 
68789
 
68790
 
68791
 
68792
 
68793
 
68794
 
68795
 
68796
 
68797
 
68798
 
68799
 
68800
 
68801
 
68802
 
68803
 
68804
 
68805
 
68806
 
68807
 
68808
 
68809
 
68810
 
68811
 
68812
 
68813
 
68814
 
68815
 
68816
 
68817
 
68818
 
68819
 
68820
 
68821
 
68822
 
68823
 
68824
 
68825
 
68826
 
68827
 
68828
 
68829
 
68830
 
68831
 
68832
 
68833
 
68834
 
68835
 
68836
 
68837
 
68838
 
68839
 
68840
 
68841
 
68842
 
68843
 
68844
 
68845
 
68846
 
68847
 
68848
 
68849
 
68850
 
68851
 
68852
 
68853
 
68854
 
68855
 
68856
 
68857
 
68858
 
68859
 
68860
 
68861
 
68862
 
68863
 
68864
 
68865
 
68866
 
68867
 
68868
 
68869
 
68870
 
68871
 
68872
 
68873
 
68874
 
68875
 
68876
 
68877
 
68878
 
68879
 
68880
 
68881
 
68882
 
68883
 
68884
 
68885
 
68886
 
68887
 
68888
 
68889
 
68890
 
68891
 
68892
 
68893
 
68894
 
68895
 
68896
 
68897
 
68898
 
68899
 
68900
 
68901
 
68902
 
68903
 
68904
 
68905
 
68906
 
68907
 
68908
 
68909
 
68910
 
68911
 
68912
 
68913
 
68914
 
68915
 
68916
 
68917
 
68918
 
68919
 
68920
 
68921
 
68922
 
68923
 
68924
 
68925
 
68926
 
68927
 
68928
 
68929
 
68930
 
68931
 
68932
 
68933
 
68934
 
68935
 
68936
 
68937
 
68938
 
68939
 
68940
 
68941
 
68942
 
68943
 
68944
 
68945
 
68946
 
68947
 
68948
 
68949
 
68950
 
68951
 
68952
 
68953
 
68954
 
68955
 
68956
 
68957
 
68958
 
68959
 
68960
 
68961
 
68962
 
68963
 
68964
 
68965
 
68966
 
68967
 
68968
 
68969
 
68970
 
68971
 
68972
 
68973
 
68974
 
68975
 
68976
 
68977
 
68978
 
68979
 
68980
 
68981
 
68982
 
68983
 
68984
 
68985
 
68986
 
68987
 
68988
 
68989
 
68990
 
68991
 
68992
 
68993
 
68994
 
68995
 
68996
 
68997
 
68998
 
68999
 
69000
 
69001
 
69002
 
69003
 
69004
 
69005
 
69006
 
69007
 
69008
 
69009
 
69010
 
69011
 
69012
 
69013
 
69014
 
69015
 
69016
 
69017
 
69018
 
69019
 
69020
 
69021
 
69022
 
69023
 
69024
 
69025
 
69026
 
69027
 
69028
 
69029
 
69030
 
69031
 
69032
 
69033
 
69034
 
69035
 
69036
 
69037
 
69038
 
69039
 
69040
 
69041
 
69042
 
69043
 
69044
 
69045
 
69046
 
69047
 
69048
 
69049
 
69050
 
69051
 
69052
 
69053
 
69054
 
69055
 
69056
 
69057
 
69058
 
69059
 
69060
 
69061
 
69062
 
69063
 
69064
 
69065
 
69066
 
69067
 
69068
 
69069
 
69070
 
69071
 
69072
 
69073
 
69074
 
69075
 
69076
 
69077
 
69078
 
69079
 
69080
 
69081
 
69082
 
69083
 
69084
 
69085
 
69086
 
69087
 
69088
 
69089
 
69090
 
69091
 
69092
 
69093
 
69094
 
69095
 
69096
 
69097
 
69098
 
69099
 
69100
 
69101
 
69102
 
69103
 
69104
 
69105
 
69106
 
69107
 
69108
 
69109
 
69110
 
69111
 
69112
 
69113
 
69114
 
69115
 
69116
 
69117
 
69118
 
69119
 
69120
 
69121
 
69122
 
69123
 
69124
 
69125
 
69126
 
69127
 
69128
 
69129
 
69130
 
69131
 
69132
 
69133
 
69134
 
69135
 
69136
 
69137
 
69138
 
69139
 
69140
 
69141
 
69142
 
69143
 
69144
 
69145
 
69146
 
69147
 
69148
 
69149
 
69150
 
69151
 
69152
 
69153
 
69154
 
69155
 
69156
 
69157
 
69158
 
69159
 
69160
 
69161
 
69162
 
69163
 
69164
 
69165
 
69166
 
69167
 
69168
 
69169
 
69170
 
69171
 
69172
 
69173
 
69174
 
69175
 
69176
 
69177
 
69178
 
69179
 
69180
 
69181
 
69182
 
69183
 
69184
 
69185
 
69186
 
69187
 
69188
 
69189
 
69190
 
69191
 
69192
 
69193
 
69194
 
69195
 
69196
 
69197
 
69198
 
69199
 
69200
 
69201
 
69202
 
69203
 
69204
 
69205
 
69206
 
69207
 
69208
 
69209
 
69210
 
69211
 
69212
 
69213
 
69214
 
69215
 
69216
 
69217
 
69218
 
69219
 
69220
 
69221
 
69222
 
69223
 
69224
 
69225
 
69226
 
69227
 
69228
 
69229
 
69230
 
69231
 
69232
 
69233
 
69234
 
69235
 
69236
 
69237
 
69238
 
69239
 
69240
 
69241
 
69242
 
69243
 
69244
 
69245
 
69246
 
69247
 
69248
 
69249
 
69250
 
69251
 
69252
 
69253
 
69254
 
69255
 
69256
 
69257
 
69258
 
69259
 
69260
 
69261
 
69262
 
69263
 
69264
 
69265
 
69266
 
69267
 
69268
 
69269
 
69270
 
69271
 
69272
 
69273
 
69274
 
69275
 
69276
 
69277
 
69278
 
69279
 
69280
 
69281
 
69282
 
69283
 
69284
 
69285
 
69286
 
69287
 
69288
 
69289
 
69290
 
69291
 
69292
 
69293
 
69294
 
69295
 
69296
 
69297
 
69298
 
69299
 
69300
 
69301
 
69302
 
69303
 
69304
 
69305
 
69306
 
69307
 
69308
 
69309
 
69310
 
69311
 
69312
 
69313
 
69314
 
69315
 
69316
 
69317
 
69318
 
69319
 
69320
 
69321
 
69322
 
69323
 
69324
 
69325
 
69326
 
69327
 
69328
 
69329
 
69330
 
69331
 
69332
 
69333
 
69334
 
69335
 
69336
 
69337
 
69338
 
69339
 
69340
 
69341
 
69342
 
69343
 
69344
 
69345
 
69346
 
69347
 
69348
 
69349
 
69350
 
69351
 
69352
 
69353
 
69354
 
69355
 
69356
 
69357
 
69358
 
69359
 
69360
 
69361
 
69362
 
69363
 
69364
 
69365
 
69366
 
69367
 
69368
 
69369
 
69370
 
69371
 
69372
 
69373
 
69374
 
69375
 
69376
 
69377
 
69378
 
69379
 
69380
 
69381
 
69382
 
69383
 
69384
 
69385
 
69386
 
69387
 
69388
 
69389
 
69390
 
69391
 
69392
 
69393
 
69394
 
69395
 
69396
 
69397
 
69398
 
69399
 
69400
 
69401
 
69402
 
69403
 
69404
 
69405
 
69406
 
69407
 
69408
 
69409
 
69410
 
69411
 
69412
 
69413
 
69414
 
69415
 
69416
 
69417
 
69418
 
69419
 
69420
 
69421
 
69422
 
69423
 
69424
 
69425
 
69426
 
69427
 
69428
 
69429
 
69430
 
69431
 
69432
 
69433
 
69434
 
69435
 
69436
 
69437
 
69438
 
69439
 
69440
 
69441
 
69442
 
69443
 
69444
 
69445
 
69446
 
69447
 
69448
 
69449
 
69450
 
69451
 
69452
 
69453
 
69454
 
69455
 
69456
 
69457
 
69458
 
69459
 
69460
 
69461
 
69462
 
69463
 
69464
 
69465
 
69466
 
69467
 
69468
 
69469
 
69470
 
69471
 
69472
 
69473
 
69474
 
69475
 
69476
 
69477
 
69478
 
69479
 
69480
 
69481
 
69482
 
69483
 
69484
 
69485
 
69486
 
69487
 
69488
 
69489
 
69490
 
69491
 
69492
 
69493
 
69494
 
69495
 
69496
 
69497
 
69498
 
69499
 
69500
 
69501
 
69502
 
69503
 
69504
 
69505
 
69506
 
69507
 
69508
 
69509
 
69510
 
69511
 
69512
 
69513
 
69514
 
69515
 
69516
 
69517
 
69518
 
69519
 
69520
 
69521
 
69522
 
69523
 
69524
 
69525
 
69526
 
69527
 
69528
 
69529
 
69530
 
69531
 
69532
 
69533
 
69534
 
69535
 
69536
 
69537
 
69538
 
69539
 
69540
 
69541
 
69542
 
69543
 
69544
 
69545
 
69546
 
69547
 
69548
 
69549
 
69550
 
69551
 
69552
 
69553
 
69554
 
69555
 
69556
 
69557
 
69558
 
69559
 
69560
 
69561
 
69562
 
69563
 
69564
 
69565
 
69566
 
69567
 
69568
 
69569
 
69570
 
69571
 
69572
 
69573
 
69574
 
69575
 
69576
 
69577
 
69578
 
69579
 
69580
 
69581
 
69582
 
69583
 
69584
 
69585
 
69586
 
69587
 
69588
 
69589
 
69590
 
69591
 
69592
 
69593
 
69594
 
69595
 
69596
 
69597
 
69598
 
69599
 
69600
 
69601
 
69602
 
69603
 
69604
 
69605
 
69606
 
69607
 
69608
 
69609
 
69610
 
69611
 
69612
 
69613
 
69614
 
69615
 
69616
 
69617
 
69618
 
69619
 
69620
 
69621
 
69622
 
69623
 
69624
 
69625
 
69626
 
69627
 
69628
 
69629
 
69630
 
69631
 
69632
 
69633
 
69634
 
69635
 
69636
 
69637
 
69638
 
69639
 
69640
 
69641
 
69642
 
69643
 
69644
 
69645
 
69646
 
69647
 
69648
 
69649
 
69650
 
69651
 
69652
 
69653
 
69654
 
69655
 
69656
 
69657
 
69658
 
69659
 
69660
 
69661
 
69662
 
69663
 
69664
 
69665
 
69666
 
69667
 
69668
 
69669
 
69670
 
69671
 
69672
 
69673
 
69674
 
69675
 
69676
 
69677
 
69678
 
69679
 
69680
 
69681
 
69682
 
69683
 
69684
 
69685
 
69686
 
69687
 
69688
 
69689
 
69690
 
69691
 
69692
 
69693
 
69694
 
69695
 
69696
 
69697
 
69698
 
69699
 
69700
 
69701
 
69702
 
69703
 
69704
 
69705
 
69706
 
69707
 
69708
 
69709
 
69710
 
69711
 
69712
 
69713
 
69714
 
69715
 
69716
 
69717
 
69718
 
69719
 
69720
 
69721
 
69722
 
69723
 
69724
 
69725
 
69726
 
69727
 
69728
 
69729
 
69730
 
69731
 
69732
 
69733
 
69734
 
69735
 
69736
 
69737
 
69738
 
69739
 
69740
 
69741
 
69742
 
69743
 
69744
 
69745
 
69746
 
69747
 
69748
 
69749
 
69750
 
69751
 
69752
 
69753
 
69754
 
69755
 
69756
 
69757
 
69758
 
69759
 
69760
 
69761
 
69762
 
69763
 
69764
 
69765
 
69766
 
69767
 
69768
 
69769
 
69770
 
69771
 
69772
 
69773
 
69774
 
69775
 
69776
 
69777
 
69778
 
69779
 
69780
 
69781
 
69782
 
69783
 
69784
 
69785
 
69786
 
69787
 
69788
 
69789
 
69790
 
69791
 
69792
 
69793
 
69794
 
69795
 
69796
 
69797
 
69798
 
69799
 
69800
 
69801
 
69802
 
69803
 
69804
 
69805
 
69806
 
69807
 
69808
 
69809
 
69810
 
69811
 
69812
 
69813
 
69814
 
69815
 
69816
 
69817
 
69818
 
69819
 
69820
 
69821
 
69822
 
69823
 
69824
 
69825
 
69826
 
69827
 
69828
 
69829
 
69830
 
69831
 
69832
 
69833
 
69834
 
69835
 
69836
 
69837
 
69838
 
69839
 
69840
 
69841
 
69842
 
69843
 
69844
 
69845
 
69846
 
69847
 
69848
 
69849
 
69850
 
69851
 
69852
 
69853
 
69854
 
69855
 
69856
 
69857
 
69858
 
69859
 
69860
 
69861
 
69862
 
69863
 
69864
 
69865
 
69866
 
69867
 
69868
 
69869
 
69870
 
69871
 
69872
 
69873
 
69874
 
69875
 
69876
 
69877
 
69878
 
69879
 
69880
 
69881
 
69882
 
69883
 
69884
 
69885
 
69886
 
69887
 
69888
 
69889
 
69890
 
69891
 
69892
 
69893
 
69894
 
69895
 
69896
 
69897
 
69898
 
69899
 
69900
 
69901
 
69902
 
69903
 
69904
 
69905
 
69906
 
69907
 
69908
 
69909
 
69910
 
69911
 
69912
 
69913
 
69914
 
69915
 
69916
 
69917
 
69918
 
69919
 
69920
 
69921
 
69922
 
69923
 
69924
 
69925
 
69926
 
69927
 
69928
 
69929
 
69930
 
69931
 
69932
 
69933
 
69934
 
69935
 
69936
 
69937
 
69938
 
69939
 
69940
 
69941
 
69942
 
69943
 
69944
 
69945
 
69946
 
69947
 
69948
 
69949
 
69950
 
69951
 
69952
 
69953
 
69954
 
69955
 
69956
 
69957
 
69958
 
69959
 
69960
 
69961
 
69962
 
69963
 
69964
 
69965
 
69966
 
69967
 
69968
 
69969
 
69970
 
69971
 
69972
 
69973
 
69974
 
69975
 
69976
 
69977
 
69978
 
69979
 
69980
 
69981
 
69982
 
69983
 
69984
 
69985
 
69986
 
69987
 
69988
 
69989
 
69990
 
69991
 
69992
 
69993
 
69994
 
69995
 
69996
 
69997
 
69998
 
69999
 
70000
 
70001
 
70002
 
70003
 
70004
 
70005
 
70006
 
70007
 
70008
 
70009
 
70010
 
70011
 
70012
 
70013
 
70014
 
70015
 
70016
 
70017
 
70018
 
70019
 
70020
 
70021
 
70022
 
70023
 
70024
 
70025
 
70026
 
70027
 
70028
 
70029
 
70030
 
70031
 
70032
 
70033
 
70034
 
70035
 
70036
 
70037
 
70038
 
70039
 
70040
 
70041
 
70042
 
70043
 
70044
 
70045
 
70046
 
70047
 
70048
 
70049
 
70050
 
70051
 
70052
 
70053
 
70054
 
70055
 
70056
 
70057
 
70058
 
70059
 
70060
 
70061
 
70062
 
70063
 
70064
 
70065
 
70066
 
70067
 
70068
 
70069
 
70070
 
70071
 
70072
 
70073
 
70074
 
70075
 
70076
 
70077
 
70078
 
70079
 
70080
 
70081
 
70082
 
70083
 
70084
 
70085
 
70086
 
70087
 
70088
 
70089
 
70090
 
70091
 
70092
 
70093
 
70094
 
70095
 
70096
 
70097
 
70098
 
70099
 
70100
 
70101
 
70102
 
70103
 
70104
 
70105
 
70106
 
70107
 
70108
 
70109
 
70110
 
70111
 
70112
 
70113
 
70114
 
70115
 
70116
 
70117
 
70118
 
70119
 
70120
 
70121
 
70122
 
70123
 
70124
 
70125
 
70126
 
70127
 
70128
 
70129
 
70130
 
70131
 
70132
 
70133
 
70134
 
70135
 
70136
 
70137
 
70138
 
70139
 
70140
 
70141
 
70142
 
70143
 
70144
 
70145
 
70146
 
70147
 
70148
 
70149
 
70150
 
70151
 
70152
 
70153
 
70154
 
70155
 
70156
 
70157
 
70158
 
70159
 
70160
 
70161
 
70162
 
70163
 
70164
 
70165
 
70166
 
70167
 
70168
 
70169
 
70170
 
70171
 
70172
 
70173
 
70174
 
70175
 
70176
 
70177
 
70178
 
70179
 
70180
 
70181
 
70182
 
70183
 
70184
 
70185
 
70186
 
70187
 
70188
 
70189
 
70190
 
70191
 
70192
 
70193
 
70194
 
70195
 
70196
 
70197
 
70198
 
70199
 
70200
 
70201
 
70202
 
70203
 
70204
 
70205
 
70206
 
70207
 
70208
 
70209
 
70210
 
70211
 
70212
 
70213
 
70214
 
70215
 
70216
 
70217
 
70218
 
70219
 
70220
 
70221
 
70222
 
70223
 
70224
 
70225
 
70226
 
70227
 
70228
 
70229
 
70230
 
70231
 
70232
 
70233
 
70234
 
70235
 
70236
 
70237
 
70238
 
70239
 
70240
 
70241
 
70242
 
70243
 
70244
 
70245
 
70246
 
70247
 
70248
 
70249
 
70250
 
70251
 
70252
 
70253
 
70254
 
70255
 
70256
 
70257
 
70258
 
70259
 
70260
 
70261
 
70262
 
70263
 
70264
 
70265
 
70266
 
70267
 
70268
 
70269
 
70270
 
70271
 
70272
 
70273
 
70274
 
70275
 
70276
 
70277
 
70278
 
70279
 
70280
 
70281
 
70282
 
70283
 
70284
 
70285
 
70286
 
70287
 
70288
 
70289
 
70290
 
70291
 
70292
 
70293
 
70294
 
70295
 
70296
 
70297
 
70298
 
70299
 
70300
 
70301
 
70302
 
70303
 
70304
 
70305
 
70306
 
70307
 
70308
 
70309
 
70310
 
70311
 
70312
 
70313
 
70314
 
70315
 
70316
 
70317
 
70318
 
70319
 
70320
 
70321
 
70322
 
70323
 
70324
 
70325
 
70326
 
70327
 
70328
 
70329
 
70330
 
70331
 
70332
 
70333
 
70334
 
70335
 
70336
 
70337
 
70338
 
70339
 
70340
 
70341
 
70342
 
70343
 
70344
 
70345
 
70346
 
70347
 
70348
 
70349
 
70350
 
70351
 
70352
 
70353
 
70354
 
70355
 
70356
 
70357
 
70358
 
70359
 
70360
 
70361
 
70362
 
70363
 
70364
 
70365
 
70366
 
70367
 
70368
 
70369
 
70370
 
70371
 
70372
 
70373
 
70374
 
70375
 
70376
 
70377
 
70378
 
70379
 
70380
 
70381
 
70382
 
70383
 
70384
 
70385
 
70386
 
70387
 
70388
 
70389
 
70390
 
70391
 
70392
 
70393
 
70394
 
70395
 
70396
 
70397
 
70398
 
70399
 
70400
 
70401
 
70402
 
70403
 
70404
 
70405
 
70406
 
70407
 
70408
 
70409
 
70410
 
70411
 
70412
 
70413
 
70414
 
70415
 
70416
 
70417
 
70418
 
70419
 
70420
 
70421
 
70422
 
70423
 
70424
 
70425
 
70426
 
70427
 
70428
 
70429
 
70430
 
70431
 
70432
 
70433
 
70434
 
70435
 
70436
 
70437
 
70438
 
70439
 
70440
 
70441
 
70442
 
70443
 
70444
 
70445
 
70446
 
70447
 
70448
 
70449
 
70450
 
70451
 
70452
 
70453
 
70454
 
70455
 
70456
 
70457
 
70458
 
70459
 
70460
 
70461
 
70462
 
70463
 
70464
 
70465
 
70466
 
70467
 
70468
 
70469
 
70470
 
70471
 
70472
 
70473
 
70474
 
70475
 
70476
 
70477
 
70478
 
70479
 
70480
 
70481
 
70482
 
70483
 
70484
 
70485
 
70486
 
70487
 
70488
 
70489
 
70490
 
70491
 
70492
 
70493
 
70494
 
70495
 
70496
 
70497
 
70498
 
70499
 
70500
 
70501
 
70502
 
70503
 
70504
 
70505
 
70506
 
70507
 
70508
 
70509
 
70510
 
70511
 
70512
 
70513
 
70514
 
70515
 
70516
 
70517
 
70518
 
70519
 
70520
 
70521
 
70522
 
70523
 
70524
 
70525
 
70526
 
70527
 
70528
 
70529
 
70530
 
70531
 
70532
 
70533
 
70534
 
70535
 
70536
 
70537
 
70538
 
70539
 
70540
 
70541
 
70542
 
70543
 
70544
 
70545
 
70546
 
70547
 
70548
 
70549
 
70550
 
70551
 
70552
 
70553
 
70554
 
70555
 
70556
 
70557
 
70558
 
70559
 
70560
 
70561
 
70562
 
70563
 
70564
 
70565
 
70566
 
70567
 
70568
 
70569
 
70570
 
70571
 
70572
 
70573
 
70574
 
70575
 
70576
 
70577
 
70578
 
70579
 
70580
 
70581
 
70582
 
70583
 
70584
 
70585
 
70586
 
70587
 
70588
 
70589
 
70590
 
70591
 
70592
 
70593
 
70594
 
70595
 
70596
 
70597
 
70598
 
70599
 
70600
 
70601
 
70602
 
70603
 
70604
 
70605
 
70606
 
70607
 
70608
 
70609
 
70610
 
70611
 
70612
 
70613
 
70614
 
70615
 
70616
 
70617
 
70618
 
70619
 
70620
 
70621
 
70622
 
70623
 
70624
 
70625
 
70626
 
70627
 
70628
 
70629
 
70630
 
70631
 
70632
 
70633
 
70634
 
70635
 
70636
 
70637
 
70638
 
70639
 
70640
 
70641
 
70642
 
70643
 
70644
 
70645
 
70646
 
70647
 
70648
 
70649
 
70650
 
70651
 
70652
 
70653
 
70654
 
70655
 
70656
 
70657
 
70658
 
70659
 
70660
 
70661
 
70662
 
70663
 
70664
 
70665
 
70666
 
70667
 
70668
 
70669
 
70670
 
70671
 
70672
 
70673
 
70674
 
70675
 
70676
 
70677
 
70678
 
70679
 
70680
 
70681
 
70682
 
70683
 
70684
 
70685
 
70686
 
70687
 
70688
 
70689
 
70690
 
70691
 
70692
 
70693
 
70694
 
70695
 
70696
 
70697
 
70698
 
70699
 
70700
 
70701
 
70702
 
70703
 
70704
 
70705
 
70706
 
70707
 
70708
 
70709
 
70710
 
70711
 
70712
 
70713
 
70714
 
70715
 
70716
 
70717
 
70718
 
70719
 
70720
 
70721
 
70722
 
70723
 
70724
 
70725
 
70726
 
70727
 
70728
 
70729
 
70730
 
70731
 
70732
 
70733
 
70734
 
70735
 
70736
 
70737
 
70738
 
70739
 
70740
 
70741
 
70742
 
70743
 
70744
 
70745
 
70746
 
70747
 
70748
 
70749
 
70750
 
70751
 
70752
 
70753
 
70754
 
70755
 
70756
 
70757
 
70758
 
70759
 
70760
 
70761
 
70762
 
70763
 
70764
 
70765
 
70766
 
70767
 
70768
 
70769
 
70770
 
70771
 
70772
 
70773
 
70774
 
70775
 
70776
 
70777
 
70778
 
70779
 
70780
 
70781
 
70782
 
70783
 
70784
 
70785
 
70786
 
70787
 
70788
 
70789
 
70790
 
70791
 
70792
 
70793
 
70794
 
70795
 
70796
 
70797
 
70798
 
70799
 
70800
 
70801
 
70802
 
70803
 
70804
 
70805
 
70806
 
70807
 
70808
 
70809
 
70810
 
70811
 
70812
 
70813
 
70814
 
70815
 
70816
 
70817
 
70818
 
70819
 
70820
 
70821
 
70822
 
70823
 
70824
 
70825
 
70826
 
70827
 
70828
 
70829
 
70830
 
70831
 
70832
 
70833
 
70834
 
70835
 
70836
 
70837
 
70838
 
70839
 
70840
 
70841
 
70842
 
70843
 
70844
 
70845
 
70846
 
70847
 
70848
 
70849
 
70850
 
70851
 
70852
 
70853
 
70854
 
70855
 
70856
 
70857
 
70858
 
70859
 
70860
 
70861
 
70862
 
70863
 
70864
 
70865
 
70866
 
70867
 
70868
 
70869
 
70870
 
70871
 
70872
 
70873
 
70874
 
70875
 
70876
 
70877
 
70878
 
70879
 
70880
 
70881
 
70882
 
70883
 
70884
 
70885
 
70886
 
70887
 
70888
 
70889
 
70890
 
70891
 
70892
 
70893
 
70894
 
70895
 
70896
 
70897
 
70898
 
70899
 
70900
 
70901
 
70902
 
70903
 
70904
 
70905
 
70906
 
70907
 
70908
 
70909
 
70910
 
70911
 
70912
 
70913
 
70914
 
70915
 
70916
 
70917
 
70918
 
70919
 
70920
 
70921
 
70922
 
70923
 
70924
 
70925
 
70926
 
70927
 
70928
 
70929
 
70930
 
70931
 
70932
 
70933
 
70934
 
70935
 
70936
 
70937
 
70938
 
70939
 
70940
 
70941
 
70942
 
70943
 
70944
 
70945
 
70946
 
70947
 
70948
 
70949
 
70950
 
70951
 
70952
 
70953
 
70954
 
70955
 
70956
 
70957
 
70958
 
70959
 
70960
 
70961
 
70962
 
70963
 
70964
 
70965
 
70966
 
70967
 
70968
 
70969
 
70970
 
70971
 
70972
 
70973
 
70974
 
70975
 
70976
 
70977
 
70978
 
70979
 
70980
 
70981
 
70982
 
70983
 
70984
 
70985
 
70986
 
70987
 
70988
 
70989
 
70990
 
70991
 
70992
 
70993
 
70994
 
70995
 
70996
 
70997
 
70998
 
70999
 
71000
 
71001
 
71002
 
71003
 
71004
 
71005
 
71006
 
71007
 
71008
 
71009
 
71010
 
71011
 
71012
 
71013
 
71014
 
71015
 
71016
 
71017
 
71018
 
71019
 
71020
 
71021
 
71022
 
71023
 
71024
 
71025
 
71026
 
71027
 
71028
 
71029
 
71030
 
71031
 
71032
 
71033
 
71034
 
71035
 
71036
 
71037
 
71038
 
71039
 
71040
 
71041
 
71042
 
71043
 
71044
 
71045
 
71046
 
71047
 
71048
 
71049
 
71050
 
71051
 
71052
 
71053
 
71054
 
71055
 
71056
 
71057
 
71058
 
71059
 
71060
 
71061
 
71062
 
71063
 
71064
 
71065
 
71066
 
71067
 
71068
 
71069
 
71070
 
71071
 
71072
 
71073
 
71074
 
71075
 
71076
 
71077
 
71078
 
71079
 
71080
 
71081
 
71082
 
71083
 
71084
 
71085
 
71086
 
71087
 
71088
 
71089
 
71090
 
71091
 
71092
 
71093
 
71094
 
71095
 
71096
 
71097
 
71098
 
71099
 
71100
 
71101
 
71102
 
71103
 
71104
 
71105
 
71106
 
71107
 
71108
 
71109
 
71110
 
71111
 
71112
 
71113
 
71114
 
71115
 
71116
 
71117
 
71118
 
71119
 
71120
 
71121
 
71122
 
71123
 
71124
 
71125
 
71126
 
71127
 
71128
 
71129
 
71130
 
71131
 
71132
 
71133
 
71134
 
71135
 
71136
 
71137
 
71138
 
71139
 
71140
 
71141
 
71142
 
71143
 
71144
 
71145
 
71146
 
71147
 
71148
 
71149
 
71150
 
71151
 
71152
 
71153
 
71154
 
71155
 
71156
 
71157
 
71158
 
71159
 
71160
 
71161
 
71162
 
71163
 
71164
 
71165
 
71166
 
71167
 
71168
 
71169
 
71170
 
71171
 
71172
 
71173
 
71174
 
71175
 
71176
 
71177
 
71178
 
71179
 
71180
 
71181
 
71182
 
71183
 
71184
 
71185
 
71186
 
71187
 
71188
 
71189
 
71190
 
71191
 
71192
 
71193
 
71194
 
71195
 
71196
 
71197
 
71198
 
71199
 
71200
 
71201
 
71202
 
71203
 
71204
 
71205
 
71206
 
71207
 
71208
 
71209
 
71210
 
71211
 
71212
 
71213
 
71214
 
71215
 
71216
 
71217
 
71218
 
71219
 
71220
 
71221
 
71222
 
71223
 
71224
 
71225
 
71226
 
71227
 
71228
 
71229
 
71230
 
71231
 
71232
 
71233
 
71234
 
71235
 
71236
 
71237
 
71238
 
71239
 
71240
 
71241
 
71242
 
71243
 
71244
 
71245
 
71246
 
71247
 
71248
 
71249
 
71250
 
71251
 
71252
 
71253
 
71254
 
71255
 
71256
 
71257
 
71258
 
71259
 
71260
 
71261
 
71262
 
71263
 
71264
 
71265
 
71266
 
71267
 
71268
 
71269
 
71270
 
71271
 
71272
 
71273
 
71274
 
71275
 
71276
 
71277
 
71278
 
71279
 
71280
 
71281
 
71282
 
71283
 
71284
 
71285
 
71286
 
71287
 
71288
 
71289
 
71290
 
71291
 
71292
 
71293
 
71294
 
71295
 
71296
 
71297
 
71298
 
71299
 
71300
 
71301
 
71302
 
71303
 
71304
 
71305
 
71306
 
71307
 
71308
 
71309
 
71310
 
71311
 
71312
 
71313
 
71314
 
71315
 
71316
 
71317
 
71318
 
71319
 
71320
 
71321
 
71322
 
71323
 
71324
 
71325
 
71326
 
71327
 
71328
 
71329
 
71330
 
71331
 
71332
 
71333
 
71334
 
71335
 
71336
 
71337
 
71338
 
71339
 
71340
 
71341
 
71342
 
71343
 
71344
 
71345
 
71346
 
71347
 
71348
 
71349
 
71350
 
71351
 
71352
 
71353
 
71354
 
71355
 
71356
 
71357
 
71358
 
71359
 
71360
 
71361
 
71362
 
71363
 
71364
 
71365
 
71366
 
71367
 
71368
 
71369
 
71370
 
71371
 
71372
 
71373
 
71374
 
71375
 
71376
 
71377
 
71378
 
71379
 
71380
 
71381
 
71382
 
71383
 
71384
 
71385
 
71386
 
71387
 
71388
 
71389
 
71390
 
71391
 
71392
 
71393
 
71394
 
71395
 
71396
 
71397
 
71398
 
71399
 
71400
 
71401
 
71402
 
71403
 
71404
 
71405
 
71406
 
71407
 
71408
 
71409
 
71410
 
71411
 
71412
 
71413
 
71414
 
71415
 
71416
 
71417
 
71418
 
71419
 
71420
 
71421
 
71422
 
71423
 
71424
 
71425
 
71426
 
71427
 
71428
 
71429
 
71430
 
71431
 
71432
 
71433
 
71434
 
71435
 
71436
 
71437
 
71438
 
71439
 
71440
 
71441
 
71442
 
71443
 
71444
 
71445
 
71446
 
71447
 
71448
 
71449
 
71450
 
71451
 
71452
 
71453
 
71454
 
71455
 
71456
 
71457
 
71458
 
71459
 
71460
 
71461
 
71462
 
71463
 
71464
 
71465
 
71466
 
71467
 
71468
 
71469
 
71470
 
71471
 
71472
 
71473
 
71474
 
71475
 
71476
 
71477
 
71478
 
71479
 
71480
 
71481
 
71482
 
71483
 
71484
 
71485
 
71486
 
71487
 
71488
 
71489
 
71490
 
71491
 
71492
 
71493
 
71494
 
71495
 
71496
 
71497
 
71498
 
71499
 
71500
 
71501
 
71502
 
71503
 
71504
 
71505
 
71506
 
71507
 
71508
 
71509
 
71510
 
71511
 
71512
 
71513
 
71514
 
71515
 
71516
 
71517
 
71518
 
71519
 
71520
 
71521
 
71522
 
71523
 
71524
 
71525
 
71526
 
71527
 
71528
 
71529
 
71530
 
71531
 
71532
 
71533
 
71534
 
71535
 
71536
 
71537
 
71538
 
71539
 
71540
 
71541
 
71542
 
71543
 
71544
 
71545
 
71546
 
71547
 
71548
 
71549
 
71550
 
71551
 
71552
 
71553
 
71554
 
71555
 
71556
 
71557
 
71558
 
71559
 
71560
 
71561
 
71562
 
71563
 
71564
 
71565
 
71566
 
71567
 
71568
 
71569
 
71570
 
71571
 
71572
 
71573
 
71574
 
71575
 
71576
 
71577
 
71578
 
71579
 
71580
 
71581
 
71582
 
71583
 
71584
 
71585
 
71586
 
71587
 
71588
 
71589
 
71590
 
71591
 
71592
 
71593
 
71594
 
71595
 
71596
 
71597
 
71598
 
71599
 
71600
 
71601
 
71602
 
71603
 
71604
 
71605
 
71606
 
71607
 
71608
 
71609
 
71610
 
71611
 
71612
 
71613
 
71614
 
71615
 
71616
 
71617
 
71618
 
71619
 
71620
 
71621
 
71622
 
71623
 
71624
 
71625
 
71626
 
71627
 
71628
 
71629
 
71630
 
71631
 
71632
 
71633
 
71634
 
71635
 
71636
 
71637
 
71638
 
71639
 
71640
 
71641
 
71642
 
71643
 
71644
 
71645
 
71646
 
71647
 
71648
 
71649
 
71650
 
71651
 
71652
 
71653
 
71654
 
71655
 
71656
 
71657
 
71658
 
71659
 
71660
 
71661
 
71662
 
71663
 
71664
 
71665
 
71666
 
71667
 
71668
 
71669
 
71670
 
71671
 
71672
 
71673
 
71674
 
71675
 
71676
 
71677
 
71678
 
71679
 
71680
 
71681
 
71682
 
71683
 
71684
 
71685
 
71686
 
71687
 
71688
 
71689
 
71690
 
71691
 
71692
 
71693
 
71694
 
71695
 
71696
 
71697
 
71698
 
71699
 
71700
 
71701
 
71702
 
71703
 
71704
 
71705
 
71706
 
71707
 
71708
 
71709
 
71710
 
71711
 
71712
 
71713
 
71714
 
71715
 
71716
 
71717
 
71718
 
71719
 
71720
 
71721
 
71722
 
71723
 
71724
 
71725
 
71726
 
71727
 
71728
 
71729
 
71730
 
71731
 
71732
 
71733
 
71734
 
71735
 
71736
 
71737
 
71738
 
71739
 
71740
 
71741
 
71742
 
71743
 
71744
 
71745
 
71746
 
71747
 
71748
 
71749
 
71750
 
71751
 
71752
 
71753
 
71754
 
71755
 
71756
 
71757
 
71758
 
71759
 
71760
 
71761
 
71762
 
71763
 
71764
 
71765
 
71766
 
71767
 
71768
 
71769
 
71770
 
71771
 
71772
 
71773
 
71774
 
71775
 
71776
 
71777
 
71778
 
71779
 
71780
 
71781
 
71782
 
71783
 
71784
 
71785
 
71786
 
71787
 
71788
 
71789
 
71790
 
71791
 
71792
 
71793
 
71794
 
71795
 
71796
 
71797
 
71798
 
71799
 
71800
 
71801
 
71802
 
71803
 
71804
 
71805
 
71806
 
71807
 
71808
 
71809
 
71810
 
71811
 
71812
 
71813
 
71814
 
71815
 
71816
 
71817
 
71818
 
71819
 
71820
 
71821
 
71822
 
71823
 
71824
 
71825
 
71826
 
71827
 
71828
 
71829
 
71830
 
71831
 
71832
 
71833
 
71834
 
71835
 
71836
 
71837
 
71838
 
71839
 
71840
 
71841
 
71842
 
71843
 
71844
 
71845
 
71846
 
71847
 
71848
 
71849
 
71850
 
71851
 
71852
 
71853
 
71854
 
71855
 
71856
 
71857
 
71858
 
71859
 
71860
 
71861
 
71862
 
71863
 
71864
 
71865
 
71866
 
71867
 
71868
 
71869
 
71870
 
71871
 
71872
 
71873
 
71874
 
71875
 
71876
 
71877
 
71878
 
71879
 
71880
 
71881
 
71882
 
71883
 
71884
 
71885
 
71886
 
71887
 
71888
 
71889
 
71890
 
71891
 
71892
 
71893
 
71894
 
71895
 
71896
 
71897
 
71898
 
71899
 
71900
 
71901
 
71902
 
71903
 
71904
 
71905
 
71906
 
71907
 
71908
 
71909
 
71910
 
71911
 
71912
 
71913
 
71914
 
71915
 
71916
 
71917
 
71918
 
71919
 
71920
 
71921
 
71922
 
71923
 
71924
 
71925
 
71926
 
71927
 
71928
 
71929
 
71930
 
71931
 
71932
 
71933
 
71934
 
71935
 
71936
 
71937
 
71938
 
71939
 
71940
 
71941
 
71942
 
71943
 
71944
 
71945
 
71946
 
71947
 
71948
 
71949
 
71950
 
71951
 
71952
 
71953
 
71954
 
71955
 
71956
 
71957
 
71958
 
71959
 
71960
 
71961
 
71962
 
71963
 
71964
 
71965
 
71966
 
71967
 
71968
 
71969
 
71970
 
71971
 
71972
 
71973
 
71974
 
71975
 
71976
 
71977
 
71978
 
71979
 
71980
 
71981
 
71982
 
71983
 
71984
 
71985
 
71986
 
71987
 
71988
 
71989
 
71990
 
71991
 
71992
 
71993
 
71994
 
71995
 
71996
 
71997
 
71998
 
71999
 
72000
 
72001
 
72002
 
72003
 
72004
 
72005
 
72006
 
72007
 
72008
 
72009
 
72010
 
72011
 
72012
 
72013
 
72014
 
72015
 
72016
 
72017
 
72018
 
72019
 
72020
 
72021
 
72022
 
72023
 
72024
 
72025
 
72026
 
72027
 
72028
 
72029
 
72030
 
72031
 
72032
 
72033
 
72034
 
72035
 
72036
 
72037
 
72038
 
72039
 
72040
 
72041
 
72042
 
72043
 
72044
 
72045
 
72046
 
72047
 
72048
 
72049
 
72050
 
72051
 
72052
 
72053
 
72054
 
72055
 
72056
 
72057
 
72058
 
72059
 
72060
 
72061
 
72062
 
72063
 
72064
 
72065
 
72066
 
72067
 
72068
 
72069
 
72070
 
72071
 
72072
 
72073
 
72074
 
72075
 
72076
 
72077
 
72078
 
72079
 
72080
 
72081
 
72082
 
72083
 
72084
 
72085
 
72086
 
72087
 
72088
 
72089
 
72090
 
72091
 
72092
 
72093
 
72094
 
72095
 
72096
 
72097
 
72098
 
72099
 
72100
 
72101
 
72102
 
72103
 
72104
 
72105
 
72106
 
72107
 
72108
 
72109
 
72110
 
72111
 
72112
 
72113
 
72114
 
72115
 
72116
 
72117
 
72118
 
72119
 
72120
 
72121
 
72122
 
72123
 
72124
 
72125
 
72126
 
72127
 
72128
 
72129
 
72130
 
72131
 
72132
 
72133
 
72134
 
72135
 
72136
 
72137
 
72138
 
72139
 
72140
 
72141
 
72142
 
72143
 
72144
 
72145
 
72146
 
72147
 
72148
 
72149
 
72150
 
72151
 
72152
 
72153
 
72154
 
72155
 
72156
 
72157
 
72158
 
72159
 
72160
 
72161
 
72162
 
72163
 
72164
 
72165
 
72166
 
72167
 
72168
 
72169
 
72170
 
72171
 
72172
 
72173
 
72174
 
72175
 
72176
 
72177
 
72178
 
72179
 
72180
 
72181
 
72182
 
72183
 
72184
 
72185
 
72186
 
72187
 
72188
 
72189
 
72190
 
72191
 
72192
 
72193
 
72194
 
72195
 
72196
 
72197
 
72198
 
72199
 
72200
 
72201
 
72202
 
72203
 
72204
 
72205
 
72206
 
72207
 
72208
 
72209
 
72210
 
72211
 
72212
 
72213
 
72214
 
72215
 
72216
 
72217
 
72218
 
72219
 
72220
 
72221
 
72222
 
72223
 
72224
 
72225
 
72226
 
72227
 
72228
 
72229
 
72230
 
72231
 
72232
 
72233
 
72234
 
72235
 
72236
 
72237
 
72238
 
72239
 
72240
 
72241
 
72242
 
72243
 
72244
 
72245
 
72246
 
72247
 
72248
 
72249
 
72250
 
72251
 
72252
 
72253
 
72254
 
72255
 
72256
 
72257
 
72258
 
72259
 
72260
 
72261
 
72262
 
72263
 
72264
 
72265
 
72266
 
72267
 
72268
 
72269
 
72270
 
72271
 
72272
 
72273
 
72274
 
72275
 
72276
 
72277
 
72278
 
72279
 
72280
 
72281
 
72282
 
72283
 
72284
 
72285
 
72286
 
72287
 
72288
 
72289
 
72290
 
72291
 
72292
 
72293
 
72294
 
72295
 
72296
 
72297
 
72298
 
72299
 
72300
 
72301
 
72302
 
72303
 
72304
 
72305
 
72306
 
72307
 
72308
 
72309
 
72310
 
72311
 
72312
 
72313
 
72314
 
72315
 
72316
 
72317
 
72318
 
72319
 
72320
 
72321
 
72322
 
72323
 
72324
 
72325
 
72326
 
72327
 
72328
 
72329
 
72330
 
72331
 
72332
 
72333
 
72334
 
72335
 
72336
 
72337
 
72338
 
72339
 
72340
 
72341
 
72342
 
72343
 
72344
 
72345
 
72346
 
72347
 
72348
 
72349
 
72350
 
72351
 
72352
 
72353
 
72354
 
72355
 
72356
 
72357
 
72358
 
72359
 
72360
 
72361
 
72362
 
72363
 
72364
 
72365
 
72366
 
72367
 
72368
 
72369
 
72370
 
72371
 
72372
 
72373
 
72374
 
72375
 
72376
 
72377
 
72378
 
72379
 
72380
 
72381
 
72382
 
72383
 
72384
 
72385
 
72386
 
72387
 
72388
 
72389
 
72390
 
72391
 
72392
 
72393
 
72394
 
72395
 
72396
 
72397
 
72398
 
72399
 
72400
 
72401
 
72402
 
72403
 
72404
 
72405
 
72406
 
72407
 
72408
 
72409
 
72410
 
72411
 
72412
 
72413
 
72414
 
72415
 
72416
 
72417
 
72418
 
72419
 
72420
 
72421
 
72422
 
72423
 
72424
 
72425
 
72426
 
72427
 
72428
 
72429
 
72430
 
72431
 
72432
 
72433
 
72434
 
72435
 
72436
 
72437
 
72438
 
72439
 
72440
 
72441
 
72442
 
72443
 
72444
 
72445
 
72446
 
72447
 
72448
 
72449
 
72450
 
72451
 
72452
 
72453
 
72454
 
72455
 
72456
 
72457
 
72458
 
72459
 
72460
 
72461
 
72462
 
72463
 
72464
 
72465
 
72466
 
72467
 
72468
 
72469
 
72470
 
72471
 
72472
 
72473
 
72474
 
72475
 
72476
 
72477
 
72478
 
72479
 
72480
 
72481
 
72482
 
72483
 
72484
 
72485
 
72486
 
72487
 
72488
 
72489
 
72490
 
72491
 
72492
 
72493
 
72494
 
72495
 
72496
 
72497
 
72498
 
72499
 
72500
 
72501
 
72502
 
72503
 
72504
 
72505
 
72506
 
72507
 
72508
 
72509
 
72510
 
72511
 
72512
 
72513
 
72514
 
72515
 
72516
 
72517
 
72518
 
72519
 
72520
 
72521
 
72522
 
72523
 
72524
 
72525
 
72526
 
72527
 
72528
 
72529
 
72530
 
72531
 
72532
 
72533
 
72534
 
72535
 
72536
 
72537
 
72538
 
72539
 
72540
 
72541
 
72542
 
72543
 
72544
 
72545
 
72546
 
72547
 
72548
 
72549
 
72550
 
72551
 
72552
 
72553
 
72554
 
72555
 
72556
 
72557
 
72558
 
72559
 
72560
 
72561
 
72562
 
72563
 
72564
 
72565
 
72566
 
72567
 
72568
 
72569
 
72570
 
72571
 
72572
 
72573
 
72574
 
72575
 
72576
 
72577
 
72578
 
72579
 
72580
 
72581
 
72582
 
72583
 
72584
 
72585
 
72586
 
72587
 
72588
 
72589
 
72590
 
72591
 
72592
 
72593
 
72594
 
72595
 
72596
 
72597
 
72598
 
72599
 
72600
 
72601
 
72602
 
72603
 
72604
 
72605
 
72606
 
72607
 
72608
 
72609
 
72610
 
72611
 
72612
 
72613
 
72614
 
72615
 
72616
 
72617
 
72618
 
72619
 
72620
 
72621
 
72622
 
72623
 
72624
 
72625
 
72626
 
72627
 
72628
 
72629
 
72630
 
72631
 
72632
 
72633
 
72634
 
72635
 
72636
 
72637
 
72638
 
72639
 
72640
 
72641
 
72642
 
72643
 
72644
 
72645
 
72646
 
72647
 
72648
 
72649
 
72650
 
72651
 
72652
 
72653
 
72654
 
72655
 
72656
 
72657
 
72658
 
72659
 
72660
 
72661
 
72662
 
72663
 
72664
 
72665
 
72666
 
72667
 
72668
 
72669
 
72670
 
72671
 
72672
 
72673
 
72674
 
72675
 
72676
 
72677
 
72678
 
72679
 
72680
 
72681
 
72682
 
72683
 
72684
 
72685
 
72686
 
72687
 
72688
 
72689
 
72690
 
72691
 
72692
 
72693
 
72694
 
72695
 
72696
 
72697
 
72698
 
72699
 
72700
 
72701
 
72702
 
72703
 
72704
 
72705
 
72706
 
72707
 
72708
 
72709
 
72710
 
72711
 
72712
 
72713
 
72714
 
72715
 
72716
 
72717
 
72718
 
72719
 
72720
 
72721
 
72722
 
72723
 
72724
 
72725
 
72726
 
72727
 
72728
 
72729
 
72730
 
72731
 
72732
 
72733
 
72734
 
72735
 
72736
 
72737
 
72738
 
72739
 
72740
 
72741
 
72742
 
72743
 
72744
 
72745
 
72746
 
72747
 
72748
 
72749
 
72750
 
72751
 
72752
 
72753
 
72754
 
72755
 
72756
 
72757
 
72758
 
72759
 
72760
 
72761
 
72762
 
72763
 
72764
 
72765
 
72766
 
72767
 
72768
 
72769
 
72770
 
72771
 
72772
 
72773
 
72774
 
72775
 
72776
 
72777
 
72778
 
72779
 
72780
 
72781
 
72782
 
72783
 
72784
 
72785
 
72786
 
72787
 
72788
 
72789
 
72790
 
72791
 
72792
 
72793
 
72794
 
72795
 
72796
 
72797
 
72798
 
72799
 
72800
 
72801
 
72802
 
72803
 
72804
 
72805
 
72806
 
72807
 
72808
 
72809
 
72810
 
72811
 
72812
 
72813
 
72814
 
72815
 
72816
 
72817
 
72818
 
72819
 
72820
 
72821
 
72822
 
72823
 
72824
 
72825
 
72826
 
72827
 
72828
 
72829
 
72830
 
72831
 
72832
 
72833
 
72834
 
72835
 
72836
 
72837
 
72838
 
72839
 
72840
 
72841
 
72842
 
72843
 
72844
 
72845
 
72846
 
72847
 
72848
 
72849
 
72850
 
72851
 
72852
 
72853
 
72854
 
72855
 
72856
 
72857
 
72858
 
72859
 
72860
 
72861
 
72862
 
72863
 
72864
 
72865
 
72866
 
72867
 
72868
 
72869
 
72870
 
72871
 
72872
 
72873
 
72874
 
72875
 
72876
 
72877
 
72878
 
72879
 
72880
 
72881
 
72882
 
72883
 
72884
 
72885
 
72886
 
72887
 
72888
 
72889
 
72890
 
72891
 
72892
 
72893
 
72894
 
72895
 
72896
 
72897
 
72898
 
72899
 
72900
 
72901
 
72902
 
72903
 
72904
 
72905
 
72906
 
72907
 
72908
 
72909
 
72910
 
72911
 
72912
 
72913
 
72914
 
72915
 
72916
 
72917
 
72918
 
72919
 
72920
 
72921
 
72922
 
72923
 
72924
 
72925
 
72926
 
72927
 
72928
 
72929
 
72930
 
72931
 
72932
 
72933
 
72934
 
72935
 
72936
 
72937
 
72938
 
72939
 
72940
 
72941
 
72942
 
72943
 
72944
 
72945
 
72946
 
72947
 
72948
 
72949
 
72950
 
72951
 
72952
 
72953
 
72954
 
72955
 
72956
 
72957
 
72958
 
72959
 
72960
 
72961
 
72962
 
72963
 
72964
 
72965
 
72966
 
72967
 
72968
 
72969
 
72970
 
72971
 
72972
 
72973
 
72974
 
72975
 
72976
 
72977
 
72978
 
72979
 
72980
 
72981
 
72982
 
72983
 
72984
 
72985
 
72986
 
72987
 
72988
 
72989
 
72990
 
72991
 
72992
 
72993
 
72994
 
72995
 
72996
 
72997
 
72998
 
72999
 
73000
 
73001
 
73002
 
73003
 
73004
 
73005
 
73006
 
73007
 
73008
 
73009
 
73010
 
73011
 
73012
 
73013
 
73014
 
73015
 
73016
 
73017
 
73018
 
73019
 
73020
 
73021
 
73022
 
73023
 
73024
 
73025
 
73026
 
73027
 
73028
 
73029
 
73030
 
73031
 
73032
 
73033
 
73034
 
73035
 
73036
 
73037
 
73038
 
73039
 
73040
 
73041
 
73042
 
73043
 
73044
 
73045
 
73046
 
73047
 
73048
 
73049
 
73050
 
73051
 
73052
 
73053
 
73054
 
73055
 
73056
 
73057
 
73058
 
73059
 
73060
 
73061
 
73062
 
73063
 
73064
 
73065
 
73066
 
73067
 
73068
 
73069
 
73070
 
73071
 
73072
 
73073
 
73074
 
73075
 
73076
 
73077
 
73078
 
73079
 
73080
 
73081
 
73082
 
73083
 
73084
 
73085
 
73086
 
73087
 
73088
 
73089
 
73090
 
73091
 
73092
 
73093
 
73094
 
73095
 
73096
 
73097
 
73098
 
73099
 
73100
 
73101
 
73102
 
73103
 
73104
 
73105
 
73106
 
73107
 
73108
 
73109
 
73110
 
73111
 
73112
 
73113
 
73114
 
73115
 
73116
 
73117
 
73118
 
73119
 
73120
 
73121
 
73122
 
73123
 
73124
 
73125
 
73126
 
73127
 
73128
 
73129
 
73130
 
73131
 
73132
 
73133
 
73134
 
73135
 
73136
 
73137
 
73138
 
73139
 
73140
 
73141
 
73142
 
73143
 
73144
 
73145
 
73146
 
73147
 
73148
 
73149
 
73150
 
73151
 
73152
 
73153
 
73154
 
73155
 
73156
 
73157
 
73158
 
73159
 
73160
 
73161
 
73162
 
73163
 
73164
 
73165
 
73166
 
73167
 
73168
 
73169
 
73170
 
73171
 
73172
 
73173
 
73174
 
73175
 
73176
 
73177
 
73178
 
73179
 
73180
 
73181
 
73182
 
73183
 
73184
 
73185
 
73186
 
73187
 
73188
 
73189
 
73190
 
73191
 
73192
 
73193
 
73194
 
73195
 
73196
 
73197
 
73198
 
73199
 
73200
 
73201
 
73202
 
73203
 
73204
 
73205
 
73206
 
73207
 
73208
 
73209
 
73210
 
73211
 
73212
 
73213
 
73214
 
73215
 
73216
 
73217
 
73218
 
73219
 
73220
 
73221
 
73222
 
73223
 
73224
 
73225
 
73226
 
73227
 
73228
 
73229
 
73230
 
73231
 
73232
 
73233
 
73234
 
73235
 
73236
 
73237
 
73238
 
73239
 
73240
 
73241
 
73242
 
73243
 
73244
 
73245
 
73246
 
73247
 
73248
 
73249
 
73250
 
73251
 
73252
 
73253
 
73254
 
73255
 
73256
 
73257
 
73258
 
73259
 
73260
 
73261
 
73262
 
73263
 
73264
 
73265
 
73266
 
73267
 
73268
 
73269
 
73270
 
73271
 
73272
 
73273
 
73274
 
73275
 
73276
 
73277
 
73278
 
73279
 
73280
 
73281
 
73282
 
73283
 
73284
 
73285
 
73286
 
73287
 
73288
 
73289
 
73290
 
73291
 
73292
 
73293
 
73294
 
73295
 
73296
 
73297
 
73298
 
73299
 
73300
 
73301
 
73302
 
73303
 
73304
 
73305
 
73306
 
73307
 
73308
 
73309
 
73310
 
73311
 
73312
 
73313
 
73314
 
73315
 
73316
 
73317
 
73318
 
73319
 
73320
 
73321
 
73322
 
73323
 
73324
 
73325
 
73326
 
73327
 
73328
 
73329
 
73330
 
73331
 
73332
 
73333
 
73334
 
73335
 
73336
 
73337
 
73338
 
73339
 
73340
 
73341
 
73342
 
73343
 
73344
 
73345
 
73346
 
73347
 
73348
 
73349
 
73350
 
73351
 
73352
 
73353
 
73354
 
73355
 
73356
 
73357
 
73358
 
73359
 
73360
 
73361
 
73362
 
73363
 
73364
 
73365
 
73366
 
73367
 
73368
 
73369
 
73370
 
73371
 
73372
 
73373
 
73374
 
73375
 
73376
 
73377
 
73378
 
73379
 
73380
 
73381
 
73382
 
73383
 
73384
 
73385
 
73386
 
73387
 
73388
 
73389
 
73390
 
73391
 
73392
 
73393
 
73394
 
73395
 
73396
 
73397
 
73398
 
73399
 
73400
 
73401
 
73402
 
73403
 
73404
 
73405
 
73406
 
73407
 
73408
 
73409
 
73410
 
73411
 
73412
 
73413
 
73414
 
73415
 
73416
 
73417
 
73418
 
73419
 
73420
 
73421
 
73422
 
73423
 
73424
 
73425
 
73426
 
73427
 
73428
 
73429
 
73430
 
73431
 
73432
 
73433
 
73434
 
73435
 
73436
 
73437
 
73438
 
73439
 
73440
 
73441
 
73442
 
73443
 
73444
 
73445
 
73446
 
73447
 
73448
 
73449
 
73450
 
73451
 
73452
 
73453
 
73454
 
73455
 
73456
 
73457
 
73458
 
73459
 
73460
 
73461
 
73462
 
73463
 
73464
 
73465
 
73466
 
73467
 
73468
 
73469
 
73470
 
73471
 
73472
 
73473
 
73474
 
73475
 
73476
 
73477
 
73478
 
73479
 
73480
 
73481
 
73482
 
73483
 
73484
 
73485
 
73486
 
73487
 
73488
 
73489
 
73490
 
73491
 
73492
 
73493
 
73494
 
73495
 
73496
 
73497
 
73498
 
73499
 
73500
 
73501
 
73502
 
73503
 
73504
 
73505
 
73506
 
73507
 
73508
 
73509
 
73510
 
73511
 
73512
 
73513
 
73514
 
73515
 
73516
 
73517
 
73518
 
73519
 
73520
 
73521
 
73522
 
73523
 
73524
 
73525
 
73526
 
73527
 
73528
 
73529
 
73530
 
73531
 
73532
 
73533
 
73534
 
73535
 
73536
 
73537
 
73538
 
73539
 
73540
 
73541
 
73542
 
73543
 
73544
 
73545
 
73546
 
73547
 
73548
 
73549
 
73550
 
73551
 
73552
 
73553
 
73554
 
73555
 
73556
 
73557
 
73558
 
73559
 
73560
 
73561
 
73562
 
73563
 
73564
 
73565
 
73566
 
73567
 
73568
 
73569
 
73570
 
73571
 
73572
 
73573
 
73574
 
73575
 
73576
 
73577
 
73578
 
73579
 
73580
 
73581
 
73582
 
73583
 
73584
 
73585
 
73586
 
73587
 
73588
 
73589
 
73590
 
73591
 
73592
 
73593
 
73594
 
73595
 
73596
 
73597
 
73598
 
73599
 
73600
 
73601
 
73602
 
73603
 
73604
 
73605
 
73606
 
73607
 
73608
 
73609
 
73610
 
73611
 
73612
 
73613
 
73614
 
73615
 
73616
 
73617
 
73618
 
73619
 
73620
 
73621
 
73622
 
73623
 
73624
 
73625
 
73626
 
73627
 
73628
 
73629
 
73630
 
73631
 
73632
 
73633
 
73634
 
73635
 
73636
 
73637
 
73638
 
73639
 
73640
 
73641
 
73642
 
73643
 
73644
 
73645
 
73646
 
73647
 
73648
 
73649
 
73650
 
73651
 
73652
 
73653
 
73654
 
73655
 
73656
 
73657
 
73658
 
73659
 
73660
 
73661
 
73662
 
73663
 
73664
 
73665
 
73666
 
73667
 
73668
 
73669
 
73670
 
73671
 
73672
 
73673
 
73674
 
73675
 
73676
 
73677
 
73678
 
73679
 
73680
 
73681
 
73682
 
73683
 
73684
 
73685
 
73686
 
73687
 
73688
 
73689
 
73690
 
73691
 
73692
 
73693
 
73694
 
73695
 
73696
 
73697
 
73698
 
73699
 
73700
 
73701
 
73702
 
73703
 
73704
 
73705
 
73706
 
73707
 
73708
 
73709
 
73710
 
73711
 
73712
 
73713
 
73714
 
73715
 
73716
 
73717
 
73718
 
73719
 
73720
 
73721
 
73722
 
73723
 
73724
 
73725
 
73726
 
73727
 
73728
 
73729
 
73730
 
73731
 
73732
 
73733
 
73734
 
73735
 
73736
 
73737
 
73738
 
73739
 
73740
 
73741
 
73742
 
73743
 
73744
 
73745
 
73746
 
73747
 
73748
 
73749
 
73750
 
73751
 
73752
 
73753
 
73754
 
73755
 
73756
 
73757
 
73758
 
73759
 
73760
 
73761
 
73762
 
73763
 
73764
 
73765
 
73766
 
73767
 
73768
 
73769
 
73770
 
73771
 
73772
 
73773
 
73774
 
73775
 
73776
 
73777
 
73778
 
73779
 
73780
 
73781
 
73782
 
73783
 
73784
 
73785
 
73786
 
73787
 
73788
 
73789
 
73790
 
73791
 
73792
 
73793
 
73794
 
73795
 
73796
 
73797
 
73798
 
73799
 
73800
 
73801
 
73802
 
73803
 
73804
 
73805
 
73806
 
73807
 
73808
 
73809
 
73810
 
73811
 
73812
 
73813
 
73814
 
73815
 
73816
 
73817
 
73818
 
73819
 
73820
 
73821
 
73822
 
73823
 
73824
 
73825
 
73826
 
73827
 
73828
 
73829
 
73830
 
73831
 
73832
 
73833
 
73834
 
73835
 
73836
 
73837
 
73838
 
73839
 
73840
 
73841
 
73842
 
73843
 
73844
 
73845
 
73846
 
73847
 
73848
 
73849
 
73850
 
73851
 
73852
 
73853
 
73854
 
73855
 
73856
 
73857
 
73858
 
73859
 
73860
 
73861
 
73862
 
73863
 
73864
 
73865
 
73866
 
73867
 
73868
 
73869
 
73870
 
73871
 
73872
 
73873
 
73874
 
73875
 
73876
 
73877
 
73878
 
73879
 
73880
 
73881
 
73882
 
73883
 
73884
 
73885
 
73886
 
73887
 
73888
 
73889
 
73890
 
73891
 
73892
 
73893
 
73894
 
73895
 
73896
 
73897
 
73898
 
73899
 
73900
 
73901
 
73902
 
73903
 
73904
 
73905
 
73906
 
73907
 
73908
 
73909
 
73910
 
73911
 
73912
 
73913
 
73914
 
73915
 
73916
 
73917
 
73918
 
73919
 
73920
 
73921
 
73922
 
73923
 
73924
 
73925
 
73926
 
73927
 
73928
 
73929
 
73930
 
73931
 
73932
 
73933
 
73934
 
73935
 
73936
 
73937
 
73938
 
73939
 
73940
 
73941
 
73942
 
73943
 
73944
 
73945
 
73946
 
73947
 
73948
 
73949
 
73950
 
73951
 
73952
 
73953
 
73954
 
73955
 
73956
 
73957
 
73958
 
73959
 
73960
 
73961
 
73962
 
73963
 
73964
 
73965
 
73966
 
73967
 
73968
 
73969
 
73970
 
73971
 
73972
 
73973
 
73974
 
73975
 
73976
 
73977
 
73978
 
73979
 
73980
 
73981
 
73982
 
73983
 
73984
 
73985
 
73986
 
73987
 
73988
 
73989
 
73990
 
73991
 
73992
 
73993
 
73994
 
73995
 
73996
 
73997
 
73998
 
73999
 
74000
 
74001
 
74002
 
74003
 
74004
 
74005
 
74006
 
74007
 
74008
 
74009
 
74010
 
74011
 
74012
 
74013
 
74014
 
74015
 
74016
 
74017
 
74018
 
74019
 
74020
 
74021
 
74022
 
74023
 
74024
 
74025
 
74026
 
74027
 
74028
 
74029
 
74030
 
74031
 
74032
 
74033
 
74034
 
74035
 
74036
 
74037
 
74038
 
74039
 
74040
 
74041
 
74042
 
74043
 
74044
 
74045
 
74046
 
74047
 
74048
 
74049
 
74050
 
74051
 
74052
 
74053
 
74054
 
74055
 
74056
 
74057
 
74058
 
74059
 
74060
 
74061
 
74062
 
74063
 
74064
 
74065
 
74066
 
74067
 
74068
 
74069
 
74070
 
74071
 
74072
 
74073
 
74074
 
74075
 
74076
 
74077
 
74078
 
74079
 
74080
 
74081
 
74082
 
74083
 
74084
 
74085
 
74086
 
74087
 
74088
 
74089
 
74090
 
74091
 
74092
 
74093
 
74094
 
74095
 
74096
 
74097
 
74098
 
74099
 
74100
 
74101
 
74102
 
74103
 
74104
 
74105
 
74106
 
74107
 
74108
 
74109
 
74110
 
74111
 
74112
 
74113
 
74114
 
74115
 
74116
 
74117
 
74118
 
74119
 
74120
 
74121
 
74122
 
74123
 
74124
 
74125
 
74126
 
74127
 
74128
 
74129
 
74130
 
74131
 
74132
 
74133
 
74134
 
74135
 
74136
 
74137
 
74138
 
74139
 
74140
 
74141
 
74142
 
74143
 
74144
 
74145
 
74146
 
74147
 
74148
 
74149
 
74150
 
74151
 
74152
 
74153
 
74154
 
74155
 
74156
 
74157
 
74158
 
74159
 
74160
 
74161
 
74162
 
74163
 
74164
 
74165
 
74166
 
74167
 
74168
 
74169
 
74170
 
74171
 
74172
 
74173
 
74174
 
74175
 
74176
 
74177
 
74178
 
74179
 
74180
 
74181
 
74182
 
74183
 
74184
 
74185
 
74186
 
74187
 
74188
 
74189
 
74190
 
74191
 
74192
 
74193
 
74194
 
74195
 
74196
 
74197
 
74198
 
74199
 
74200
 
74201
 
74202
 
74203
 
74204
 
74205
 
74206
 
74207
 
74208
 
74209
 
74210
 
74211
 
74212
 
74213
 
74214
 
74215
 
74216
 
74217
 
74218
 
74219
 
74220
 
74221
 
74222
 
74223
 
74224
 
74225
 
74226
 
74227
 
74228
 
74229
 
74230
 
74231
 
74232
 
74233
 
74234
 
74235
 
74236
 
74237
 
74238
 
74239
 
74240
 
74241
 
74242
 
74243
 
74244
 
74245
 
74246
 
74247
 
74248
 
74249
 
74250
 
74251
 
74252
 
74253
 
74254
 
74255
 
74256
 
74257
 
74258
 
74259
 
74260
 
74261
 
74262
 
74263
 
74264
 
74265
 
74266
 
74267
 
74268
 
74269
 
74270
 
74271
 
74272
 
74273
 
74274
 
74275
 
74276
 
74277
 
74278
 
74279
 
74280
 
74281
 
74282
 
74283
 
74284
 
74285
 
74286
 
74287
 
74288
 
74289
 
74290
 
74291
 
74292
 
74293
 
74294
 
74295
 
74296
 
74297
 
74298
 
74299
 
74300
 
74301
 
74302
 
74303
 
74304
 
74305
 
74306
 
74307
 
74308
 
74309
 
74310
 
74311
 
74312
 
74313
 
74314
 
74315
 
74316
 
74317
 
74318
 
74319
 
74320
 
74321
 
74322
 
74323
 
74324
 
74325
 
74326
 
74327
 
74328
 
74329
 
74330
 
74331
 
74332
 
74333
 
74334
 
74335
 
74336
 
74337
 
74338
 
74339
 
74340
 
74341
 
74342
 
74343
 
74344
 
74345
 
74346
 
74347
 
74348
 
74349
 
74350
 
74351
 
74352
 
74353
 
74354
 
74355
 
74356
 
74357
 
74358
 
74359
 
74360
 
74361
 
74362
 
74363
 
74364
 
74365
 
74366
 
74367
 
74368
 
74369
 
74370
 
74371
 
74372
 
74373
 
74374
 
74375
 
74376
 
74377
 
74378
 
74379
 
74380
 
74381
 
74382
 
74383
 
74384
 
74385
 
74386
 
74387
 
74388
 
74389
 
74390
 
74391
 
74392
 
74393
 
74394
 
74395
 
74396
 
74397
 
74398
 
74399
 
74400
 
74401
 
74402
 
74403
 
74404
 
74405
 
74406
 
74407
 
74408
 
74409
 
74410
 
74411
 
74412
 
74413
 
74414
 
74415
 
74416
 
74417
 
74418
 
74419
 
74420
 
74421
 
74422
 
74423
 
74424
 
74425
 
74426
 
74427
 
74428
 
74429
 
74430
 
74431
 
74432
 
74433
 
74434
 
74435
 
74436
 
74437
 
74438
 
74439
 
74440
 
74441
 
74442
 
74443
 
74444
 
74445
 
74446
 
74447
 
74448
 
74449
 
74450
 
74451
 
74452
 
74453
 
74454
 
74455
 
74456
 
74457
 
74458
 
74459
 
74460
 
74461
 
74462
 
74463
 
74464
 
74465
 
74466
 
74467
 
74468
 
74469
 
74470
 
74471
 
74472
 
74473
 
74474
 
74475
 
74476
 
74477
 
74478
 
74479
 
74480
 
74481
 
74482
 
74483
 
74484
 
74485
 
74486
 
74487
 
74488
 
74489
 
74490
 
74491
 
74492
 
74493
 
74494
 
74495
 
74496
 
74497
 
74498
 
74499
 
74500
 
74501
 
74502
 
74503
 
74504
 
74505
 
74506
 
74507
 
74508
 
74509
 
74510
 
74511
 
74512
 
74513
 
74514
 
74515
 
74516
 
74517
 
74518
 
74519
 
74520
 
74521
 
74522
 
74523
 
74524
 
74525
 
74526
 
74527
 
74528
 
74529
 
74530
 
74531
 
74532
 
74533
 
74534
 
74535
 
74536
 
74537
 
74538
 
74539
 
74540
 
74541
 
74542
 
74543
 
74544
 
74545
 
74546
 
74547
 
74548
 
74549
 
74550
 
74551
 
74552
 
74553
 
74554
 
74555
 
74556
 
74557
 
74558
 
74559
 
74560
 
74561
 
74562
 
74563
 
74564
 
74565
 
74566
 
74567
 
74568
 
74569
 
74570
 
74571
 
74572
 
74573
 
74574
 
74575
 
74576
 
74577
 
74578
 
74579
 
74580
 
74581
 
74582
 
74583
 
74584
 
74585
 
74586
 
74587
 
74588
 
74589
 
74590
 
74591
 
74592
 
74593
 
74594
 
74595
 
74596
 
74597
 
74598
 
74599
 
74600
 
74601
 
74602
 
74603
 
74604
 
74605
 
74606
 
74607
 
74608
 
74609
 
74610
 
74611
 
74612
 
74613
 
74614
 
74615
 
74616
 
74617
 
74618
 
74619
 
74620
 
74621
 
74622
 
74623
 
74624
 
74625
 
74626
 
74627
 
74628
 
74629
 
74630
 
74631
 
74632
 
74633
 
74634
 
74635
 
74636
 
74637
 
74638
 
74639
 
74640
 
74641
 
74642
 
74643
 
74644
 
74645
 
74646
 
74647
 
74648
 
74649
 
74650
 
74651
 
74652
 
74653
 
74654
 
74655
 
74656
 
74657
 
74658
 
74659
 
74660
 
74661
 
74662
 
74663
 
74664
 
74665
 
74666
 
74667
 
74668
 
74669
 
74670
 
74671
 
74672
 
74673
 
74674
 
74675
 
74676
 
74677
 
74678
 
74679
 
74680
 
74681
 
74682
 
74683
 
74684
 
74685
 
74686
 
74687
 
74688
 
74689
 
74690
 
74691
 
74692
 
74693
 
74694
 
74695
 
74696
 
74697
 
74698
 
74699
 
74700
 
74701
 
74702
 
74703
 
74704
 
74705
 
74706
 
74707
 
74708
 
74709
 
74710
 
74711
 
74712
 
74713
 
74714
 
74715
 
74716
 
74717
 
74718
 
74719
 
74720
 
74721
 
74722
 
74723
 
74724
 
74725
 
74726
 
74727
 
74728
 
74729
 
74730
 
74731
 
74732
 
74733
 
74734
 
74735
 
74736
 
74737
 
74738
 
74739
 
74740
 
74741
 
74742
 
74743
 
74744
 
74745
 
74746
 
74747
 
74748
 
74749
 
74750
 
74751
 
74752
 
74753
 
74754
 
74755
 
74756
 
74757
 
74758
 
74759
 
74760
 
74761
 
74762
 
74763
 
74764
 
74765
 
74766
 
74767
 
74768
 
74769
 
74770
 
74771
 
74772
 
74773
 
74774
 
74775
 
74776
 
74777
 
74778
 
74779
 
74780
 
74781
 
74782
 
74783
 
74784
 
74785
 
74786
 
74787
 
74788
 
74789
 
74790
 
74791
 
74792
 
74793
 
74794
 
74795
 
74796
 
74797
 
74798
 
74799
 
74800
 
74801
 
74802
 
74803
 
74804
 
74805
 
74806
 
74807
 
74808
 
74809
 
74810
 
74811
 
74812
 
74813
 
74814
 
74815
 
74816
 
74817
 
74818
 
74819
 
74820
 
74821
 
74822
 
74823
 
74824
 
74825
 
74826
 
74827
 
74828
 
74829
 
74830
 
74831
 
74832
 
74833
 
74834
 
74835
 
74836
 
74837
 
74838
 
74839
 
74840
 
74841
 
74842
 
74843
 
74844
 
74845
 
74846
 
74847
 
74848
 
74849
 
74850
 
74851
 
74852
 
74853
 
74854
 
74855
 
74856
 
74857
 
74858
 
74859
 
74860
 
74861
 
74862
 
74863
 
74864
 
74865
 
74866
 
74867
 
74868
 
74869
 
74870
 
74871
 
74872
 
74873
 
74874
 
74875
 
74876
 
74877
 
74878
 
74879
 
74880
 
74881
 
74882
 
74883
 
74884
 
74885
 
74886
 
74887
 
74888
 
74889
 
74890
 
74891
 
74892
 
74893
 
74894
 
74895
 
74896
 
74897
 
74898
 
74899
 
74900
 
74901
 
74902
 
74903
 
74904
 
74905
 
74906
 
74907
 
74908
 
74909
 
74910
 
74911
 
74912
 
74913
 
74914
 
74915
 
74916
 
74917
 
74918
 
74919
 
74920
 
74921
 
74922
 
74923
 
74924
 
74925
 
74926
 
74927
 
74928
 
74929
 
74930
 
74931
 
74932
 
74933
 
74934
 
74935
 
74936
 
74937
 
74938
 
74939
 
74940
 
74941
 
74942
 
74943
 
74944
 
74945
 
74946
 
74947
 
74948
 
74949
 
74950
 
74951
 
74952
 
74953
 
74954
 
74955
 
74956
 
74957
 
74958
 
74959
 
74960
 
74961
 
74962
 
74963
 
74964
 
74965
 
74966
 
74967
 
74968
 
74969
 
74970
 
74971
 
74972
 
74973
 
74974
 
74975
 
74976
 
74977
 
74978
 
74979
 
74980
 
74981
 
74982
 
74983
 
74984
 
74985
 
74986
 
74987
 
74988
 
74989
 
74990
 
74991
 
74992
 
74993
 
74994
 
74995
 
74996
 
74997
 
74998
 
74999
 
75000
 
75001
 
75002
 
75003
 
75004
 
75005
 
75006
 
75007
 
75008
 
75009
 
75010
 
75011
 
75012
 
75013
 
75014
 
75015
 
75016
 
75017
 
75018
 
75019
 
75020
 
75021
 
75022
 
75023
 
75024
 
75025
 
75026
 
75027
 
75028
 
75029
 
75030
 
75031
 
75032
 
75033
 
75034
 
75035
 
75036
 
75037
 
75038
 
75039
 
75040
 
75041
 
75042
 
75043
 
75044
 
75045
 
75046
 
75047
 
75048
 
75049
 
75050
 
75051
 
75052
 
75053
 
75054
 
75055
 
75056
 
75057
 
75058
 
75059
 
75060
 
75061
 
75062
 
75063
 
75064
 
75065
 
75066
 
75067
 
75068
 
75069
 
75070
 
75071
 
75072
 
75073
 
75074
 
75075
 
75076
 
75077
 
75078
 
75079
 
75080
 
75081
 
75082
 
75083
 
75084
 
75085
 
75086
 
75087
 
75088
 
75089
 
75090
 
75091
 
75092
 
75093
 
75094
 
75095
 
75096
 
75097
 
75098
 
75099
 
75100
 
75101
 
75102
 
75103
 
75104
 
75105
 
75106
 
75107
 
75108
 
75109
 
75110
 
75111
 
75112
 
75113
 
75114
 
75115
 
75116
 
75117
 
75118
 
75119
 
75120
 
75121
 
75122
 
75123
 
75124
 
75125
 
75126
 
75127
 
75128
 
75129
 
75130
 
75131
 
75132
 
75133
 
75134
 
75135
 
75136
 
75137
 
75138
 
75139
 
75140
 
75141
 
75142
 
75143
 
75144
 
75145
 
75146
 
75147
 
75148
 
75149
 
75150
 
75151
 
75152
 
75153
 
75154
 
75155
 
75156
 
75157
 
75158
 
75159
 
75160
 
75161
 
75162
 
75163
 
75164
 
75165
 
75166
 
75167
 
75168
 
75169
 
75170
 
75171
 
75172
 
75173
 
75174
 
75175
 
75176
 
75177
 
75178
 
75179
 
75180
 
75181
 
75182
 
75183
 
75184
 
75185
 
75186
 
75187
 
75188
 
75189
 
75190
 
75191
 
75192
 
75193
 
75194
 
75195
 
75196
 
75197
 
75198
 
75199
 
75200
 
75201
 
75202
 
75203
 
75204
 
75205
 
75206
 
75207
 
75208
 
75209
 
75210
 
75211
 
75212
 
75213
 
75214
 
75215
 
75216
 
75217
 
75218
 
75219
 
75220
 
75221
 
75222
 
75223
 
75224
 
75225
 
75226
 
75227
 
75228
 
75229
 
75230
 
75231
 
75232
 
75233
 
75234
 
75235
 
75236
 
75237
 
75238
 
75239
 
75240
 
75241
 
75242
 
75243
 
75244
 
75245
 
75246
 
75247
 
75248
 
75249
 
75250
 
75251
 
75252
 
75253
 
75254
 
75255
 
75256
 
75257
 
75258
 
75259
 
75260
 
75261
 
75262
 
75263
 
75264
 
75265
 
75266
 
75267
 
75268
 
75269
 
75270
 
75271
 
75272
 
75273
 
75274
 
75275
 
75276
 
75277
 
75278
 
75279
 
75280
 
75281
 
75282
 
75283
 
75284
 
75285
 
75286
 
75287
 
75288
 
75289
 
75290
 
75291
 
75292
 
75293
 
75294
 
75295
 
75296
 
75297
 
75298
 
75299
 
75300
 
75301
 
75302
 
75303
 
75304
 
75305
 
75306
 
75307
 
75308
 
75309
 
75310
 
75311
 
75312
 
75313
 
75314
 
75315
 
75316
 
75317
 
75318
 
75319
 
75320
 
75321
 
75322
 
75323
 
75324
 
75325
 
75326
 
75327
 
75328
 
75329
 
75330
 
75331
 
75332
 
75333
 
75334
 
75335
 
75336
 
75337
 
75338
 
75339
 
75340
 
75341
 
75342
 
75343
 
75344
 
75345
 
75346
 
75347
 
75348
 
75349
 
75350
 
75351
 
75352
 
75353
 
75354
 
75355
 
75356
 
75357
 
75358
 
75359
 
75360
 
75361
 
75362
 
75363
 
75364
 
75365
 
75366
 
75367
 
75368
 
75369
 
75370
 
75371
 
75372
 
75373
 
75374
 
75375
 
75376
 
75377
 
75378
 
75379
 
75380
 
75381
 
75382
 
75383
 
75384
 
75385
 
75386
 
75387
 
75388
 
75389
 
75390
 
75391
 
75392
 
75393
 
75394
 
75395
 
75396
 
75397
 
75398
 
75399
 
75400
 
75401
 
75402
 
75403
 
75404
 
75405
 
75406
 
75407
 
75408
 
75409
 
75410
 
75411
 
75412
 
75413
 
75414
 
75415
 
75416
 
75417
 
75418
 
75419
 
75420
 
75421
 
75422
 
75423
 
75424
 
75425
 
75426
 
75427
 
75428
 
75429
 
75430
 
75431
 
75432
 
75433
 
75434
 
75435
 
75436
 
75437
 
75438
 
75439
 
75440
 
75441
 
75442
 
75443
 
75444
 
75445
 
75446
 
75447
 
75448
 
75449
 
75450
 
75451
 
75452
 
75453
 
75454
 
75455
 
75456
 
75457
 
75458
 
75459
 
75460
 
75461
 
75462
 
75463
 
75464
 
75465
 
75466
 
75467
 
75468
 
75469
 
75470
 
75471
 
75472
 
75473
 
75474
 
75475
 
75476
 
75477
 
75478
 
75479
 
75480
 
75481
 
75482
 
75483
 
75484
 
75485
 
75486
 
75487
 
75488
 
75489
 
75490
 
75491
 
75492
 
75493
 
75494
 
75495
 
75496
 
75497
 
75498
 
75499
 
75500
 
75501
 
75502
 
75503
 
75504
 
75505
 
75506
 
75507
 
75508
 
75509
 
75510
 
75511
 
75512
 
75513
 
75514
 
75515
 
75516
 
75517
 
75518
 
75519
 
75520
 
75521
 
75522
 
75523
 
75524
 
75525
 
75526
 
75527
 
75528
 
75529
 
75530
 
75531
 
75532
 
75533
 
75534
 
75535
 
75536
 
75537
 
75538
 
75539
 
75540
 
75541
 
75542
 
75543
 
75544
 
75545
 
75546
 
75547
 
75548
 
75549
 
75550
 
75551
 
75552
 
75553
 
75554
 
75555
 
75556
 
75557
 
75558
 
75559
 
75560
 
75561
 
75562
 
75563
 
75564
 
75565
 
75566
 
75567
 
75568
 
75569
 
75570
 
75571
 
75572
 
75573
 
75574
 
75575
 
75576
 
75577
 
75578
 
75579
 
75580
 
75581
 
75582
 
75583
 
75584
 
75585
 
75586
 
75587
 
75588
 
75589
 
75590
 
75591
 
75592
 
75593
 
75594
 
75595
 
75596
 
75597
 
75598
 
75599
 
75600
 
75601
 
75602
 
75603
 
75604
 
75605
 
75606
 
75607
 
75608
 
75609
 
75610
 
75611
 
75612
 
75613
 
75614
 
75615
 
75616
 
75617
 
75618
 
75619
 
75620
 
75621
 
75622
 
75623
 
75624
 
75625
 
75626
 
75627
 
75628
 
75629
 
75630
 
75631
 
75632
 
75633
 
75634
 
75635
 
75636
 
75637
 
75638
 
75639
 
75640
 
75641
 
75642
 
75643
 
75644
 
75645
 
75646
 
75647
 
75648
 
75649
 
75650
 
75651
 
75652
 
75653
 
75654
 
75655
 
75656
 
75657
 
75658
 
75659
 
75660
 
75661
 
75662
 
75663
 
75664
 
75665
 
75666
 
75667
 
75668
 
75669
 
75670
 
75671
 
75672
 
75673
 
75674
 
75675
 
75676
 
75677
 
75678
 
75679
 
75680
 
75681
 
75682
 
75683
 
75684
 
75685
 
75686
 
75687
 
75688
 
75689
 
75690
 
75691
 
75692
 
75693
 
75694
 
75695
 
75696
 
75697
 
75698
 
75699
 
75700
 
75701
 
75702
 
75703
 
75704
 
75705
 
75706
 
75707
 
75708
 
75709
 
75710
 
75711
 
75712
 
75713
 
75714
 
75715
 
75716
 
75717
 
75718
 
75719
 
75720
 
75721
 
75722
 
75723
 
75724
 
75725
 
75726
 
75727
 
75728
 
75729
 
75730
 
75731
 
75732
 
75733
 
75734
 
75735
 
75736
 
75737
 
75738
 
75739
 
75740
 
75741
 
75742
 
75743
 
75744
 
75745
 
75746
 
75747
 
75748
 
75749
 
75750
 
75751
 
75752
 
75753
 
75754
 
75755
 
75756
 
75757
 
75758
 
75759
 
75760
 
75761
 
75762
 
75763
 
75764
 
75765
 
75766
 
75767
 
75768
 
75769
 
75770
 
75771
 
75772
 
75773
 
75774
 
75775
 
75776
 
75777
 
75778
 
75779
 
75780
 
75781
 
75782
 
75783
 
75784
 
75785
 
75786
 
75787
 
75788
 
75789
 
75790
 
75791
 
75792
 
75793
 
75794
 
75795
 
75796
 
75797
 
75798
 
75799
 
75800
 
75801
 
75802
 
75803
 
75804
 
75805
 
75806
 
75807
 
75808
 
75809
 
75810
 
75811
 
75812
 
75813
 
75814
 
75815
 
75816
 
75817
 
75818
 
75819
 
75820
 
75821
 
75822
 
75823
 
75824
 
75825
 
75826
 
75827
 
75828
 
75829
 
75830
 
75831
 
75832
 
75833
 
75834
 
75835
 
75836
 
75837
 
75838
 
75839
 
75840
 
75841
 
75842
 
75843
 
75844
 
75845
 
75846
 
75847
 
75848
 
75849
 
75850
 
75851
 
75852
 
75853
 
75854
 
75855
 
75856
 
75857
 
75858
 
75859
 
75860
 
75861
 
75862
 
75863
 
75864
 
75865
 
75866
 
75867
 
75868
 
75869
 
75870
 
75871
 
75872
 
75873
 
75874
 
75875
 
75876
 
75877
 
75878
 
75879
 
75880
 
75881
 
75882
 
75883
 
75884
 
75885
 
75886
 
75887
 
75888
 
75889
 
75890
 
75891
 
75892
 
75893
 
75894
 
75895
 
75896
 
75897
 
75898
 
75899
 
75900
 
75901
 
75902
 
75903
 
75904
 
75905
 
75906
 
75907
 
75908
 
75909
 
75910
 
75911
 
75912
 
75913
 
75914
 
75915
 
75916
 
75917
 
75918
 
75919
 
75920
 
75921
 
75922
 
75923
 
75924
 
75925
 
75926
 
75927
 
75928
 
75929
 
75930
 
75931
 
75932
 
75933
 
75934
 
75935
 
75936
 
75937
 
75938
 
75939
 
75940
 
75941
 
75942
 
75943
 
75944
 
75945
 
75946
 
75947
 
75948
 
75949
 
75950
 
75951
 
75952
 
75953
 
75954
 
75955
 
75956
 
75957
 
75958
 
75959
 
75960
 
75961
 
75962
 
75963
 
75964
 
75965
 
75966
 
75967
 
75968
 
75969
 
75970
 
75971
 
75972
 
75973
 
75974
 
75975
 
75976
 
75977
 
75978
 
75979
 
75980
 
75981
 
75982
 
75983
 
75984
 
75985
 
75986
 
75987
 
75988
 
75989
 
75990
 
75991
 
75992
 
75993
 
75994
 
75995
 
75996
 
75997
 
75998
 
75999
 
76000
 
76001
 
76002
 
76003
 
76004
 
76005
 
76006
 
76007
 
76008
 
76009
 
76010
 
76011
 
76012
 
76013
 
76014
 
76015
 
76016
 
76017
 
76018
 
76019
 
76020
 
76021
 
76022
 
76023
 
76024
 
76025
 
76026
 
76027
 
76028
 
76029
 
76030
 
76031
 
76032
 
76033
 
76034
 
76035
 
76036
 
76037
 
76038
 
76039
 
76040
 
76041
 
76042
 
76043
 
76044
 
76045
 
76046
 
76047
 
76048
 
76049
 
76050
 
76051
 
76052
 
76053
 
76054
 
76055
 
76056
 
76057
 
76058
 
76059
 
76060
 
76061
 
76062
 
76063
 
76064
 
76065
 
76066
 
76067
 
76068
 
76069
 
76070
 
76071
 
76072
 
76073
 
76074
 
76075
 
76076
 
76077
 
76078
 
76079
 
76080
 
76081
 
76082
 
76083
 
76084
 
76085
 
76086
 
76087
 
76088
 
76089
 
76090
 
76091
 
76092
 
76093
 
76094
 
76095
 
76096
 
76097
 
76098
 
76099
 
76100
 
76101
 
76102
 
76103
 
76104
 
76105
 
76106
 
76107
 
76108
 
76109
 
76110
 
76111
 
76112
 
76113
 
76114
 
76115
 
76116
 
76117
 
76118
 
76119
 
76120
 
76121
 
76122
 
76123
 
76124
 
76125
 
76126
 
76127
 
76128
 
76129
 
76130
 
76131
 
76132
 
76133
 
76134
 
76135
 
76136
 
76137
 
76138
 
76139
 
76140
 
76141
 
76142
 
76143
 
76144
 
76145
 
76146
 
76147
 
76148
 
76149
 
76150
 
76151
 
76152
 
76153
 
76154
 
76155
 
76156
 
76157
 
76158
 
76159
 
76160
 
76161
 
76162
 
76163
 
76164
 
76165
 
76166
 
76167
 
76168
 
76169
 
76170
 
76171
 
76172
 
76173
 
76174
 
76175
 
76176
 
76177
 
76178
 
76179
 
76180
 
76181
 
76182
 
76183
 
76184
 
76185
 
76186
 
76187
 
76188
 
76189
 
76190
 
76191
 
76192
 
76193
 
76194
 
76195
 
76196
 
76197
 
76198
 
76199
 
76200
 
76201
 
76202
 
76203
 
76204
 
76205
 
76206
 
76207
 
76208
 
76209
 
76210
 
76211
 
76212
 
76213
 
76214
 
76215
 
76216
 
76217
 
76218
 
76219
 
76220
 
76221
 
76222
 
76223
 
76224
 
76225
 
76226
 
76227
 
76228
 
76229
 
76230
 
76231
 
76232
 
76233
 
76234
 
76235
 
76236
 
76237
 
76238
 
76239
 
76240
 
76241
 
76242
 
76243
 
76244
 
76245
 
76246
 
76247
 
76248
 
76249
 
76250
 
76251
 
76252
 
76253
 
76254
 
76255
 
76256
 
76257
 
76258
 
76259
 
76260
 
76261
 
76262
 
76263
 
76264
 
76265
 
76266
 
76267
 
76268
 
76269
 
76270
 
76271
 
76272
 
76273
 
76274
 
76275
 
76276
 
76277
 
76278
 
76279
 
76280
 
76281
 
76282
 
76283
 
76284
 
76285
 
76286
 
76287
 
76288
 
76289
 
76290
 
76291
 
76292
 
76293
 
76294
 
76295
 
76296
 
76297
 
76298
 
76299
 
76300
 
76301
 
76302
 
76303
 
76304
 
76305
 
76306
 
76307
 
76308
 
76309
 
76310
 
76311
 
76312
 
76313
 
76314
 
76315
 
76316
 
76317
 
76318
 
76319
 
76320
 
76321
 
76322
 
76323
 
76324
 
76325
 
76326
 
76327
 
76328
 
76329
 
76330
 
76331
 
76332
 
76333
 
76334
 
76335
 
76336
 
76337
 
76338
 
76339
 
76340
 
76341
 
76342
 
76343
 
76344
 
76345
 
76346
 
76347
 
76348
 
76349
 
76350
 
76351
 
76352
 
76353
 
76354
 
76355
 
76356
 
76357
 
76358
 
76359
 
76360
 
76361
 
76362
 
76363
 
76364
 
76365
 
76366
 
76367
 
76368
 
76369
 
76370
 
76371
 
76372
 
76373
 
76374
 
76375
 
76376
 
76377
 
76378
 
76379
 
76380
 
76381
 
76382
 
76383
 
76384
 
76385
 
76386
 
76387
 
76388
 
76389
 
76390
 
76391
 
76392
 
76393
 
76394
 
76395
 
76396
 
76397
 
76398
 
76399
 
76400
 
76401
 
76402
 
76403
 
76404
 
76405
 
76406
 
76407
 
76408
 
76409
 
76410
 
76411
 
76412
 
76413
 
76414
 
76415
 
76416
 
76417
 
76418
 
76419
 
76420
 
76421
 
76422
 
76423
 
76424
 
76425
 
76426
 
76427
 
76428
 
76429
 
76430
 
76431
 
76432
 
76433
 
76434
 
76435
 
76436
 
76437
 
76438
 
76439
 
76440
 
76441
 
76442
 
76443
 
76444
 
76445
 
76446
 
76447
 
76448
 
76449
 
76450
 
76451
 
76452
 
76453
 
76454
 
76455
 
76456
 
76457
 
76458
 
76459
 
76460
 
76461
 
76462
 
76463
 
76464
 
76465
 
76466
 
76467
 
76468
 
76469
 
76470
 
76471
 
76472
 
76473
 
76474
 
76475
 
76476
 
76477
 
76478
 
76479
 
76480
 
76481
 
76482
 
76483
 
76484
 
76485
 
76486
 
76487
 
76488
 
76489
 
76490
 
76491
 
76492
 
76493
 
76494
 
76495
 
76496
 
76497
 
76498
 
76499
 
76500
 
76501
 
76502
 
76503
 
76504
 
76505
 
76506
 
76507
 
76508
 
76509
 
76510
 
76511
 
76512
 
76513
 
76514
 
76515
 
76516
 
76517
 
76518
 
76519
 
76520
 
76521
 
76522
 
76523
 
76524
 
76525
 
76526
 
76527
 
76528
 
76529
 
76530
 
76531
 
76532
 
76533
 
76534
 
76535
 
76536
 
76537
 
76538
 
76539
 
76540
 
76541
 
76542
 
76543
 
76544
 
76545
 
76546
 
76547
 
76548
 
76549
 
76550
 
76551
 
76552
 
76553
 
76554
 
76555
 
76556
 
76557
 
76558
 
76559
 
76560
 
76561
 
76562
 
76563
 
76564
 
76565
 
76566
 
76567
 
76568
 
76569
 
76570
 
76571
 
76572
 
76573
 
76574
 
76575
 
76576
 
76577
 
76578
 
76579
 
76580
 
76581
 
76582
 
76583
 
76584
 
76585
 
76586
 
76587
 
76588
 
76589
 
76590
 
76591
 
76592
 
76593
 
76594
 
76595
 
76596
 
76597
 
76598
 
76599
 
76600
 
76601
 
76602
 
76603
 
76604
 
76605
 
76606
 
76607
 
76608
 
76609
 
76610
 
76611
 
76612
 
76613
 
76614
 
76615
 
76616
 
76617
 
76618
 
76619
 
76620
 
76621
 
76622
 
76623
 
76624
 
76625
 
76626
 
76627
 
76628
 
76629
 
76630
 
76631
 
76632
 
76633
 
76634
 
76635
 
76636
 
76637
 
76638
 
76639
 
76640
 
76641
 
76642
 
76643
 
76644
 
76645
 
76646
 
76647
 
76648
 
76649
 
76650
 
76651
 
76652
 
76653
 
76654
 
76655
 
76656
 
76657
 
76658
 
76659
 
76660
 
76661
 
76662
 
76663
 
76664
 
76665
 
76666
 
76667
 
76668
 
76669
 
76670
 
76671
 
76672
 
76673
 
76674
 
76675
 
76676
 
76677
 
76678
 
76679
 
76680
 
76681
 
76682
 
76683
 
76684
 
76685
 
76686
 
76687
 
76688
 
76689
 
76690
 
76691
 
76692
 
76693
 
76694
 
76695
 
76696
 
76697
 
76698
 
76699
 
76700
 
76701
 
76702
 
76703
 
76704
 
76705
 
76706
 
76707
 
76708
 
76709
 
76710
 
76711
 
76712
 
76713
 
76714
 
76715
 
76716
 
76717
 
76718
 
76719
 
76720
 
76721
 
76722
 
76723
 
76724
 
76725
 
76726
 
76727
 
76728
 
76729
 
76730
 
76731
 
76732
 
76733
 
76734
 
76735
 
76736
 
76737
 
76738
 
76739
 
76740
 
76741
 
76742
 
76743
 
76744
 
76745
 
76746
 
76747
 
76748
 
76749
 
76750
 
76751
 
76752
 
76753
 
76754
 
76755
 
76756
 
76757
 
76758
 
76759
 
76760
 
76761
 
76762
 
76763
 
76764
 
76765
 
76766
 
76767
 
76768
 
76769
 
76770
 
76771
 
76772
 
76773
 
76774
 
76775
 
76776
 
76777
 
76778
 
76779
 
76780
 
76781
 
76782
 
76783
 
76784
 
76785
 
76786
 
76787
 
76788
 
76789
 
76790
 
76791
 
76792
 
76793
 
76794
 
76795
 
76796
 
76797
 
76798
 
76799
 
76800
 
76801
 
76802
 
76803
 
76804
 
76805
 
76806
 
76807
 
76808
 
76809
 
76810
 
76811
 
76812
 
76813
 
76814
 
76815
 
76816
 
76817
 
76818
 
76819
 
76820
 
76821
 
76822
 
76823
 
76824
 
76825
 
76826
 
76827
 
76828
 
76829
 
76830
 
76831
 
76832
 
76833
 
76834
 
76835
 
76836
 
76837
 
76838
 
76839
 
76840
 
76841
 
76842
 
76843
 
76844
 
76845
 
76846
 
76847
 
76848
 
76849
 
76850
 
76851
 
76852
 
76853
 
76854
 
76855
 
76856
 
76857
 
76858
 
76859
 
76860
 
76861
 
76862
 
76863
 
76864
 
76865
 
76866
 
76867
 
76868
 
76869
 
76870
 
76871
 
76872
 
76873
 
76874
 
76875
 
76876
 
76877
 
76878
 
76879
 
76880
 
76881
 
76882
 
76883
 
76884
 
76885
 
76886
 
76887
 
76888
 
76889
 
76890
 
76891
 
76892
 
76893
 
76894
 
76895
 
76896
 
76897
 
76898
 
76899
 
76900
 
76901
 
76902
 
76903
 
76904
 
76905
 
76906
 
76907
 
76908
 
76909
 
76910
 
76911
 
76912
 
76913
 
76914
 
76915
 
76916
 
76917
 
76918
 
76919
 
76920
 
76921
 
76922
 
76923
 
76924
 
76925
 
76926
 
76927
 
76928
 
76929
 
76930
 
76931
 
76932
 
76933
 
76934
 
76935
 
76936
 
76937
 
76938
 
76939
 
76940
 
76941
 
76942
 
76943
 
76944
 
76945
 
76946
 
76947
 
76948
 
76949
 
76950
 
76951
 
76952
 
76953
 
76954
 
76955
 
76956
 
76957
 
76958
 
76959
 
76960
 
76961
 
76962
 
76963
 
76964
 
76965
 
76966
 
76967
 
76968
 
76969
 
76970
 
76971
 
76972
 
76973
 
76974
 
76975
 
76976
 
76977
 
76978
 
76979
 
76980
 
76981
 
76982
 
76983
 
76984
 
76985
 
76986
 
76987
 
76988
 
76989
 
76990
 
76991
 
76992
 
76993
 
76994
 
76995
 
76996
 
76997
 
76998
 
76999
 
77000
 
77001
 
77002
 
77003
 
77004
 
77005
 
77006
 
77007
 
77008
 
77009
 
77010
 
77011
 
77012
 
77013
 
77014
 
77015
 
77016
 
77017
 
77018
 
77019
 
77020
 
77021
 
77022
 
77023
 
77024
 
77025
 
77026
 
77027
 
77028
 
77029
 
77030
 
77031
 
77032
 
77033
 
77034
 
77035
 
77036
 
77037
 
77038
 
77039
 
77040
 
77041
 
77042
 
77043
 
77044
 
77045
 
77046
 
77047
 
77048
 
77049
 
77050
 
77051
 
77052
 
77053
 
77054
 
77055
 
77056
 
77057
 
77058
 
77059
 
77060
 
77061
 
77062
 
77063
 
77064
 
77065
 
77066
 
77067
 
77068
 
77069
 
77070
 
77071
 
77072
 
77073
 
77074
 
77075
 
77076
 
77077
 
77078
 
77079
 
77080
 
77081
 
77082
 
77083
 
77084
 
77085
 
77086
 
77087
 
77088
 
77089
 
77090
 
77091
 
77092
 
77093
 
77094
 
77095
 
77096
 
77097
 
77098
 
77099
 
77100
 
77101
 
77102
 
77103
 
77104
 
77105
 
77106
 
77107
 
77108
 
77109
 
77110
 
77111
 
77112
 
77113
 
77114
 
77115
 
77116
 
77117
 
77118
 
77119
 
77120
 
77121
 
77122
 
77123
 
77124
 
77125
 
77126
 
77127
 
77128
 
77129
 
77130
 
77131
 
77132
 
77133
 
77134
 
77135
 
77136
 
77137
 
77138
 
77139
 
77140
 
77141
 
77142
 
77143
 
77144
 
77145
 
77146
 
77147
 
77148
 
77149
 
77150
 
77151
 
77152
 
77153
 
77154
 
77155
 
77156
 
77157
 
77158
 
77159
 
77160
 
77161
 
77162
 
77163
 
77164
 
77165
 
77166
 
77167
 
77168
 
77169
 
77170
 
77171
 
77172
 
77173
 
77174
 
77175
 
77176
 
77177
 
77178
 
77179
 
77180
 
77181
 
77182
 
77183
 
77184
 
77185
 
77186
 
77187
 
77188
 
77189
 
77190
 
77191
 
77192
 
77193
 
77194
 
77195
 
77196
 
77197
 
77198
 
77199
 
77200
 
77201
 
77202
 
77203
 
77204
 
77205
 
77206
 
77207
 
77208
 
77209
 
77210
 
77211
 
77212
 
77213
 
77214
 
77215
 
77216
 
77217
 
77218
 
77219
 
77220
 
77221
 
77222
 
77223
 
77224
 
77225
 
77226
 
77227
 
77228
 
77229
 
77230
 
77231
 
77232
 
77233
 
77234
 
77235
 
77236
 
77237
 
77238
 
77239
 
77240
 
77241
 
77242
 
77243
 
77244
 
77245
 
77246
 
77247
 
77248
 
77249
 
77250
 
77251
 
77252
 
77253
 
77254
 
77255
 
77256
 
77257
 
77258
 
77259
 
77260
 
77261
 
77262
 
77263
 
77264
 
77265
 
77266
 
77267
 
77268
 
77269
 
77270
 
77271
 
77272
 
77273
 
77274
 
77275
 
77276
 
77277
 
77278
 
77279
 
77280
 
77281
 
77282
 
77283
 
77284
 
77285
 
77286
 
77287
 
77288
 
77289
 
77290
 
77291
 
77292
 
77293
 
77294
 
77295
 
77296
 
77297
 
77298
 
77299
 
77300
 
77301
 
77302
 
77303
 
77304
 
77305
 
77306
 
77307
 
77308
 
77309
 
77310
 
77311
 
77312
 
77313
 
77314
 
77315
 
77316
 
77317
 
77318
 
77319
 
77320
 
77321
 
77322
 
77323
 
77324
 
77325
 
77326
 
77327
 
77328
 
77329
 
77330
 
77331
 
77332
 
77333
 
77334
 
77335
 
77336
 
77337
 
77338
 
77339
 
77340
 
77341
 
77342
 
77343
 
77344
 
77345
 
77346
 
77347
 
77348
 
77349
 
77350
 
77351
 
77352
 
77353
 
77354
 
77355
 
77356
 
77357
 
77358
 
77359
 
77360
 
77361
 
77362
 
77363
 
77364
 
77365
 
77366
 
77367
 
77368
 
77369
 
77370
 
77371
 
77372
 
77373
 
77374
 
77375
 
77376
 
77377
 
77378
 
77379
 
77380
 
77381
 
77382
 
77383
 
77384
 
77385
 
77386
 
77387
 
77388
 
77389
 
77390
 
77391
 
77392
 
77393
 
77394
 
77395
 
77396
 
77397
 
77398
 
77399
 
77400
 
77401
 
77402
 
77403
 
77404
 
77405
 
77406
 
77407
 
77408
 
77409
 
77410
 
77411
 
77412
 
77413
 
77414
 
77415
 
77416
 
77417
 
77418
 
77419
 
77420
 
77421
 
77422
 
77423
 
77424
 
77425
 
77426
 
77427
 
77428
 
77429
 
77430
 
77431
 
77432
 
77433
 
77434
 
77435
 
77436
 
77437
 
77438
 
77439
 
77440
 
77441
 
77442
 
77443
 
77444
 
77445
 
77446
 
77447
 
77448
 
77449
 
77450
 
77451
 
77452
 
77453
 
77454
 
77455
 
77456
 
77457
 
77458
 
77459
 
77460
 
77461
 
77462
 
77463
 
77464
 
77465
 
77466
 
77467
 
77468
 
77469
 
77470
 
77471
 
77472
 
77473
 
77474
 
77475
 
77476
 
77477
 
77478
 
77479
 
77480
 
77481
 
77482
 
77483
 
77484
 
77485
 
77486
 
77487
 
77488
 
77489
 
77490
 
77491
 
77492
 
77493
 
77494
 
77495
 
77496
 
77497
 
77498
 
77499
 
77500
 
77501
 
77502
 
77503
 
77504
 
77505
 
77506
 
77507
 
77508
 
77509
 
77510
 
77511
 
77512
 
77513
 
77514
 
77515
 
77516
 
77517
 
77518
 
77519
 
77520
 
77521
 
77522
 
77523
 
77524
 
77525
 
77526
 
77527
 
77528
 
77529
 
77530
 
77531
 
77532
 
77533
 
77534
 
77535
 
77536
 
77537
 
77538
 
77539
 
77540
 
77541
 
77542
 
77543
 
77544
 
77545
 
77546
 
77547
 
77548
 
77549
 
77550
 
77551
 
77552
 
77553
 
77554
 
77555
 
77556
 
77557
 
77558
 
77559
 
77560
 
77561
 
77562
 
77563
 
77564
 
77565
 
77566
 
77567
 
77568
 
77569
 
77570
 
77571
 
77572
 
77573
 
77574
 
77575
 
77576
 
77577
 
77578
 
77579
 
77580
 
77581
 
77582
 
77583
 
77584
 
77585
 
77586
 
77587
 
77588
 
77589
 
77590
 
77591
 
77592
 
77593
 
77594
 
77595
 
77596
 
77597
 
77598
 
77599
 
77600
 
77601
 
77602
 
77603
 
77604
 
77605
 
77606
 
77607
 
77608
 
77609
 
77610
 
77611
 
77612
 
77613
 
77614
 
77615
 
77616
 
77617
 
77618
 
77619
 
77620
 
77621
 
77622
 
77623
 
77624
 
77625
 
77626
 
77627
 
77628
 
77629
 
77630
 
77631
 
77632
 
77633
 
77634
 
77635
 
77636
 
77637
 
77638
 
77639
 
77640
 
77641
 
77642
 
77643
 
77644
 
77645
 
77646
 
77647
 
77648
 
77649
 
77650
 
77651
 
77652
 
77653
 
77654
 
77655
 
77656
 
77657
 
77658
 
77659
 
77660
 
77661
 
77662
 
77663
 
77664
 
77665
 
77666
 
77667
 
77668
 
77669
 
77670
 
77671
 
77672
 
77673
 
77674
 
77675
 
77676
 
77677
 
77678
 
77679
 
77680
 
77681
 
77682
 
77683
 
77684
 
77685
 
77686
 
77687
 
77688
 
77689
 
77690
 
77691
 
77692
 
77693
 
77694
 
77695
 
77696
 
77697
 
77698
 
77699
 
77700
 
77701
 
77702
 
77703
 
77704
 
77705
 
77706
 
77707
 
77708
 
77709
 
77710
 
77711
 
77712
 
77713
 
77714
 
77715
 
77716
 
77717
 
77718
 
77719
 
77720
 
77721
 
77722
 
77723
 
77724
 
77725
 
77726
 
77727
 
77728
 
77729
 
77730
 
77731
 
77732
 
77733
 
77734
 
77735
 
77736
 
77737
 
77738
 
77739
 
77740
 
77741
 
77742
 
77743
 
77744
 
77745
 
77746
 
77747
 
77748
 
77749
 
77750
 
77751
 
77752
 
77753
 
77754
 
77755
 
77756
 
77757
 
77758
 
77759
 
77760
 
77761
 
77762
 
77763
 
77764
 
77765
 
77766
 
77767
 
77768
 
77769
 
77770
 
77771
 
77772
 
77773
 
77774
 
77775
 
77776
 
77777
 
77778
 
77779
 
77780
 
77781
 
77782
 
77783
 
77784
 
77785
 
77786
 
77787
 
77788
 
77789
 
77790
 
77791
 
77792
 
77793
 
77794
 
77795
 
77796
 
77797
 
77798
 
77799
 
77800
 
77801
 
77802
 
77803
 
77804
 
77805
 
77806
 
77807
 
77808
 
77809
 
77810
 
77811
 
77812
 
77813
 
77814
 
77815
 
77816
 
77817
 
77818
 
77819
 
77820
 
77821
 
77822
 
77823
 
77824
 
77825
 
77826
 
77827
 
77828
 
77829
 
77830
 
77831
 
77832
 
77833
 
77834
 
77835
 
77836
 
77837
 
77838
 
77839
 
77840
 
77841
 
77842
 
77843
 
77844
 
77845
 
77846
 
77847
 
77848
 
77849
 
77850
 
77851
 
77852
 
77853
 
77854
 
77855
 
77856
 
77857
 
77858
 
77859
 
77860
 
77861
 
77862
 
77863
 
77864
 
77865
 
77866
 
77867
 
77868
 
77869
 
77870
 
77871
 
77872
 
77873
 
77874
 
77875
 
77876
 
77877
 
77878
 
77879
 
77880
 
77881
 
77882
 
77883
 
77884
 
77885
 
77886
 
77887
 
77888
 
77889
 
77890
 
77891
 
77892
 
77893
 
77894
 
77895
 
77896
 
77897
 
77898
 
77899
 
77900
 
77901
 
77902
 
77903
 
77904
 
77905
 
77906
 
77907
 
77908
 
77909
 
77910
 
77911
 
77912
 
77913
 
77914
 
77915
 
77916
 
77917
 
77918
 
77919
 
77920
 
77921
 
77922
 
77923
 
77924
 
77925
 
77926
 
77927
 
77928
 
77929
 
77930
 
77931
 
77932
 
77933
 
77934
 
77935
 
77936
 
77937
 
77938
 
77939
 
77940
 
77941
 
77942
 
77943
 
77944
 
77945
 
77946
 
77947
 
77948
 
77949
 
77950
 
77951
 
77952
 
77953
 
77954
 
77955
 
77956
 
77957
 
77958
 
77959
 
77960
 
77961
 
77962
 
77963
 
77964
 
77965
 
77966
 
77967
 
77968
 
77969
 
77970
 
77971
 
77972
 
77973
 
77974
 
77975
 
77976
 
77977
 
77978
 
77979
 
77980
 
77981
 
77982
 
77983
 
77984
 
77985
 
77986
 
77987
 
77988
 
77989
 
77990
 
77991
 
77992
 
77993
 
77994
 
77995
 
77996
 
77997
 
77998
 
77999
 
78000
 
78001
 
78002
 
78003
 
78004
 
78005
 
78006
 
78007
 
78008
 
78009
 
78010
 
78011
 
78012
 
78013
 
78014
 
78015
 
78016
 
78017
 
78018
 
78019
 
78020
 
78021
 
78022
 
78023
 
78024
 
78025
 
78026
 
78027
 
78028
 
78029
 
78030
 
78031
 
78032
 
78033
 
78034
 
78035
 
78036
 
78037
 
78038
 
78039
 
78040
 
78041
 
78042
 
78043
 
78044
 
78045
 
78046
 
78047
 
78048
 
78049
 
78050
 
78051
 
78052
 
78053
 
78054
 
78055
 
78056
 
78057
 
78058
 
78059
 
78060
 
78061
 
78062
 
78063
 
78064
 
78065
 
78066
 
78067
 
78068
 
78069
 
78070
 
78071
 
78072
 
78073
 
78074
 
78075
 
78076
 
78077
 
78078
 
78079
 
78080
 
78081
 
78082
 
78083
 
78084
 
78085
 
78086
 
78087
 
78088
 
78089
 
78090
 
78091
 
78092
 
78093
 
78094
 
78095
 
78096
 
78097
 
78098
 
78099
 
78100
 
78101
 
78102
 
78103
 
78104
 
78105
 
78106
 
78107
 
78108
 
78109
 
78110
 
78111
 
78112
 
78113
 
78114
 
78115
 
78116
 
78117
 
78118
 
78119
 
78120
 
78121
 
78122
 
78123
 
78124
 
78125
 
78126
 
78127
 
78128
 
78129
 
78130
 
78131
 
78132
 
78133
 
78134
 
78135
 
78136
 
78137
 
78138
 
78139
 
78140
 
78141
 
78142
 
78143
 
78144
 
78145
 
78146
 
78147
 
78148
 
78149
 
78150
 
78151
 
78152
 
78153
 
78154
 
78155
 
78156
 
78157
 
78158
 
78159
 
78160
 
78161
 
78162
 
78163
 
78164
 
78165
 
78166
 
78167
 
78168
 
78169
 
78170
 
78171
 
78172
 
78173
 
78174
 
78175
 
78176
 
78177
 
78178
 
78179
 
78180
 
78181
 
78182
 
78183
 
78184
 
78185
 
78186
 
78187
 
78188
 
78189
 
78190
 
78191
 
78192
 
78193
 
78194
 
78195
 
78196
 
78197
 
78198
 
78199
 
78200
 
78201
 
78202
 
78203
 
78204
 
78205
 
78206
 
78207
 
78208
 
78209
 
78210
 
78211
 
78212
 
78213
 
78214
 
78215
 
78216
 
78217
 
78218
 
78219
 
78220
 
78221
 
78222
 
78223
 
78224
 
78225
 
78226
 
78227
 
78228
 
78229
 
78230
 
78231
 
78232
 
78233
 
78234
 
78235
 
78236
 
78237
 
78238
 
78239
 
78240
 
78241
 
78242
 
78243
 
78244
 
78245
 
78246
 
78247
 
78248
 
78249
 
78250
 
78251
 
78252
 
78253
 
78254
 
78255
 
78256
 
78257
 
78258
 
78259
 
78260
 
78261
 
78262
 
78263
 
78264
 
78265
 
78266
 
78267
 
78268
 
78269
 
78270
 
78271
 
78272
 
78273
 
78274
 
78275
 
78276
 
78277
 
78278
 
78279
 
78280
 
78281
 
78282
 
78283
 
78284
 
78285
 
78286
 
78287
 
78288
 
78289
 
78290
 
78291
 
78292
 
78293
 
78294
 
78295
 
78296
 
78297
 
78298
 
78299
 
78300
 
78301
 
78302
 
78303
 
78304
 
78305
 
78306
 
78307
 
78308
 
78309
 
78310
 
78311
 
78312
 
78313
 
78314
 
78315
 
78316
 
78317
 
78318
 
78319
 
78320
 
78321
 
78322
 
78323
 
78324
 
78325
 
78326
 
78327
 
78328
 
78329
 
78330
 
78331
 
78332
 
78333
 
78334
 
78335
 
78336
 
78337
 
78338
 
78339
 
78340
 
78341
 
78342
 
78343
 
78344
 
78345
 
78346
 
78347
 
78348
 
78349
 
78350
 
78351
 
78352
 
78353
 
78354
 
78355
 
78356
 
78357
 
78358
 
78359
 
78360
 
78361
 
78362
 
78363
 
78364
 
78365
 
78366
 
78367
 
78368
 
78369
 
78370
 
78371
 
78372
 
78373
 
78374
 
78375
 
78376
 
78377
 
78378
 
78379
 
78380
 
78381
 
78382
 
78383
 
78384
 
78385
 
78386
 
78387
 
78388
 
78389
 
78390
 
78391
 
78392
 
78393
 
78394
 
78395
 
78396
 
78397
 
78398
 
78399
 
78400
 
78401
 
78402
 
78403
 
78404
 
78405
 
78406
 
78407
 
78408
 
78409
 
78410
 
78411
 
78412
 
78413
 
78414
 
78415
 
78416
 
78417
 
78418
 
78419
 
78420
 
78421
 
78422
 
78423
 
78424
 
78425
 
78426
 
78427
 
78428
 
78429
 
78430
 
78431
 
78432
 
78433
 
78434
 
78435
 
78436
 
78437
 
78438
 
78439
 
78440
 
78441
 
78442
 
78443
 
78444
 
78445
 
78446
 
78447
 
78448
 
78449
 
78450
 
78451
 
78452
 
78453
 
78454
 
78455
 
78456
 
78457
 
78458
 
78459
 
78460
 
78461
 
78462
 
78463
 
78464
 
78465
 
78466
 
78467
 
78468
 
78469
 
78470
 
78471
 
78472
 
78473
 
78474
 
78475
 
78476
 
78477
 
78478
 
78479
 
78480
 
78481
 
78482
 
78483
 
78484
 
78485
 
78486
 
78487
 
78488
 
78489
 
78490
 
78491
 
78492
 
78493
 
78494
 
78495
 
78496
 
78497
 
78498
 
78499
 
78500
 
78501
 
78502
 
78503
 
78504
 
78505
 
78506
 
78507
 
78508
 
78509
 
78510
 
78511
 
78512
 
78513
 
78514
 
78515
 
78516
 
78517
 
78518
 
78519
 
78520
 
78521
 
78522
 
78523
 
78524
 
78525
 
78526
 
78527
 
78528
 
78529
 
78530
 
78531
 
78532
 
78533
 
78534
 
78535
 
78536
 
78537
 
78538
 
78539
 
78540
 
78541
 
78542
 
78543
 
78544
 
78545
 
78546
 
78547
 
78548
 
78549
 
78550
 
78551
 
78552
 
78553
 
78554
 
78555
 
78556
 
78557
 
78558
 
78559
 
78560
 
78561
 
78562
 
78563
 
78564
 
78565
 
78566
 
78567
 
78568
 
78569
 
78570
 
78571
 
78572
 
78573
 
78574
 
78575
 
78576
 
78577
 
78578
 
78579
 
78580
 
78581
 
78582
 
78583
 
78584
 
78585
 
78586
 
78587
 
78588
 
78589
 
78590
 
78591
 
78592
 
78593
 
78594
 
78595
 
78596
 
78597
 
78598
 
78599
 
78600
 
78601
 
78602
 
78603
 
78604
 
78605
 
78606
 
78607
 
78608
 
78609
 
78610
 
78611
 
78612
 
78613
 
78614
 
78615
 
78616
 
78617
 
78618
 
78619
 
78620
 
78621
 
78622
 
78623
 
78624
 
78625
 
78626
 
78627
 
78628
 
78629
 
78630
 
78631
 
78632
 
78633
 
78634
 
78635
 
78636
 
78637
 
78638
 
78639
 
78640
 
78641
 
78642
 
78643
 
78644
 
78645
 
78646
 
78647
 
78648
 
78649
 
78650
 
78651
 
78652
 
78653
 
78654
 
78655
 
78656
 
78657
 
78658
 
78659
 
78660
 
78661
 
78662
 
78663
 
78664
 
78665
 
78666
 
78667
 
78668
 
78669
 
78670
 
78671
 
78672
 
78673
 
78674
 
78675
 
78676
 
78677
 
78678
 
78679
 
78680
 
78681
 
78682
 
78683
 
78684
 
78685
 
78686
 
78687
 
78688
 
78689
 
78690
 
78691
 
78692
 
78693
 
78694
 
78695
 
78696
 
78697
 
78698
 
78699
 
78700
 
78701
 
78702
 
78703
 
78704
 
78705
 
78706
 
78707
 
78708
 
78709
 
78710
 
78711
 
78712
 
78713
 
78714
 
78715
 
78716
 
78717
 
78718
 
78719
 
78720
 
78721
 
78722
 
78723
 
78724
 
78725
 
78726
 
78727
 
78728
 
78729
 
78730
 
78731
 
78732
 
78733
 
78734
 
78735
 
78736
 
78737
 
78738
 
78739
 
78740
 
78741
 
78742
 
78743
 
78744
 
78745
 
78746
 
78747
 
78748
 
78749
 
78750
 
78751
 
78752
 
78753
 
78754
 
78755
 
78756
 
78757
 
78758
 
78759
 
78760
 
78761
 
78762
 
78763
 
78764
 
78765
 
78766
 
78767
 
78768
 
78769
 
78770
 
78771
 
78772
 
78773
 
78774
 
78775
 
78776
 
78777
 
78778
 
78779
 
78780
 
78781
 
78782
 
78783
 
78784
 
78785
 
78786
 
78787
 
78788
 
78789
 
78790
 
78791
 
78792
 
78793
 
78794
 
78795
 
78796
 
78797
 
78798
 
78799
 
78800
 
78801
 
78802
 
78803
 
78804
 
78805
 
78806
 
78807
 
78808
 
78809
 
78810
 
78811
 
78812
 
78813
 
78814
 
78815
 
78816
 
78817
 
78818
 
78819
 
78820
 
78821
 
78822
 
78823
 
78824
 
78825
 
78826
 
78827
 
78828
 
78829
 
78830
 
78831
 
78832
 
78833
 
78834
 
78835
 
78836
 
78837
 
78838
 
78839
 
78840
 
78841
 
78842
 
78843
 
78844
 
78845
 
78846
 
78847
 
78848
 
78849
 
78850
 
78851
 
78852
 
78853
 
78854
 
78855
 
78856
 
78857
 
78858
 
78859
 
78860
 
78861
 
78862
 
78863
 
78864
 
78865
 
78866
 
78867
 
78868
 
78869
 
78870
 
78871
 
78872
 
78873
 
78874
 
78875
 
78876
 
78877
 
78878
 
78879
 
78880
 
78881
 
78882
 
78883
 
78884
 
78885
 
78886
 
78887
 
78888
 
78889
 
78890
 
78891
 
78892
 
78893
 
78894
 
78895
 
78896
 
78897
 
78898
 
78899
 
78900
 
78901
 
78902
 
78903
 
78904
 
78905
 
78906
 
78907
 
78908
 
78909
 
78910
 
78911
 
78912
 
78913
 
78914
 
78915
 
78916
 
78917
 
78918
 
78919
 
78920
 
78921
 
78922
 
78923
 
78924
 
78925
 
78926
 
78927
 
78928
 
78929
 
78930
 
78931
 
78932
 
78933
 
78934
 
78935
 
78936
 
78937
 
78938
 
78939
 
78940
 
78941
 
78942
 
78943
 
78944
 
78945
 
78946
 
78947
 
78948
 
78949
 
78950
 
78951
 
78952
 
78953
 
78954
 
78955
 
78956
 
78957
 
78958
 
78959
 
78960
 
78961
 
78962
 
78963
 
78964
 
78965
 
78966
 
78967
 
78968
 
78969
 
78970
 
78971
 
78972
 
78973
 
78974
 
78975
 
78976
 
78977
 
78978
 
78979
 
78980
 
78981
 
78982
 
78983
 
78984
 
78985
 
78986
 
78987
 
78988
 
78989
 
78990
 
78991
 
78992
 
78993
 
78994
 
78995
 
78996
 
78997
 
78998
 
78999
 
79000
 
79001
 
79002
 
79003
 
79004
 
79005
 
79006
 
79007
 
79008
 
79009
 
79010
 
79011
 
79012
 
79013
 
79014
 
79015
 
79016
 
79017
 
79018
 
79019
 
79020
 
79021
 
79022
 
79023
 
79024
 
79025
 
79026
 
79027
 
79028
 
79029
 
79030
 
79031
 
79032
 
79033
 
79034
 
79035
 
79036
 
79037
 
79038
 
79039
 
79040
 
79041
 
79042
 
79043
 
79044
 
79045
 
79046
 
79047
 
79048
 
79049
 
79050
 
79051
 
79052
 
79053
 
79054
 
79055
 
79056
 
79057
 
79058
 
79059
 
79060
 
79061
 
79062
 
79063
 
79064
 
79065
 
79066
 
79067
 
79068
 
79069
 
79070
 
79071
 
79072
 
79073
 
79074
 
79075
 
79076
 
79077
 
79078
 
79079
 
79080
 
79081
 
79082
 
79083
 
79084
 
79085
 
79086
 
79087
 
79088
 
79089
 
79090
 
79091
 
79092
 
79093
 
79094
 
79095
 
79096
 
79097
 
79098
 
79099
 
79100
 
79101
 
79102
 
79103
 
79104
 
79105
 
79106
 
79107
 
79108
 
79109
 
79110
 
79111
 
79112
 
79113
 
79114
 
79115
 
79116
 
79117
 
79118
 
79119
 
79120
 
79121
 
79122
 
79123
 
79124
 
79125
 
79126
 
79127
 
79128
 
79129
 
79130
 
79131
 
79132
 
79133
 
79134
 
79135
 
79136
 
79137
 
79138
 
79139
 
79140
 
79141
 
79142
 
79143
 
79144
 
79145
 
79146
 
79147
 
79148
 
79149
 
79150
 
79151
 
79152
 
79153
 
79154
 
79155
 
79156
 
79157
 
79158
 
79159
 
79160
 
79161
 
79162
 
79163
 
79164
 
79165
 
79166
 
79167
 
79168
 
79169
 
79170
 
79171
 
79172
 
79173
 
79174
 
79175
 
79176
 
79177
 
79178
 
79179
 
79180
 
79181
 
79182
 
79183
 
79184
 
79185
 
79186
 
79187
 
79188
 
79189
 
79190
 
79191
 
79192
 
79193
 
79194
 
79195
 
79196
 
79197
 
79198
 
79199
 
79200
 
79201
 
79202
 
79203
 
79204
 
79205
 
79206
 
79207
 
79208
 
79209
 
79210
 
79211
 
79212
 
79213
 
79214
 
79215
 
79216
 
79217
 
79218
 
79219
 
79220
 
79221
 
79222
 
79223
 
79224
 
79225
 
79226
 
79227
 
79228
 
79229
 
79230
 
79231
 
79232
 
79233
 
79234
 
79235
 
79236
 
79237
 
79238
 
79239
 
79240
 
79241
 
79242
 
79243
 
79244
 
79245
 
79246
 
79247
 
79248
 
79249
 
79250
 
79251
 
79252
 
79253
 
79254
 
79255
 
79256
 
79257
 
79258
 
79259
 
79260
 
79261
 
79262
 
79263
 
79264
 
79265
 
79266
 
79267
 
79268
 
79269
 
79270
 
79271
 
79272
 
79273
 
79274
 
79275
 
79276
 
79277
 
79278
 
79279
 
79280
 
79281
 
79282
 
79283
 
79284
 
79285
 
79286
 
79287
 
79288
 
79289
 
79290
 
79291
 
79292
 
79293
 
79294
 
79295
 
79296
 
79297
 
79298
 
79299
 
79300
 
79301
 
79302
 
79303
 
79304
 
79305
 
79306
 
79307
 
79308
 
79309
 
79310
 
79311
 
79312
 
79313
 
79314
 
79315
 
79316
 
79317
 
79318
 
79319
 
79320
 
79321
 
79322
 
79323
 
79324
 
79325
 
79326
 
79327
 
79328
 
79329
 
79330
 
79331
 
79332
 
79333
 
79334
 
79335
 
79336
 
79337
 
79338
 
79339
 
79340
 
79341
 
79342
 
79343
 
79344
 
79345
 
79346
 
79347
 
79348
 
79349
 
79350
 
79351
 
79352
 
79353
 
79354
 
79355
 
79356
 
79357
 
79358
 
79359
 
79360
 
79361
 
79362
 
79363
 
79364
 
79365
 
79366
 
79367
 
79368
 
79369
 
79370
 
79371
 
79372
 
79373
 
79374
 
79375
 
79376
 
79377
 
79378
 
79379
 
79380
 
79381
 
79382
 
79383
 
79384
 
79385
 
79386
 
79387
 
79388
 
79389
 
79390
 
79391
 
79392
 
79393
 
79394
 
79395
 
79396
 
79397
 
79398
 
79399
 
79400
 
79401
 
79402
 
79403
 
79404
 
79405
 
79406
 
79407
 
79408
 
79409
 
79410
 
79411
 
79412
 
79413
 
79414
 
79415
 
79416
 
79417
 
79418
 
79419
 
79420
 
79421
 
79422
 
79423
 
79424
 
79425
 
79426
 
79427
 
79428
 
79429
 
79430
 
79431
 
79432
 
79433
 
79434
 
79435
 
79436
 
79437
 
79438
 
79439
 
79440
 
79441
 
79442
 
79443
 
79444
 
79445
 
79446
 
79447
 
79448
 
79449
 
79450
 
79451
 
79452
 
79453
 
79454
 
79455
 
79456
 
79457
 
79458
 
79459
 
79460
 
79461
 
79462
 
79463
 
79464
 
79465
 
79466
 
79467
 
79468
 
79469
 
79470
 
79471
 
79472
 
79473
 
79474
 
79475
 
79476
 
79477
 
79478
 
79479
 
79480
 
79481
 
79482
 
79483
 
79484
 
79485
 
79486
 
79487
 
79488
 
79489
 
79490
 
79491
 
79492
 
79493
 
79494
 
79495
 
79496
 
79497
 
79498
 
79499
 
79500
 
79501
 
79502
 
79503
 
79504
 
79505
 
79506
 
79507
 
79508
 
79509
 
79510
 
79511
 
79512
 
79513
 
79514
 
79515
 
79516
 
79517
 
79518
 
79519
 
79520
 
79521
 
79522
 
79523
 
79524
 
79525
 
79526
 
79527
 
79528
 
79529
 
79530
 
79531
 
79532
 
79533
 
79534
 
79535
 
79536
 
79537
 
79538
 
79539
 
79540
 
79541
 
79542
 
79543
 
79544
 
79545
 
79546
 
79547
 
79548
 
79549
 
79550
 
79551
 
79552
 
79553
 
79554
 
79555
 
79556
 
79557
 
79558
 
79559
 
79560
 
79561
 
79562
 
79563
 
79564
 
79565
 
79566
 
79567
 
79568
 
79569
 
79570
 
79571
 
79572
 
79573
 
79574
 
79575
 
79576
 
79577
 
79578
 
79579
 
79580
 
79581
 
79582
 
79583
 
79584
 
79585
 
79586
 
79587
 
79588
 
79589
 
79590
 
79591
 
79592
 
79593
 
79594
 
79595
 
79596
 
79597
 
79598
 
79599
 
79600
 
79601
 
79602
 
79603
 
79604
 
79605
 
79606
 
79607
 
79608
 
79609
 
79610
 
79611
 
79612
 
79613
 
79614
 
79615
 
79616
 
79617
 
79618
 
79619
 
79620
 
79621
 
79622
 
79623
 
79624
 
79625
 
79626
 
79627
 
79628
 
79629
 
79630
 
79631
 
79632
 
79633
 
79634
 
79635
 
79636
 
79637
 
79638
 
79639
 
79640
 
79641
 
79642
 
79643
 
79644
 
79645
 
79646
 
79647
 
79648
 
79649
 
79650
 
79651
 
79652
 
79653
 
79654
 
79655
 
79656
 
79657
 
79658
 
79659
 
79660
 
79661
 
79662
 
79663
 
79664
 
79665
 
79666
 
79667
 
79668
 
79669
 
79670
 
79671
 
79672
 
79673
 
79674
 
79675
 
79676
 
79677
 
79678
 
79679
 
79680
 
79681
 
79682
 
79683
 
79684
 
79685
 
79686
 
79687
 
79688
 
79689
 
79690
 
79691
 
79692
 
79693
 
79694
 
79695
 
79696
 
79697
 
79698
 
79699
 
79700
 
79701
 
79702
 
79703
 
79704
 
79705
 
79706
 
79707
 
79708
 
79709
 
79710
 
79711
 
79712
 
79713
 
79714
 
79715
 
79716
 
79717
 
79718
 
79719
 
79720
 
79721
 
79722
 
79723
 
79724
 
79725
 
79726
 
79727
 
79728
 
79729
 
79730
 
79731
 
79732
 
79733
 
79734
 
79735
 
79736
 
79737
 
79738
 
79739
 
79740
 
79741
 
79742
 
79743
 
79744
 
79745
 
79746
 
79747
 
79748
 
79749
 
79750
 
79751
 
79752
 
79753
 
79754
 
79755
 
79756
 
79757
 
79758
 
79759
 
79760
 
79761
 
79762
 
79763
 
79764
 
79765
 
79766
 
79767
 
79768
 
79769
 
79770
 
79771
 
79772
 
79773
 
79774
 
79775
 
79776
 
79777
 
79778
 
79779
 
79780
 
79781
 
79782
 
79783
 
79784
 
79785
 
79786
 
79787
 
79788
 
79789
 
79790
 
79791
 
79792
 
79793
 
79794
 
79795
 
79796
 
79797
 
79798
 
79799
 
79800
 
79801
 
79802
 
79803
 
79804
 
79805
 
79806
 
79807
 
79808
 
79809
 
79810
 
79811
 
79812
 
79813
 
79814
 
79815
 
79816
 
79817
 
79818
 
79819
 
79820
 
79821
 
79822
 
79823
 
79824
 
79825
 
79826
 
79827
 
79828
 
79829
 
79830
 
79831
 
79832
 
79833
 
79834
 
79835
 
79836
 
79837
 
79838
 
79839
 
79840
 
79841
 
79842
 
79843
 
79844
 
79845
 
79846
 
79847
 
79848
 
79849
 
79850
 
79851
 
79852
 
79853
 
79854
 
79855
 
79856
 
79857
 
79858
 
79859
 
79860
 
79861
 
79862
 
79863
 
79864
 
79865
 
79866
 
79867
 
79868
 
79869
 
79870
 
79871
 
79872
 
79873
 
79874
 
79875
 
79876
 
79877
 
79878
 
79879
 
79880
 
79881
 
79882
 
79883
 
79884
 
79885
 
79886
 
79887
 
79888
 
79889
 
79890
 
79891
 
79892
 
79893
 
79894
 
79895
 
79896
 
79897
 
79898
 
79899
 
79900
 
79901
 
79902
 
79903
 
79904
 
79905
 
79906
 
79907
 
79908
 
79909
 
79910
 
79911
 
79912
 
79913
 
79914
 
79915
 
79916
 
79917
 
79918
 
79919
 
79920
 
79921
 
79922
 
79923
 
79924
 
79925
 
79926
 
79927
 
79928
 
79929
 
79930
 
79931
 
79932
 
79933
 
79934
 
79935
 
79936
 
79937
 
79938
 
79939
 
79940
 
79941
 
79942
 
79943
 
79944
 
79945
 
79946
 
79947
 
79948
 
79949
 
79950
 
79951
 
79952
 
79953
 
79954
 
79955
 
79956
 
79957
 
79958
 
79959
 
79960
 
79961
 
79962
 
79963
 
79964
 
79965
 
79966
 
79967
 
79968
 
79969
 
79970
 
79971
 
79972
 
79973
 
79974
 
79975
 
79976
 
79977
 
79978
 
79979
 
79980
 
79981
 
79982
 
79983
 
79984
 
79985
 
79986
 
79987
 
79988
 
79989
 
79990
 
79991
 
79992
 
79993
 
79994
 
79995
 
79996
 
79997
 
79998
 
79999
 
80000
 
80001
 
80002
 
80003
 
80004
 
80005
 
80006
 
80007
 
80008
 
80009
 
80010
 
80011
 
80012
 
80013
 
80014
 
80015
 
80016
 
80017
 
80018
 
80019
 
80020
 
80021
 
80022
 
80023
 
80024
 
80025
 
80026
 
80027
 
80028
 
80029
 
80030
 
80031
 
80032
 
80033
 
80034
 
80035
 
80036
 
80037
 
80038
 
80039
 
80040
 
80041
 
80042
 
80043
 
80044
 
80045
 
80046
 
80047
 
80048
 
80049
 
80050
 
80051
 
80052
 
80053
 
80054
 
80055
 
80056
 
80057
 
80058
 
80059
 
80060
 
80061
 
80062
 
80063
 
80064
 
80065
 
80066
 
80067
 
80068
 
80069
 
80070
 
80071
 
80072
 
80073
 
80074
 
80075
 
80076
 
80077
 
80078
 
80079
 
80080
 
80081
 
80082
 
80083
 
80084
 
80085
 
80086
 
80087
 
80088
 
80089
 
80090
 
80091
 
80092
 
80093
 
80094
 
80095
 
80096
 
80097
 
80098
 
80099
 
80100
 
80101
 
80102
 
80103
 
80104
 
80105
 
80106
 
80107
 
80108
 
80109
 
80110
 
80111
 
80112
 
80113
 
80114
 
80115
 
80116
 
80117
 
80118
 
80119
 
80120
 
80121
 
80122
 
80123
 
80124
 
80125
 
80126
 
80127
 
80128
 
80129
 
80130
 
80131
 
80132
 
80133
 
80134
 
80135
 
80136
 
80137
 
80138
 
80139
 
80140
 
80141
 
80142
 
80143
 
80144
 
80145
 
80146
 
80147
 
80148
 
80149
 
80150
 
80151
 
80152
 
80153
 
80154
 
80155
 
80156
 
80157
 
80158
 
80159
 
80160
 
80161
 
80162
 
80163
 
80164
 
80165
 
80166
 
80167
 
80168
 
80169
 
80170
 
80171
 
80172
 
80173
 
80174
 
80175
 
80176
 
80177
 
80178
 
80179
 
80180
 
80181
 
80182
 
80183
 
80184
 
80185
 
80186
 
80187
 
80188
 
80189
 
80190
 
80191
 
80192
 
80193
 
80194
 
80195
 
80196
 
80197
 
80198
 
80199
 
80200
 
80201
 
80202
 
80203
 
80204
 
80205
 
80206
 
80207
 
80208
 
80209
 
80210
 
80211
 
80212
 
80213
 
80214
 
80215
 
80216
 
80217
 
80218
 
80219
 
80220
 
80221
 
80222
 
80223
 
80224
 
80225
 
80226
 
80227
 
80228
 
80229
 
80230
 
80231
 
80232
 
80233
 
80234
 
80235
 
80236
 
80237
 
80238
 
80239
 
80240
 
80241
 
80242
 
80243
 
80244
 
80245
 
80246
 
80247
 
80248
 
80249
 
80250
 
80251
 
80252
 
80253
 
80254
 
80255
 
80256
 
80257
 
80258
 
80259
 
80260
 
80261
 
80262
 
80263
 
80264
 
80265
 
80266
 
80267
 
80268
 
80269
 
80270
 
80271
 
80272
 
80273
 
80274
 
80275
 
80276
 
80277
 
80278
 
80279
 
80280
 
80281
 
80282
 
80283
 
80284
 
80285
 
80286
 
80287
 
80288
 
80289
 
80290
 
80291
 
80292
 
80293
 
80294
 
80295
 
80296
 
80297
 
80298
 
80299
 
80300
 
80301
 
80302
 
80303
 
80304
 
80305
 
80306
 
80307
 
80308
 
80309
 
80310
 
80311
 
80312
 
80313
 
80314
 
80315
 
80316
 
80317
 
80318
 
80319
 
80320
 
80321
 
80322
 
80323
 
80324
 
80325
 
80326
 
80327
 
80328
 
80329
 
80330
 
80331
 
80332
 
80333
 
80334
 
80335
 
80336
 
80337
 
80338
 
80339
 
80340
 
80341
 
80342
 
80343
 
80344
 
80345
 
80346
 
80347
 
80348
 
80349
 
80350
 
80351
 
80352
 
80353
 
80354
 
80355
 
80356
 
80357
 
80358
 
80359
 
80360
 
80361
 
80362
 
80363
 
80364
 
80365
 
80366
 
80367
 
80368
 
80369
 
80370
 
80371
 
80372
 
80373
 
80374
 
80375
 
80376
 
80377
 
80378
 
80379
 
80380
 
80381
 
80382
 
80383
 
80384
 
80385
 
80386
 
80387
 
80388
 
80389
 
80390
 
80391
 
80392
 
80393
 
80394
 
80395
 
80396
 
80397
 
80398
 
80399
 
80400
 
80401
 
80402
 
80403
 
80404
 
80405
 
80406
 
80407
 
80408
 
80409
 
80410
 
80411
 
80412
 
80413
 
80414
 
80415
 
80416
 
80417
 
80418
 
80419
 
80420
 
80421
 
80422
 
80423
 
80424
 
80425
 
80426
 
80427
 
80428
 
80429
 
80430
 
80431
 
80432
 
80433
 
80434
 
80435
 
80436
 
80437
 
80438
 
80439
 
80440
 
80441
 
80442
 
80443
 
80444
 
80445
 
80446
 
80447
 
80448
 
80449
 
80450
 
80451
 
80452
 
80453
 
80454
 
80455
 
80456
 
80457
 
80458
 
80459
 
80460
 
80461
 
80462
 
80463
 
80464
 
80465
 
80466
 
80467
 
80468
 
80469
 
80470
 
80471
 
80472
 
80473
 
80474
 
80475
 
80476
 
80477
 
80478
 
80479
 
80480
 
80481
 
80482
 
80483
 
80484
 
80485
 
80486
 
80487
 
80488
 
80489
 
80490
 
80491
 
80492
 
80493
 
80494
 
80495
 
80496
 
80497
 
80498
 
80499
 
80500
 
80501
 
80502
 
80503
 
80504
 
80505
 
80506
 
80507
 
80508
 
80509
 
80510
 
80511
 
80512
 
80513
 
80514
 
80515
 
80516
 
80517
 
80518
 
80519
 
80520
 
80521
 
80522
 
80523
 
80524
 
80525
 
80526
 
80527
 
80528
 
80529
 
80530
 
80531
 
80532
 
80533
 
80534
 
80535
 
80536
 
80537
 
80538
 
80539
 
80540
 
80541
 
80542
 
80543
 
80544
 
80545
 
80546
 
80547
 
80548
 
80549
 
80550
 
80551
 
80552
 
80553
 
80554
 
80555
 
80556
 
80557
 
80558
 
80559
 
80560
 
80561
 
80562
 
80563
 
80564
 
80565
 
80566
 
80567
 
80568
 
80569
 
80570
 
80571
 
80572
 
80573
 
80574
 
80575
 
80576
 
80577
 
80578
 
80579
 
80580
 
80581
 
80582
 
80583
 
80584
 
80585
 
80586
 
80587
 
80588
 
80589
 
80590
 
80591
 
80592
 
80593
 
80594
 
80595
 
80596
 
80597
 
80598
 
80599
 
80600
 
80601
 
80602
 
80603
 
80604
 
80605
 
80606
 
80607
 
80608
 
80609
 
80610
 
80611
 
80612
 
80613
 
80614
 
80615
 
80616
 
80617
 
80618
 
80619
 
80620
 
80621
 
80622
 
80623
 
80624
 
80625
 
80626
 
80627
 
80628
 
80629
 
80630
 
80631
 
80632
 
80633
 
80634
 
80635
 
80636
 
80637
 
80638
 
80639
 
80640
 
80641
 
80642
 
80643
 
80644
 
80645
 
80646
 
80647
 
80648
 
80649
 
80650
 
80651
 
80652
 
80653
 
80654
 
80655
 
80656
 
80657
 
80658
 
80659
 
80660
 
80661
 
80662
 
80663
 
80664
 
80665
 
80666
 
80667
 
80668
 
80669
 
80670
 
80671
 
80672
 
80673
 
80674
 
80675
 
80676
 
80677
 
80678
 
80679
 
80680
 
80681
 
80682
 
80683
 
80684
 
80685
 
80686
 
80687
 
80688
 
80689
 
80690
 
80691
 
80692
 
80693
 
80694
 
80695
 
80696
 
80697
 
80698
 
80699
 
80700
 
80701
 
80702
 
80703
 
80704
 
80705
 
80706
 
80707
 
80708
 
80709
 
80710
 
80711
 
80712
 
80713
 
80714
 
80715
 
80716
 
80717
 
80718
 
80719
 
80720
 
80721
 
80722
 
80723
 
80724
 
80725
 
80726
 
80727
 
80728
 
80729
 
80730
 
80731
 
80732
 
80733
 
80734
 
80735
 
80736
 
80737
 
80738
 
80739
 
80740
 
80741
 
80742
 
80743
 
80744
 
80745
 
80746
 
80747
 
80748
 
80749
 
80750
 
80751
 
80752
 
80753
 
80754
 
80755
 
80756
 
80757
 
80758
 
80759
 
80760
 
80761
 
80762
 
80763
 
80764
 
80765
 
80766
 
80767
 
80768
 
80769
 
80770
 
80771
 
80772
 
80773
 
80774
 
80775
 
80776
 
80777
 
80778
 
80779
 
80780
 
80781
 
80782
 
80783
 
80784
 
80785
 
80786
 
80787
 
80788
 
80789
 
80790
 
80791
 
80792
 
80793
 
80794
 
80795
 
80796
 
80797
 
80798
 
80799
 
80800
 
80801
 
80802
 
80803
 
80804
 
80805
 
80806
 
80807
 
80808
 
80809
 
80810
 
80811
 
80812
 
80813
 
80814
 
80815
 
80816
 
80817
 
80818
 
80819
 
80820
 
80821
 
80822
 
80823
 
80824
 
80825
 
80826
 
80827
 
80828
 
80829
 
80830
 
80831
 
80832
 
80833
 
80834
 
80835
 
80836
 
80837
 
80838
 
80839
 
80840
 
80841
 
80842
 
80843
 
80844
 
80845
 
80846
 
80847
 
80848
 
80849
 
80850
 
80851
 
80852
 
80853
 
80854
 
80855
 
80856
 
80857
 
80858
 
80859
 
80860
 
80861
 
80862
 
80863
 
80864
 
80865
 
80866
 
80867
 
80868
 
80869
 
80870
 
80871
 
80872
 
80873
 
80874
 
80875
 
80876
 
80877
 
80878
 
80879
 
80880
 
80881
 
80882
 
80883
 
80884
 
80885
 
80886
 
80887
 
80888
 
80889
 
80890
 
80891
 
80892
 
80893
 
80894
 
80895
 
80896
 
80897
 
80898
 
80899
 
80900
 
80901
 
80902
 
80903
 
80904
 
80905
 
80906
 
80907
 
80908
 
80909
 
80910
 
80911
 
80912
 
80913
 
80914
 
80915
 
80916
 
80917
 
80918
 
80919
 
80920
 
80921
 
80922
 
80923
 
80924
 
80925
 
80926
 
80927
 
80928
 
80929
 
80930
 
80931
 
80932
 
80933
 
80934
 
80935
 
80936
 
80937
 
80938
 
80939
 
80940
 
80941
 
80942
 
80943
 
80944
 
80945
 
80946
 
80947
 
80948
 
80949
 
80950
 
80951
 
80952
 
80953
 
80954
 
80955
 
80956
 
80957
 
80958
 
80959
 
80960
 
80961
 
80962
 
80963
 
80964
 
80965
 
80966
 
80967
 
80968
 
80969
 
80970
 
80971
 
80972
 
80973
 
80974
 
80975
 
80976
 
80977
 
80978
 
80979
 
80980
 
80981
 
80982
 
80983
 
80984
 
80985
 
80986
 
80987
 
80988
 
80989
 
80990
 
80991
 
80992
 
80993
 
80994
 
80995
 
80996
 
80997
 
80998
 
80999
 
81000
 
81001
 
81002
 
81003
 
81004
 
81005
 
81006
 
81007
 
81008
 
81009
 
81010
 
81011
 
81012
 
81013
 
81014
 
81015
 
81016
 
81017
 
81018
 
81019
 
81020
 
81021
 
81022
 
81023
 
81024
 
81025
 
81026
 
81027
 
81028
 
81029
 
81030
 
81031
 
81032
 
81033
 
81034
 
81035
 
81036
 
81037
 
81038
 
81039
 
81040
 
81041
 
81042
 
81043
 
81044
 
81045
 
81046
 
81047
 
81048
 
81049
 
81050
 
81051
 
81052
 
81053
 
81054
 
81055
 
81056
 
81057
 
81058
 
81059
 
81060
 
81061
 
81062
 
81063
 
81064
 
81065
 
81066
 
81067
 
81068
 
81069
 
81070
 
81071
 
81072
 
81073
 
81074
 
81075
 
81076
 
81077
 
81078
 
81079
 
81080
 
81081
 
81082
 
81083
 
81084
 
81085
 
81086
 
81087
 
81088
 
81089
 
81090
 
81091
 
81092
 
81093
 
81094
 
81095
 
81096
 
81097
 
81098
 
81099
 
81100
 
81101
 
81102
 
81103
 
81104
 
81105
 
81106
 
81107
 
81108
 
81109
 
81110
 
81111
 
81112
 
81113
 
81114
 
81115
 
81116
 
81117
 
81118
 
81119
 
81120
 
81121
 
81122
 
81123
 
81124
 
81125
 
81126
 
81127
 
81128
 
81129
 
81130
 
81131
 
81132
 
81133
 
81134
 
81135
 
81136
 
81137
 
81138
 
81139
 
81140
 
81141
 
81142
 
81143
 
81144
 
81145
 
81146
 
81147
 
81148
 
81149
 
81150
 
81151
 
81152
 
81153
 
81154
 
81155
 
81156
 
81157
 
81158
 
81159
 
81160
 
81161
 
81162
 
81163
 
81164
 
81165
 
81166
 
81167
 
81168
 
81169
 
81170
 
81171
 
81172
 
81173
 
81174
 
81175
 
81176
 
81177
 
81178
 
81179
 
81180
 
81181
 
81182
 
81183
 
81184
 
81185
 
81186
 
81187
 
81188
 
81189
 
81190
 
81191
 
81192
 
81193
 
81194
 
81195
 
81196
 
81197
 
81198
 
81199
 
81200
 
81201
 
81202
 
81203
 
81204
 
81205
 
81206
 
81207
 
81208
 
81209
 
81210
 
81211
 
81212
 
81213
 
81214
 
81215
 
81216
 
81217
 
81218
 
81219
 
81220
 
81221
 
81222
 
81223
 
81224
 
81225
 
81226
 
81227
 
81228
 
81229
 
81230
 
81231
 
81232
 
81233
 
81234
 
81235
 
81236
 
81237
 
81238
 
81239
 
81240
 
81241
 
81242
 
81243
 
81244
 
81245
 
81246
 
81247
 
81248
 
81249
 
81250
 
81251
 
81252
 
81253
 
81254
 
81255
 
81256
 
81257
 
81258
 
81259
 
81260
 
81261
 
81262
 
81263
 
81264
 
81265
 
81266
 
81267
 
81268
 
81269
 
81270
 
81271
 
81272
 
81273
 
81274
 
81275
 
81276
 
81277
 
81278
 
81279
 
81280
 
81281
 
81282
 
81283
 
81284
 
81285
 
81286
 
81287
 
81288
 
81289
 
81290
 
81291
 
81292
 
81293
 
81294
 
81295
 
81296
 
81297
 
81298
 
81299
 
81300
 
81301
 
81302
 
81303
 
81304
 
81305
 
81306
 
81307
 
81308
 
81309
 
81310
 
81311
 
81312
 
81313
 
81314
 
81315
 
81316
 
81317
 
81318
 
81319
 
81320
 
81321
 
81322
 
81323
 
81324
 
81325
 
81326
 
81327
 
81328
 
81329
 
81330
 
81331
 
81332
 
81333
 
81334
 
81335
 
81336
 
81337
 
81338
 
81339
 
81340
 
81341
 
81342
 
81343
 
81344
 
81345
 
81346
 
81347
 
81348
 
81349
 
81350
 
81351
 
81352
 
81353
 
81354
 
81355
 
81356
 
81357
 
81358
 
81359
 
81360
 
81361
 
81362
 
81363
 
81364
 
81365
 
81366
 
81367
 
81368
 
81369
 
81370
 
81371
 
81372
 
81373
 
81374
 
81375
 
81376
 
81377
 
81378
 
81379
 
81380
 
81381
 
81382
 
81383
 
81384
 
81385
 
81386
 
81387
 
81388
 
81389
 
81390
 
81391
 
81392
 
81393
 
81394
 
81395
 
81396
 
81397
 
81398
 
81399
 
81400
 
81401
 
81402
 
81403
 
81404
 
81405
 
81406
 
81407
 
81408
 
81409
 
81410
 
81411
 
81412
 
81413
 
81414
 
81415
 
81416
 
81417
 
81418
 
81419
 
81420
 
81421
 
81422
 
81423
 
81424
 
81425
 
81426
 
81427
 
81428
 
81429
 
81430
 
81431
 
81432
 
81433
 
81434
 
81435
 
81436
 
81437
 
81438
 
81439
 
81440
 
81441
 
81442
 
81443
 
81444
 
81445
 
81446
 
81447
 
81448
 
81449
 
81450
 
81451
 
81452
 
81453
 
81454
 
81455
 
81456
 
81457
 
81458
 
81459
 
81460
 
81461
 
81462
 
81463
 
81464
 
81465
 
81466
 
81467
 
81468
 
81469
 
81470
 
81471
 
81472
 
81473
 
81474
 
81475
 
81476
 
81477
 
81478
 
81479
 
81480
 
81481
 
81482
 
81483
 
81484
 
81485
 
81486
 
81487
 
81488
 
81489
 
81490
 
81491
 
81492
 
81493
 
81494
 
81495
 
81496
 
81497
 
81498
 
81499
 
81500
 
81501
 
81502
 
81503
 
81504
 
81505
 
81506
 
81507
 
81508
 
81509
 
81510
 
81511
 
81512
 
81513
 
81514
 
81515
 
81516
 
81517
 
81518
 
81519
 
81520
 
81521
 
81522
 
81523
 
81524
 
81525
 
81526
 
81527
 
81528
 
81529
 
81530
 
81531
 
81532
 
81533
 
81534
 
81535
 
81536
 
81537
 
81538
 
81539
 
81540
 
81541
 
81542
 
81543
 
81544
 
81545
 
81546
 
81547
 
81548
 
81549
 
81550
 
81551
 
81552
 
81553
 
81554
 
81555
 
81556
 
81557
 
81558
 
81559
 
81560
 
81561
 
81562
 
81563
 
81564
 
81565
 
81566
 
81567
 
81568
 
81569
 
81570
 
81571
 
81572
 
81573
 
81574
 
81575
 
81576
 
81577
 
81578
 
81579
 
81580
 
81581
 
81582
 
81583
 
81584
 
81585
 
81586
 
81587
 
81588
 
81589
 
81590
 
81591
 
81592
 
81593
 
81594
 
81595
 
81596
 
81597
 
81598
 
81599
 
81600
 
81601
 
81602
 
81603
 
81604
 
81605
 
81606
 
81607
 
81608
 
81609
 
81610
 
81611
 
81612
 
81613
 
81614
 
81615
 
81616
 
81617
 
81618
 
81619
 
81620
 
81621
 
81622
 
81623
 
81624
 
81625
 
81626
 
81627
 
81628
 
81629
 
81630
 
81631
 
81632
 
81633
 
81634
 
81635
 
81636
 
81637
 
81638
 
81639
 
81640
 
81641
 
81642
 
81643
 
81644
 
81645
 
81646
 
81647
 
81648
 
81649
 
81650
 
81651
 
81652
 
81653
 
81654
 
81655
 
81656
 
81657
 
81658
 
81659
 
81660
 
81661
 
81662
 
81663
 
81664
 
81665
 
81666
 
81667
 
81668
 
81669
 
81670
 
81671
 
81672
 
81673
 
81674
 
81675
 
81676
 
81677
 
81678
 
81679
 
81680
 
81681
 
81682
 
81683
 
81684
 
81685
 
81686
 
81687
 
81688
 
81689
 
81690
 
81691
 
81692
 
81693
 
81694
 
81695
 
81696
 
81697
 
81698
 
81699
 
81700
 
81701
 
81702
 
81703
 
81704
 
81705
 
81706
 
81707
 
81708
 
81709
 
81710
 
81711
 
81712
 
81713
 
81714
 
81715
 
81716
 
81717
 
81718
 
81719
 
81720
 
81721
 
81722
 
81723
 
81724
 
81725
 
81726
 
81727
 
81728
 
81729
 
81730
 
81731
 
81732
 
81733
 
81734
 
81735
 
81736
 
81737
 
81738
 
81739
 
81740
 
81741
 
81742
 
81743
 
81744
 
81745
 
81746
 
81747
 
81748
 
81749
 
81750
 
81751
 
81752
 
81753
 
81754
 
81755
 
81756
 
81757
 
81758
 
81759
 
81760
 
81761
 
81762
 
81763
 
81764
 
81765
 
81766
 
81767
 
81768
 
81769
 
81770
 
81771
 
81772
 
81773
 
81774
 
81775
 
81776
 
81777
 
81778
 
81779
 
81780
 
81781
 
81782
 
81783
 
81784
 
81785
 
81786
 
81787
 
81788
 
81789
 
81790
 
81791
 
81792
 
81793
 
81794
 
81795
 
81796
 
81797
 
81798
 
81799
 
81800
 
81801
 
81802
 
81803
 
81804
 
81805
 
81806
 
81807
 
81808
 
81809
 
81810
 
81811
 
81812
 
81813
 
81814
 
81815
 
81816
 
81817
 
81818
 
81819
 
81820
 
81821
 
81822
 
81823
 
81824
 
81825
 
81826
 
81827
 
81828
 
81829
 
81830
 
81831
 
81832
 
81833
 
81834
 
81835
 
81836
 
81837
 
81838
 
81839
 
81840
 
81841
 
81842
 
81843
 
81844
 
81845
 
81846
 
81847
 
81848
 
81849
 
81850
 
81851
 
81852
 
81853
 
81854
 
81855
 
81856
 
81857
 
81858
 
81859
 
81860
 
81861
 
81862
 
81863
 
81864
 
81865
 
81866
 
81867
 
81868
 
81869
 
81870
 
81871
 
81872
 
81873
 
81874
 
81875
 
81876
 
81877
 
81878
 
81879
 
81880
 
81881
 
81882
 
81883
 
81884
 
81885
 
81886
 
81887
 
81888
 
81889
 
81890
 
81891
 
81892
 
81893
 
81894
 
81895
 
81896
 
81897
 
81898
 
81899
 
81900
 
81901
 
81902
 
81903
 
81904
 
81905
 
81906
 
81907
 
81908
 
81909
 
81910
 
81911
 
81912
 
81913
 
81914
 
81915
 
81916
 
81917
 
81918
 
81919
 
81920
 
81921
 
81922
 
81923
 
81924
 
81925
 
81926
 
81927
 
81928
 
81929
 
81930
 
81931
 
81932
 
81933
 
81934
 
81935
 
81936
 
81937
 
81938
 
81939
 
81940
 
81941
 
81942
 
81943
 
81944
 
81945
 
81946
 
81947
 
81948
 
81949
 
81950
 
81951
 
81952
 
81953
 
81954
 
81955
 
81956
 
81957
 
81958
 
81959
 
81960
 
81961
 
81962
 
81963
 
81964
 
81965
 
81966
 
81967
 
81968
 
81969
 
81970
 
81971
 
81972
 
81973
 
81974
 
81975
 
81976
 
81977
 
81978
 
81979
 
81980
 
81981
 
81982
 
81983
 
81984
 
81985
 
81986
 
81987
 
81988
 
81989
 
81990
 
81991
 
81992
 
81993
 
81994
 
81995
 
81996
 
81997
 
81998
 
81999
 
82000
 
82001
 
82002
 
82003
 
82004
 
82005
 
82006
 
82007
 
82008
 
82009
 
82010
 
82011
 
82012
 
82013
 
82014
 
82015
 
82016
 
82017
 
82018
 
82019
 
82020
 
82021
 
82022
 
82023
 
82024
 
82025
 
82026
 
82027
 
82028
 
82029
 
82030
 
82031
 
82032
 
82033
 
82034
 
82035
 
82036
 
82037
 
82038
 
82039
 
82040
 
82041
 
82042
 
82043
 
82044
 
82045
 
82046
 
82047
 
82048
 
82049
 
82050
 
82051
 
82052
 
82053
 
82054
 
82055
 
82056
 
82057
 
82058
 
82059
 
82060
 
82061
 
82062
 
82063
 
82064
 
82065
 
82066
 
82067
 
82068
 
82069
 
82070
 
82071
 
82072
 
82073
 
82074
 
82075
 
82076
 
82077
 
82078
 
82079
 
82080
 
82081
 
82082
 
82083
 
82084
 
82085
 
82086
 
82087
 
82088
 
82089
 
82090
 
82091
 
82092
 
82093
 
82094
 
82095
 
82096
 
82097
 
82098
 
82099
 
82100
 
82101
 
82102
 
82103
 
82104
 
82105
 
82106
 
82107
 
82108
 
82109
 
82110
 
82111
 
82112
 
82113
 
82114
 
82115
 
82116
 
82117
 
82118
 
82119
 
82120
 
82121
 
82122
 
82123
 
82124
 
82125
 
82126
 
82127
 
82128
 
82129
 
82130
 
82131
 
82132
 
82133
 
82134
 
82135
 
82136
 
82137
 
82138
 
82139
 
82140
 
82141
 
82142
 
82143
 
82144
 
82145
 
82146
 
82147
 
82148
 
82149
 
82150
 
82151
 
82152
 
82153
 
82154
 
82155
 
82156
 
82157
 
82158
 
82159
 
82160
 
82161
 
82162
 
82163
 
82164
 
82165
 
82166
 
82167
 
82168
 
82169
 
82170
 
82171
 
82172
 
82173
 
82174
 
82175
 
82176
 
82177
 
82178
 
82179
 
82180
 
82181
 
82182
 
82183
 
82184
 
82185
 
82186
 
82187
 
82188
 
82189
 
82190
 
82191
 
82192
 
82193
 
82194
 
82195
 
82196
 
82197
 
82198
 
82199
 
82200
 
82201
 
82202
 
82203
 
82204
 
82205
 
82206
 
82207
 
82208
 
82209
 
82210
 
82211
 
82212
 
82213
 
82214
 
82215
 
82216
 
82217
 
82218
 
82219
 
82220
 
82221
 
82222
 
82223
 
82224
 
82225
 
82226
 
82227
 
82228
 
82229
 
82230
 
82231
 
82232
 
82233
 
82234
 
82235
 
82236
 
82237
 
82238
 
82239
 
82240
 
82241
 
82242
 
82243
 
82244
 
82245
 
82246
 
82247
 
82248
 
82249
 
82250
 
82251
 
82252
 
82253
 
82254
 
82255
 
82256
 
82257
 
82258
 
82259
 
82260
 
82261
 
82262
 
82263
 
82264
 
82265
 
82266
 
82267
 
82268
 
82269
 
82270
 
82271
 
82272
 
82273
 
82274
 
82275
 
82276
 
82277
 
82278
 
82279
 
82280
 
82281
 
82282
 
82283
 
82284
 
82285
 
82286
 
82287
 
82288
 
82289
 
82290
 
82291
 
82292
 
82293
 
82294
 
82295
 
82296
 
82297
 
82298
 
82299
 
82300
 
82301
 
82302
 
82303
 
82304
 
82305
 
82306
 
82307
 
82308
 
82309
 
82310
 
82311
 
82312
 
82313
 
82314
 
82315
 
82316
 
82317
 
82318
 
82319
 
82320
 
82321
 
82322
 
82323
 
82324
 
82325
 
82326
 
82327
 
82328
 
82329
 
82330
 
82331
 
82332
 
82333
 
82334
 
82335
 
82336
 
82337
 
82338
 
82339
 
82340
 
82341
 
82342
 
82343
 
82344
 
82345
 
82346
 
82347
 
82348
 
82349
 
82350
 
82351
 
82352
 
82353
 
82354
 
82355
 
82356
 
82357
 
82358
 
82359
 
82360
 
82361
 
82362
 
82363
 
82364
 
82365
 
82366
 
82367
 
82368
 
82369
 
82370
 
82371
 
82372
 
82373
 
82374
 
82375
 
82376
 
82377
 
82378
 
82379
 
82380
 
82381
 
82382
 
82383
 
82384
 
82385
 
82386
 
82387
 
82388
 
82389
 
82390
 
82391
 
82392
 
82393
 
82394
 
82395
 
82396
 
82397
 
82398
 
82399
 
82400
 
82401
 
82402
 
82403
 
82404
 
82405
 
82406
 
82407
 
82408
 
82409
 
82410
 
82411
 
82412
 
82413
 
82414
 
82415
 
82416
 
82417
 
82418
 
82419
 
82420
 
82421
 
82422
 
82423
 
82424
 
82425
 
82426
 
82427
 
82428
 
82429
 
82430
 
82431
 
82432
 
82433
 
82434
 
82435
 
82436
 
82437
 
82438
 
82439
 
82440
 
82441
 
82442
 
82443
 
82444
 
82445
 
82446
 
82447
 
82448
 
82449
 
82450
 
82451
 
82452
 
82453
 
82454
 
82455
 
82456
 
82457
 
82458
 
82459
 
82460
 
82461
 
82462
 
82463
 
82464
 
82465
 
82466
 
82467
 
82468
 
82469
 
82470
 
82471
 
82472
 
82473
 
82474
 
82475
 
82476
 
82477
 
82478
 
82479
 
82480
 
82481
 
82482
 
82483
 
82484
 
82485
 
82486
 
82487
 
82488
 
82489
 
82490
 
82491
 
82492
 
82493
 
82494
 
82495
 
82496
 
82497
 
82498
 
82499
 
82500
 
82501
 
82502
 
82503
 
82504
 
82505
 
82506
 
82507
 
82508
 
82509
 
82510
 
82511
 
82512
 
82513
 
82514
 
82515
 
82516
 
82517
 
82518
 
82519
 
82520
 
82521
 
82522
 
82523
 
82524
 
82525
 
82526
 
82527
 
82528
 
82529
 
82530
 
82531
 
82532
 
82533
 
82534
 
82535
 
82536
 
82537
 
82538
 
82539
 
82540
 
82541
 
82542
 
82543
 
82544
 
82545
 
82546
 
82547
 
82548
 
82549
 
82550
 
82551
 
82552
 
82553
 
82554
 
82555
 
82556
 
82557
 
82558
 
82559
 
82560
 
82561
 
82562
 
82563
 
82564
 
82565
 
82566
 
82567
 
82568
 
82569
 
82570
 
82571
 
82572
 
82573
 
82574
 
82575
 
82576
 
82577
 
82578
 
82579
 
82580
 
82581
 
82582
 
82583
 
82584
 
82585
 
82586
 
82587
 
82588
 
82589
 
82590
 
82591
 
82592
 
82593
 
82594
 
82595
 
82596
 
82597
 
82598
 
82599
 
82600
 
82601
 
82602
 
82603
 
82604
 
82605
 
82606
 
82607
 
82608
 
82609
 
82610
 
82611
 
82612
 
82613
 
82614
 
82615
 
82616
 
82617
 
82618
 
82619
 
82620
 
82621
 
82622
 
82623
 
82624
 
82625
 
82626
 
82627
 
82628
 
82629
 
82630
 
82631
 
82632
 
82633
 
82634
 
82635
 
82636
 
82637
 
82638
 
82639
 
82640
 
82641
 
82642
 
82643
 
82644
 
82645
 
82646
 
82647
 
82648
 
82649
 
82650
 
82651
 
82652
 
82653
 
82654
 
82655
 
82656
 
82657
 
82658
 
82659
 
82660
 
82661
 
82662
 
82663
 
82664
 
82665
 
82666
 
82667
 
82668
 
82669
 
82670
 
82671
 
82672
 
82673
 
82674
 
82675
 
82676
 
82677
 
82678
 
82679
 
82680
 
82681
 
82682
 
82683
 
82684
 
82685
 
82686
 
82687
 
82688
 
82689
 
82690
 
82691
 
82692
 
82693
 
82694
 
82695
 
82696
 
82697
 
82698
 
82699
 
82700
 
82701
 
82702
 
82703
 
82704
 
82705
 
82706
 
82707
 
82708
 
82709
 
82710
 
82711
 
82712
 
82713
 
82714
 
82715
 
82716
 
82717
 
82718
 
82719
 
82720
 
82721
 
82722
 
82723
 
82724
 
82725
 
82726
 
82727
 
82728
 
82729
 
82730
 
82731
 
82732
 
82733
 
82734
 
82735
 
82736
 
82737
 
82738
 
82739
 
82740
 
82741
 
82742
 
82743
 
82744
 
82745
 
82746
 
82747
 
82748
 
82749
 
82750
 
82751
 
82752
 
82753
 
82754
 
82755
 
82756
 
82757
 
82758
 
82759
 
82760
 
82761
 
82762
 
82763
 
82764
 
82765
 
82766
 
82767
 
82768
 
82769
 
82770
 
82771
 
82772
 
82773
 
82774
 
82775
 
82776
 
82777
 
82778
 
82779
 
82780
 
82781
 
82782
 
82783
 
82784
 
82785
 
82786
 
82787
 
82788
 
82789
 
82790
 
82791
 
82792
 
82793
 
82794
 
82795
 
82796
 
82797
 
82798
 
82799
 
82800
 
82801
 
82802
 
82803
 
82804
 
82805
 
82806
 
82807
 
82808
 
82809
 
82810
 
82811
 
82812
 
82813
 
82814
 
82815
 
82816
 
82817
 
82818
 
82819
 
82820
 
82821
 
82822
 
82823
 
82824
 
82825
 
82826
 
82827
 
82828
 
82829
 
82830
 
82831
 
82832
 
82833
 
82834
 
82835
 
82836
 
82837
 
82838
 
82839
 
82840
 
82841
 
82842
 
82843
 
82844
 
82845
 
82846
 
82847
 
82848
 
82849
 
82850
 
82851
 
82852
 
82853
 
82854
 
82855
 
82856
 
82857
 
82858
 
82859
 
82860
 
82861
 
82862
 
82863
 
82864
 
82865
 
82866
 
82867
 
82868
 
82869
 
82870
 
82871
 
82872
 
82873
 
82874
 
82875
 
82876
 
82877
 
82878
 
82879
 
82880
 
82881
 
82882
 
82883
 
82884
 
82885
 
82886
 
82887
 
82888
 
82889
 
82890
 
82891
 
82892
 
82893
 
82894
 
82895
 
82896
 
82897
 
82898
 
82899
 
82900
 
82901
 
82902
 
82903
 
82904
 
82905
 
82906
 
82907
 
82908
 
82909
 
82910
 
82911
 
82912
 
82913
 
82914
 
82915
 
82916
 
82917
 
82918
 
82919
 
82920
 
82921
 
82922
 
82923
 
82924
 
82925
 
82926
 
82927
 
82928
 
82929
 
82930
 
82931
 
82932
 
82933
 
82934
 
82935
 
82936
 
82937
 
82938
 
82939
 
82940
 
82941
 
82942
 
82943
 
82944
 
82945
 
82946
 
82947
 
82948
 
82949
 
82950
 
82951
 
82952
 
82953
 
82954
 
82955
 
82956
 
82957
 
82958
 
82959
 
82960
 
82961
 
82962
 
82963
 
82964
 
82965
 
82966
 
82967
 
82968
 
82969
 
82970
 
82971
 
82972
 
82973
 
82974
 
82975
 
82976
 
82977
 
82978
 
82979
 
82980
 
82981
 
82982
 
82983
 
82984
 
82985
 
82986
 
82987
 
82988
 
82989
 
82990
 
82991
 
82992
 
82993
 
82994
 
82995
 
82996
 
82997
 
82998
 
82999
 
83000
 
83001
 
83002
 
83003
 
83004
 
83005
 
83006
 
83007
 
83008
 
83009
 
83010
 
83011
 
83012
 
83013
 
83014
 
83015
 
83016
 
83017
 
83018
 
83019
 
83020
 
83021
 
83022
 
83023
 
83024
 
83025
 
83026
 
83027
 
83028
 
83029
 
83030
 
83031
 
83032
 
83033
 
83034
 
83035
 
83036
 
83037
 
83038
 
83039
 
83040
 
83041
 
83042
 
83043
 
83044
 
83045
 
83046
 
83047
 
83048
 
83049
 
83050
 
83051
 
83052
 
83053
 
83054
 
83055
 
83056
 
83057
 
83058
 
83059
 
83060
 
83061
 
83062
 
83063
 
83064
 
83065
 
83066
 
83067
 
83068
 
83069
 
83070
 
83071
 
83072
 
83073
 
83074
 
83075
 
83076
 
83077
 
83078
 
83079
 
83080
 
83081
 
83082
 
83083
 
83084
 
83085
 
83086
 
83087
 
83088
 
83089
 
83090
 
83091
 
83092
 
83093
 
83094
 
83095
 
83096
 
83097
 
83098
 
83099
 
83100
 
83101
 
83102
 
83103
 
83104
 
83105
 
83106
 
83107
 
83108
 
83109
 
83110
 
83111
 
83112
 
83113
 
83114
 
83115
 
83116
 
83117
 
83118
 
83119
 
83120
 
83121
 
83122
 
83123
 
83124
 
83125
 
83126
 
83127
 
83128
 
83129
 
83130
 
83131
 
83132
 
83133
 
83134
 
83135
 
83136
 
83137
 
83138
 
83139
 
83140
 
83141
 
83142
 
83143
 
83144
 
83145
 
83146
 
83147
 
83148
 
83149
 
83150
 
83151
 
83152
 
83153
 
83154
 
83155
 
83156
 
83157
 
83158
 
83159
 
83160
 
83161
 
83162
 
83163
 
83164
 
83165
 
83166
 
83167
 
83168
 
83169
 
83170
 
83171
 
83172
 
83173
 
83174
 
83175
 
83176
 
83177
 
83178
 
83179
 
83180
 
83181
 
83182
 
83183
 
83184
 
83185
 
83186
 
83187
 
83188
 
83189
 
83190
 
83191
 
83192
 
83193
 
83194
 
83195
 
83196
 
83197
 
83198
 
83199
 
83200
 
83201
 
83202
 
83203
 
83204
 
83205
 
83206
 
83207
 
83208
 
83209
 
83210
 
83211
 
83212
 
83213
 
83214
 
83215
 
83216
 
83217
 
83218
 
83219
 
83220
 
83221
 
83222
 
83223
 
83224
 
83225
 
83226
 
83227
 
83228
 
83229
 
83230
 
83231
 
83232
 
83233
 
83234
 
83235
 
83236
 
83237
 
83238
 
83239
 
83240
 
83241
 
83242
 
83243
 
83244
 
83245
 
83246
 
83247
 
83248
 
83249
 
83250
 
83251
 
83252
 
83253
 
83254
 
83255
 
83256
 
83257
 
83258
 
83259
 
83260
 
83261
 
83262
 
83263
 
83264
 
83265
 
83266
 
83267
 
83268
 
83269
 
83270
 
83271
 
83272
 
83273
 
83274
 
83275
 
83276
 
83277
 
83278
 
83279
 
83280
 
83281
 
83282
 
83283
 
83284
 
83285
 
83286
 
83287
 
83288
 
83289
 
83290
 
83291
 
83292
 
83293
 
83294
 
83295
 
83296
 
83297
 
83298
 
83299
 
83300
 
83301
 
83302
 
83303
 
83304
 
83305
 
83306
 
83307
 
83308
 
83309
 
83310
 
83311
 
83312
 
83313
 
83314
 
83315
 
83316
 
83317
 
83318
 
83319
 
83320
 
83321
 
83322
 
83323
 
83324
 
83325
 
83326
 
83327
 
83328
 
83329
 
83330
 
83331
 
83332
 
83333
 
83334
 
83335
 
83336
 
83337
 
83338
 
83339
 
83340
 
83341
 
83342
 
83343
 
83344
 
83345
 
83346
 
83347
 
83348
 
83349
 
83350
 
83351
 
83352
 
83353
 
83354
 
83355
 
83356
 
83357
 
83358
 
83359
 
83360
 
83361
 
83362
 
83363
 
83364
 
83365
 
83366
 
83367
 
83368
 
83369
 
83370
 
83371
 
83372
 
83373
 
83374
 
83375
 
83376
 
83377
 
83378
 
83379
 
83380
 
83381
 
83382
 
83383
 
83384
 
83385
 
83386
 
83387
 
83388
 
83389
 
83390
 
83391
 
83392
 
83393
 
83394
 
83395
 
83396
 
83397
 
83398
 
83399
 
83400
 
83401
 
83402
 
83403
 
83404
 
83405
 
83406
 
83407
 
83408
 
83409
 
83410
 
83411
 
83412
 
83413
 
83414
 
83415
 
83416
 
83417
 
83418
 
83419
 
83420
 
83421
 
83422
 
83423
 
83424
 
83425
 
83426
 
83427
 
83428
 
83429
 
83430
 
83431
 
83432
 
83433
 
83434
 
83435
 
83436
 
83437
 
83438
 
83439
 
83440
 
83441
 
83442
 
83443
 
83444
 
83445
 
83446
 
83447
 
83448
 
83449
 
83450
 
83451
 
83452
 
83453
 
83454
 
83455
 
83456
 
83457
 
83458
 
83459
 
83460
 
83461
 
83462
 
83463
 
83464
 
83465
 
83466
 
83467
 
83468
 
83469
 
83470
 
83471
 
83472
 
83473
 
83474
 
83475
 
83476
 
83477
 
83478
 
83479
 
83480
 
83481
 
83482
 
83483
 
83484
 
83485
 
83486
 
83487
 
83488
 
83489
 
83490
 
83491
 
83492
 
83493
 
83494
 
83495
 
83496
 
83497
 
83498
 
83499
 
83500
 
83501
 
83502
 
83503
 
83504
 
83505
 
83506
 
83507
 
83508
 
83509
 
83510
 
83511
 
83512
 
83513
 
83514
 
83515
 
83516
 
83517
 
83518
 
83519
 
83520
 
83521
 
83522
 
83523
 
83524
 
83525
 
83526
 
83527
 
83528
 
83529
 
83530
 
83531
 
83532
 
83533
 
83534
 
83535
 
83536
 
83537
 
83538
 
83539
 
83540
 
83541
 
83542
 
83543
 
83544
 
83545
 
83546
 
83547
 
83548
 
83549
 
83550
 
83551
 
83552
 
83553
 
83554
 
83555
 
83556
 
83557
 
83558
 
83559
 
83560
 
83561
 
83562
 
83563
 
83564
 
83565
 
83566
 
83567
 
83568
 
83569
 
83570
 
83571
 
83572
 
83573
 
83574
 
83575
 
83576
 
83577
 
83578
 
83579
 
83580
 
83581
 
83582
 
83583
 
83584
 
83585
 
83586
 
83587
 
83588
 
83589
 
83590
 
83591
 
83592
 
83593
 
83594
 
83595
 
83596
 
83597
 
83598
 
83599
 
83600
 
83601
 
83602
 
83603
 
83604
 
83605
 
83606
 
83607
 
83608
 
83609
 
83610
 
83611
 
83612
 
83613
 
83614
 
83615
 
83616
 
83617
 
83618
 
83619
 
83620
 
83621
 
83622
 
83623
 
83624
 
83625
 
83626
 
83627
 
83628
 
83629
 
83630
 
83631
 
83632
 
83633
 
83634
 
83635
 
83636
 
83637
 
83638
 
83639
 
83640
 
83641
 
83642
 
83643
 
83644
 
83645
 
83646
 
83647
 
83648
 
83649
 
83650
 
83651
 
83652
 
83653
 
83654
 
83655
 
83656
 
83657
 
83658
 
83659
 
83660
 
83661
 
83662
 
83663
 
83664
 
83665
 
83666
 
83667
 
83668
 
83669
 
83670
 
83671
 
83672
 
83673
 
83674
 
83675
 
83676
 
83677
 
83678
 
83679
 
83680
 
83681
 
83682
 
83683
 
83684
 
83685
 
83686
 
83687
 
83688
 
83689
 
83690
 
83691
 
83692
 
83693
 
83694
 
83695
 
83696
 
83697
 
83698
 
83699
 
83700
 
83701
 
83702
 
83703
 
83704
 
83705
 
83706
 
83707
 
83708
 
83709
 
83710
 
83711
 
83712
 
83713
 
83714
 
83715
 
83716
 
83717
 
83718
 
83719
 
83720
 
83721
 
83722
 
83723
 
83724
 
83725
 
83726
 
83727
 
83728
 
83729
 
83730
 
83731
 
83732
 
83733
 
83734
 
83735
 
83736
 
83737
 
83738
 
83739
 
83740
 
83741
 
83742
 
83743
 
83744
 
83745
 
83746
 
83747
 
83748
 
83749
 
83750
 
83751
 
83752
 
83753
 
83754
 
83755
 
83756
 
83757
 
83758
 
83759
 
83760
 
83761
 
83762
 
83763
 
83764
 
83765
 
83766
 
83767
 
83768
 
83769
 
83770
 
83771
 
83772
 
83773
 
83774
 
83775
 
83776
 
83777
 
83778
 
83779
 
83780
 
83781
 
83782
 
83783
 
83784
 
83785
 
83786
 
83787
 
83788
 
83789
 
83790
 
83791
 
83792
 
83793
 
83794
 
83795
 
83796
 
83797
 
83798
 
83799
 
83800
 
83801
 
83802
 
83803
 
83804
 
83805
 
83806
 
83807
 
83808
 
83809
 
83810
 
83811
 
83812
 
83813
 
83814
 
83815
 
83816
 
83817
 
83818
 
83819
 
83820
 
83821
 
83822
 
83823
 
83824
 
83825
 
83826
 
83827
 
83828
 
83829
 
83830
 
83831
 
83832
 
83833
 
83834
 
83835
 
83836
 
83837
 
83838
 
83839
 
83840
 
83841
 
83842
 
83843
 
83844
 
83845
 
83846
 
83847
 
83848
 
83849
 
83850
 
83851
 
83852
 
83853
 
83854
 
83855
 
83856
 
83857
 
83858
 
83859
 
83860
 
83861
 
83862
 
83863
 
83864
 
83865
 
83866
 
83867
 
83868
 
83869
 
83870
 
83871
 
83872
 
83873
 
83874
 
83875
 
83876
 
83877
 
83878
 
83879
 
83880
 
83881
 
83882
 
83883
 
83884
 
83885
 
83886
 
83887
 
83888
 
83889
 
83890
 
83891
 
83892
 
83893
 
83894
 
83895
 
83896
 
83897
 
83898
 
83899
 
83900
 
83901
 
83902
 
83903
 
83904
 
83905
 
83906
 
83907
 
83908
 
83909
 
83910
 
83911
 
83912
 
83913
 
83914
 
83915
 
83916
 
83917
 
83918
 
83919
 
83920
 
83921
 
83922
 
83923
 
83924
 
83925
 
83926
 
83927
 
83928
 
83929
 
83930
 
83931
 
83932
 
83933
 
83934
 
83935
 
83936
 
83937
 
83938
 
83939
 
83940
 
83941
 
83942
 
83943
 
83944
 
83945
 
83946
 
83947
 
83948
 
83949
 
83950
 
83951
 
83952
 
83953
 
83954
 
83955
 
83956
 
83957
 
83958
 
83959
 
83960
 
83961
 
83962
 
83963
 
83964
 
83965
 
83966
 
83967
 
83968
 
83969
 
83970
 
83971
 
83972
 
83973
 
83974
 
83975
 
83976
 
83977
 
83978
 
83979
 
83980
 
83981
 
83982
 
83983
 
83984
 
83985
 
83986
 
83987
 
83988
 
83989
 
83990
 
83991
 
83992
 
83993
 
83994
 
83995
 
83996
 
83997
 
83998
 
83999
 
84000
 
84001
 
84002
 
84003
 
84004
 
84005
 
84006
 
84007
 
84008
 
84009
 
84010
 
84011
 
84012
 
84013
 
84014
 
84015
 
84016
 
84017
 
84018
 
84019
 
84020
 
84021
 
84022
 
84023
 
84024
 
84025
 
84026
 
84027
 
84028
 
84029
 
84030
 
84031
 
84032
 
84033
 
84034
 
84035
 
84036
 
84037
 
84038
 
84039
 
84040
 
84041
 
84042
 
84043
 
84044
 
84045
 
84046
 
84047
 
84048
 
84049
 
84050
 
84051
 
84052
 
84053
 
84054
 
84055
 
84056
 
84057
 
84058
 
84059
 
84060
 
84061
 
84062
 
84063
 
84064
 
84065
 
84066
 
84067
 
84068
 
84069
 
84070
 
84071
 
84072
 
84073
 
84074
 
84075
 
84076
 
84077
 
84078
 
84079
 
84080
 
84081
 
84082
 
84083
 
84084
 
84085
 
84086
 
84087
 
84088
 
84089
 
84090
 
84091
 
84092
 
84093
 
84094
 
84095
 
84096
 
84097
 
84098
 
84099
 
84100
 
84101
 
84102
 
84103
 
84104
 
84105
 
84106
 
84107
 
84108
 
84109
 
84110
 
84111
 
84112
 
84113
 
84114
 
84115
 
84116
 
84117
 
84118
 
84119
 
84120
 
84121
 
84122
 
84123
 
84124
 
84125
 
84126
 
84127
 
84128
 
84129
 
84130
 
84131
 
84132
 
84133
 
84134
 
84135
 
84136
 
84137
 
84138
 
84139
 
84140
 
84141
 
84142
 
84143
 
84144
 
84145
 
84146
 
84147
 
84148
 
84149
 
84150
 
84151
 
84152
 
84153
 
84154
 
84155
 
84156
 
84157
 
84158
 
84159
 
84160
 
84161
 
84162
 
84163
 
84164
 
84165
 
84166
 
84167
 
84168
 
84169
 
84170
 
84171
 
84172
 
84173
 
84174
 
84175
 
84176
 
84177
 
84178
 
84179
 
84180
 
84181
 
84182
 
84183
 
84184
 
84185
 
84186
 
84187
 
84188
 
84189
 
84190
 
84191
 
84192
 
84193
 
84194
 
84195
 
84196
 
84197
 
84198
 
84199
 
84200
 
84201
 
84202
 
84203
 
84204
 
84205
 
84206
 
84207
 
84208
 
84209
 
84210
 
84211
 
84212
 
84213
 
84214
 
84215
 
84216
 
84217
 
84218
 
84219
 
84220
 
84221
 
84222
 
84223
 
84224
 
84225
 
84226
 
84227
 
84228
 
84229
 
84230
 
84231
 
84232
 
84233
 
84234
 
84235
 
84236
 
84237
 
84238
 
84239
 
84240
 
84241
 
84242
 
84243
 
84244
 
84245
 
84246
 
84247
 
84248
 
84249
 
84250
 
84251
 
84252
 
84253
 
84254
 
84255
 
84256
 
84257
 
84258
 
84259
 
84260
 
84261
 
84262
 
84263
 
84264
 
84265
 
84266
 
84267
 
84268
 
84269
 
84270
 
84271
 
84272
 
84273
 
84274
 
84275
 
84276
 
84277
 
84278
 
84279
 
84280
 
84281
 
84282
 
84283
 
84284
 
84285
 
84286
 
84287
 
84288
 
84289
 
84290
 
84291
 
84292
 
84293
 
84294
 
84295
 
84296
 
84297
 
84298
 
84299
 
84300
 
84301
 
84302
 
84303
 
84304
 
84305
 
84306
 
84307
 
84308
 
84309
 
84310
 
84311
 
84312
 
84313
 
84314
 
84315
 
84316
 
84317
 
84318
 
84319
 
84320
 
84321
 
84322
 
84323
 
84324
 
84325
 
84326
 
84327
 
84328
 
84329
 
84330
 
84331
 
84332
 
84333
 
84334
 
84335
 
84336
 
84337
 
84338
 
84339
 
84340
 
84341
 
84342
 
84343
 
84344
 
84345
 
84346
 
84347
 
84348
 
84349
 
84350
 
84351
 
84352
 
84353
 
84354
 
84355
 
84356
 
84357
 
84358
 
84359
 
84360
 
84361
 
84362
 
84363
 
84364
 
84365
 
84366
 
84367
 
84368
 
84369
 
84370
 
84371
 
84372
 
84373
 
84374
 
84375
 
84376
 
84377
 
84378
 
84379
 
84380
 
84381
 
84382
 
84383
 
84384
 
84385
 
84386
 
84387
 
84388
 
84389
 
84390
 
84391
 
84392
 
84393
 
84394
 
84395
 
84396
 
84397
 
84398
 
84399
 
84400
 
84401
 
84402
 
84403
 
84404
 
84405
 
84406
 
84407
 
84408
 
84409
 
84410
 
84411
 
84412
 
84413
 
84414
 
84415
 
84416
 
84417
 
84418
 
84419
 
84420
 
84421
 
84422
 
84423
 
84424
 
84425
 
84426
 
84427
 
84428
 
84429
 
84430
 
84431
 
84432
 
84433
 
84434
 
84435
 
84436
 
84437
 
84438
 
84439
 
84440
 
84441
 
84442
 
84443
 
84444
 
84445
 
84446
 
84447
 
84448
 
84449
 
84450
 
84451
 
84452
 
84453
 
84454
 
84455
 
84456
 
84457
 
84458
 
84459
 
84460
 
84461
 
84462
 
84463
 
84464
 
84465
 
84466
 
84467
 
84468
 
84469
 
84470
 
84471
 
84472
 
84473
 
84474
 
84475
 
84476
 
84477
 
84478
 
84479
 
84480
 
84481
 
84482
 
84483
 
84484
 
84485
 
84486
 
84487
 
84488
 
84489
 
84490
 
84491
 
84492
 
84493
 
84494
 
84495
 
84496
 
84497
 
84498
 
84499
 
84500
 
84501
 
84502
 
84503
 
84504
 
84505
 
84506
 
84507
 
84508
 
84509
 
84510
 
84511
 
84512
 
84513
 
84514
 
84515
 
84516
 
84517
 
84518
 
84519
 
84520
 
84521
 
84522
 
84523
 
84524
 
84525
 
84526
 
84527
 
84528
 
84529
 
84530
 
84531
 
84532
 
84533
 
84534
 
84535
 
84536
 
84537
 
84538
 
84539
 
84540
 
84541
 
84542
 
84543
 
84544
 
84545
 
84546
 
84547
 
84548
 
84549
 
84550
 
84551
 
84552
 
84553
 
84554
 
84555
 
84556
 
84557
 
84558
 
84559
 
84560
 
84561
 
84562
 
84563
 
84564
 
84565
 
84566
 
84567
 
84568
 
84569
 
84570
 
84571
 
84572
 
84573
 
84574
 
84575
 
84576
 
84577
 
84578
 
84579
 
84580
 
84581
 
84582
 
84583
 
84584
 
84585
 
84586
 
84587
 
84588
 
84589
 
84590
 
84591
 
84592
 
84593
 
84594
 
84595
 
84596
 
84597
 
84598
 
84599
 
84600
 
84601
 
84602
 
84603
 
84604
 
84605
 
84606
 
84607
 
84608
 
84609
 
84610
 
84611
 
84612
 
84613
 
84614
 
84615
 
84616
 
84617
 
84618
 
84619
 
84620
 
84621
 
84622
 
84623
 
84624
 
84625
 
84626
 
84627
 
84628
 
84629
 
84630
 
84631
 
84632
 
84633
 
84634
 
84635
 
84636
 
84637
 
84638
 
84639
 
84640
 
84641
 
84642
 
84643
 
84644
 
84645
 
84646
 
84647
 
84648
 
84649
 
84650
 
84651
 
84652
 
84653
 
84654
 
84655
 
84656
 
84657
 
84658
 
84659
 
84660
 
84661
 
84662
 
84663
 
84664
 
84665
 
84666
 
84667
 
84668
 
84669
 
84670
 
84671
 
84672
 
84673
 
84674
 
84675
 
84676
 
84677
 
84678
 
84679
 
84680
 
84681
 
84682
 
84683
 
84684
 
84685
 
84686
 
84687
 
84688
 
84689
 
84690
 
84691
 
84692
 
84693
 
84694
 
84695
 
84696
 
84697
 
84698
 
84699
 
84700
 
84701
 
84702
 
84703
 
84704
 
84705
 
84706
 
84707
 
84708
 
84709
 
84710
 
84711
 
84712
 
84713
 
84714
 
84715
 
84716
 
84717
 
84718
 
84719
 
84720
 
84721
 
84722
 
84723
 
84724
 
84725
 
84726
 
84727
 
84728
 
84729
 
84730
 
84731
 
84732
 
84733
 
84734
 
84735
 
84736
 
84737
 
84738
 
84739
 
84740
 
84741
 
84742
 
84743
 
84744
 
84745
 
84746
 
84747
 
84748
 
84749
 
84750
 
84751
 
84752
 
84753
 
84754
 
84755
 
84756
 
84757
 
84758
 
84759
 
84760
 
84761
 
84762
 
84763
 
84764
 
84765
 
84766
 
84767
 
84768
 
84769
 
84770
 
84771
 
84772
 
84773
 
84774
 
84775
 
84776
 
84777
 
84778
 
84779
 
84780
 
84781
 
84782
 
84783
 
84784
 
84785
 
84786
 
84787
 
84788
 
84789
 
84790
 
84791
 
84792
 
84793
 
84794
 
84795
 
84796
 
84797
 
84798
 
84799
 
84800
 
84801
 
84802
 
84803
 
84804
 
84805
 
84806
 
84807
 
84808
 
84809
 
84810
 
84811
 
84812
 
84813
 
84814
 
84815
 
84816
 
84817
 
84818
 
84819
 
84820
 
84821
 
84822
 
84823
 
84824
 
84825
 
84826
 
84827
 
84828
 
84829
 
84830
 
84831
 
84832
 
84833
 
84834
 
84835
 
84836
 
84837
 
84838
 
84839
 
84840
 
84841
 
84842
 
84843
 
84844
 
84845
 
84846
 
84847
 
84848
 
84849
 
84850
 
84851
 
84852
 
84853
 
84854
 
84855
 
84856
 
84857
 
84858
 
84859
 
84860
 
84861
 
84862
 
84863
 
84864
 
84865
 
84866
 
84867
 
84868
 
84869
 
84870
 
84871
 
84872
 
84873
 
84874
 
84875
 
84876
 
84877
 
84878
 
84879
 
84880
 
84881
 
84882
 
84883
 
84884
 
84885
 
84886
 
84887
 
84888
 
84889
 
84890
 
84891
 
84892
 
84893
 
84894
 
84895
 
84896
 
84897
 
84898
 
84899
 
84900
 
84901
 
84902
 
84903
 
84904
 
84905
 
84906
 
84907
 
84908
 
84909
 
84910
 
84911
 
84912
 
84913
 
84914
 
84915
 
84916
 
84917
 
84918
 
84919
 
84920
 
84921
 
84922
 
84923
 
84924
 
84925
 
84926
 
84927
 
84928
 
84929
 
84930
 
84931
 
84932
 
84933
 
84934
 
84935
 
84936
 
84937
 
84938
 
84939
 
84940
 
84941
 
84942
 
84943
 
84944
 
84945
 
84946
 
84947
 
84948
 
84949
 
84950
 
84951
 
84952
 
84953
 
84954
 
84955
 
84956
 
84957
 
84958
 
84959
 
84960
 
84961
 
84962
 
84963
 
84964
 
84965
 
84966
 
84967
 
84968
 
84969
 
84970
 
84971
 
84972
 
84973
 
84974
 
84975
 
84976
 
84977
 
84978
 
84979
 
84980
 
84981
 
84982
 
84983
 
84984
 
84985
 
84986
 
84987
 
84988
 
84989
 
84990
 
84991
 
84992
 
84993
 
84994
 
84995
 
84996
 
84997
 
84998
 
84999
 
85000
 
85001
 
85002
 
85003
 
85004
 
85005
 
85006
 
85007
 
85008
 
85009
 
85010
 
85011
 
85012
 
85013
 
85014
 
85015
 
85016
 
85017
 
85018
 
85019
 
85020
 
85021
 
85022
 
85023
 
85024
 
85025
 
85026
 
85027
 
85028
 
85029
 
85030
 
85031
 
85032
 
85033
 
85034
 
85035
 
85036
 
85037
 
85038
 
85039
 
85040
 
85041
 
85042
 
85043
 
85044
 
85045
 
85046
 
85047
 
85048
 
85049
 
85050
 
85051
 
85052
 
85053
 
85054
 
85055
 
85056
 
85057
 
85058
 
85059
 
85060
 
85061
 
85062
 
85063
 
85064
 
85065
 
85066
 
85067
 
85068
 
85069
 
85070
 
85071
 
85072
 
85073
 
85074
 
85075
 
85076
 
85077
 
85078
 
85079
 
85080
 
85081
 
85082
 
85083
 
85084
 
85085
 
85086
 
85087
 
85088
 
85089
 
85090
 
85091
 
85092
 
85093
 
85094
 
85095
 
85096
 
85097
 
85098
 
85099
 
85100
 
85101
 
85102
 
85103
 
85104
 
85105
 
85106
 
85107
 
85108
 
85109
 
85110
 
85111
 
85112
 
85113
 
85114
 
85115
 
85116
 
85117
 
85118
 
85119
 
85120
 
85121
 
85122
 
85123
 
85124
 
85125
 
85126
 
85127
 
85128
 
85129
 
85130
 
85131
 
85132
 
85133
 
85134
 
85135
 
85136
 
85137
 
85138
 
85139
 
85140
 
85141
 
85142
 
85143
 
85144
 
85145
 
85146
 
85147
 
85148
 
85149
 
85150
 
85151
 
85152
 
85153
 
85154
 
85155
 
85156
 
85157
 
85158
 
85159
 
85160
 
85161
 
85162
 
85163
 
85164
 
85165
 
85166
 
85167
 
85168
 
85169
 
85170
 
85171
 
85172
 
85173
 
85174
 
85175
 
85176
 
85177
 
85178
 
85179
 
85180
 
85181
 
85182
 
85183
 
85184
 
85185
 
85186
 
85187
 
85188
 
85189
 
85190
 
85191
 
85192
 
85193
 
85194
 
85195
 
85196
 
85197
 
85198
 
85199
 
85200
 
85201
 
85202
 
85203
 
85204
 
85205
 
85206
 
85207
 
85208
 
85209
 
85210
 
85211
 
85212
 
85213
 
85214
 
85215
 
85216
 
85217
 
85218
 
85219
 
85220
 
85221
 
85222
 
85223
 
85224
 
85225
 
85226
 
85227
 
85228
 
85229
 
85230
 
85231
 
85232
 
85233
 
85234
 
85235
 
85236
 
85237
 
85238
 
85239
 
85240
 
85241
 
85242
 
85243
 
85244
 
85245
 
85246
 
85247
 
85248
 
85249
 
85250
 
85251
 
85252
 
85253
 
85254
 
85255
 
85256
 
85257
 
85258
 
85259
 
85260
 
85261
 
85262
 
85263
 
85264
 
85265
 
85266
 
85267
 
85268
 
85269
 
85270
 
85271
 
85272
 
85273
 
85274
 
85275
 
85276
 
85277
 
85278
 
85279
 
85280
 
85281
 
85282
 
85283
 
85284
 
85285
 
85286
 
85287
 
85288
 
85289
 
85290
 
85291
 
85292
 
85293
 
85294
 
85295
 
85296
 
85297
 
85298
 
85299
 
85300
 
85301
 
85302
 
85303
 
85304
 
85305
 
85306
 
85307
 
85308
 
85309
 
85310
 
85311
 
85312
 
85313
 
85314
 
85315
 
85316
 
85317
 
85318
 
85319
 
85320
 
85321
 
85322
 
85323
 
85324
 
85325
 
85326
 
85327
 
85328
 
85329
 
85330
 
85331
 
85332
 
85333
 
85334
 
85335
 
85336
 
85337
 
85338
 
85339
 
85340
 
85341
 
85342
 
85343
 
85344
 
85345
 
85346
 
85347
 
85348
 
85349
 
85350
 
85351
 
85352
 
85353
 
85354
 
85355
 
85356
 
85357
 
85358
 
85359
 
85360
 
85361
 
85362
 
85363
 
85364
 
85365
 
85366
 
85367
 
85368
 
85369
 
85370
 
85371
 
85372
 
85373
 
85374
 
85375
 
85376
 
85377
 
85378
 
85379
 
85380
 
85381
 
85382
 
85383
 
85384
 
85385
 
85386
 
85387
 
85388
 
85389
 
85390
 
85391
 
85392
 
85393
 
85394
 
85395
 
85396
 
85397
 
85398
 
85399
 
85400
 
85401
 
85402
 
85403
 
85404
 
85405
 
85406
 
85407
 
85408
 
85409
 
85410
 
85411
 
85412
 
85413
 
85414
 
85415
 
85416
 
85417
 
85418
 
85419
 
85420
 
85421
 
85422
 
85423
 
85424
 
85425
 
85426
 
85427
 
85428
 
85429
 
85430
 
85431
 
85432
 
85433
 
85434
 
85435
 
85436
 
85437
 
85438
 
85439
 
85440
 
85441
 
85442
 
85443
 
85444
 
85445
 
85446
 
85447
 
85448
 
85449
 
85450
 
85451
 
85452
 
85453
 
85454
 
85455
 
85456
 
85457
 
85458
 
85459
 
85460
 
85461
 
85462
 
85463
 
85464
 
85465
 
85466
 
85467
 
85468
 
85469
 
85470
 
85471
 
85472
 
85473
 
85474
 
85475
 
85476
 
85477
 
85478
 
85479
 
85480
 
85481
 
85482
 
85483
 
85484
 
85485
 
85486
 
85487
 
85488
 
85489
 
85490
 
85491
 
85492
 
85493
 
85494
 
85495
 
85496
 
85497
 
85498
 
85499
 
85500
 
85501
 
85502
 
85503
 
85504
 
85505
 
85506
 
85507
 
85508
 
85509
 
85510
 
85511
 
85512
 
85513
 
85514
 
85515
 
85516
 
85517
 
85518
 
85519
 
85520
 
85521
 
85522
 
85523
 
85524
 
85525
 
85526
 
85527
 
85528
 
85529
 
85530
 
85531
 
85532
 
85533
 
85534
 
85535
 
85536
 
85537
 
85538
 
85539
 
85540
 
85541
 
85542
 
85543
 
85544
 
85545
 
85546
 
85547
 
85548
 
85549
 
85550
 
85551
 
85552
 
85553
 
85554
 
85555
 
85556
 
85557
 
85558
 
85559
 
85560
 
85561
 
85562
 
85563
 
85564
 
85565
 
85566
 
85567
 
85568
 
85569
 
85570
 
85571
 
85572
 
85573
 
85574
 
85575
 
85576
 
85577
 
85578
 
85579
 
85580
 
85581
 
85582
 
85583
 
85584
 
85585
 
85586
 
85587
 
85588
 
85589
 
85590
 
85591
 
85592
 
85593
 
85594
 
85595
 
85596
 
85597
 
85598
 
85599
 
85600
 
85601
 
85602
 
85603
 
85604
 
85605
 
85606
 
85607
 
85608
 
85609
 
85610
 
85611
 
85612
 
85613
 
85614
 
85615
 
85616
 
85617
 
85618
 
85619
 
85620
 
85621
 
85622
 
85623
 
85624
 
85625
 
85626
 
85627
 
85628
 
85629
 
85630
 
85631
 
85632
 
85633
 
85634
 
85635
 
85636
 
85637
 
85638
 
85639
 
85640
 
85641
 
85642
 
85643
 
85644
 
85645
 
85646
 
85647
 
85648
 
85649
 
85650
 
85651
 
85652
 
85653
 
85654
 
85655
 
85656
 
85657
 
85658
 
85659
 
85660
 
85661
 
85662
 
85663
 
85664
 
85665
 
85666
 
85667
 
85668
 
85669
 
85670
 
85671
 
85672
 
85673
 
85674
 
85675
 
85676
 
85677
 
85678
 
85679
 
85680
 
85681
 
85682
 
85683
 
85684
 
85685
 
85686
 
85687
 
85688
 
85689
 
85690
 
85691
 
85692
 
85693
 
85694
 
85695
 
85696
 
85697
 
85698
 
85699
 
85700
 
85701
 
85702
 
85703
 
85704
 
85705
 
85706
 
85707
 
85708
 
85709
 
85710
 
85711
 
85712
 
85713
 
85714
 
85715
 
85716
 
85717
 
85718
 
85719
 
85720
 
85721
 
85722
 
85723
 
85724
 
85725
 
85726
 
85727
 
85728
 
85729
 
85730
 
85731
 
85732
 
85733
 
85734
 
85735
 
85736
 
85737
 
85738
 
85739
 
85740
 
85741
 
85742
 
85743
 
85744
 
85745
 
85746
 
85747
 
85748
 
85749
 
85750
 
85751
 
85752
 
85753
 
85754
 
85755
 
85756
 
85757
 
85758
 
85759
 
85760
 
85761
 
85762
 
85763
 
85764
 
85765
 
85766
 
85767
 
85768
 
85769
 
85770
 
85771
 
85772
 
85773
 
85774
 
85775
 
85776
 
85777
 
85778
 
85779
 
85780
 
85781
 
85782
 
85783
 
85784
 
85785
 
85786
 
85787
 
85788
 
85789
 
85790
 
85791
 
85792
 
85793
 
85794
 
85795
 
85796
 
85797
 
85798
 
85799
 
85800
 
85801
 
85802
 
85803
 
85804
 
85805
 
85806
 
85807
 
85808
 
85809
 
85810
 
85811
 
85812
 
85813
 
85814
 
85815
 
85816
 
85817
 
85818
 
85819
 
85820
 
85821
 
85822
 
85823
 
85824
 
85825
 
85826
 
85827
 
85828
 
85829
 
85830
 
85831
 
85832
 
85833
 
85834
 
85835
 
85836
 
85837
 
85838
 
85839
 
85840
 
85841
 
85842
 
85843
 
85844
 
85845
 
85846
 
85847
 
85848
 
85849
 
85850
 
85851
 
85852
 
85853
 
85854
 
85855
 
85856
 
85857
 
85858
 
85859
 
85860
 
85861
 
85862
 
85863
 
85864
 
85865
 
85866
 
85867
 
85868
 
85869
 
85870
 
85871
 
85872
 
85873
 
85874
 
85875
 
85876
 
85877
 
85878
 
85879
 
85880
 
85881
 
85882
 
85883
 
85884
 
85885
 
85886
 
85887
 
85888
 
85889
 
85890
 
85891
 
85892
 
85893
 
85894
 
85895
 
85896
 
85897
 
85898
 
85899
 
85900
 
85901
 
85902
 
85903
 
85904
 
85905
 
85906
 
85907
 
85908
 
85909
 
85910
 
85911
 
85912
 
85913
 
85914
 
85915
 
85916
 
85917
 
85918
 
85919
 
85920
 
85921
 
85922
 
85923
 
85924
 
85925
 
85926
 
85927
 
85928
 
85929
 
85930
 
85931
 
85932
 
85933
 
85934
 
85935
 
85936
 
85937
 
85938
 
85939
 
85940
 
85941
 
85942
 
85943
 
85944
 
85945
 
85946
 
85947
 
85948
 
85949
 
85950
 
85951
 
85952
 
85953
 
85954
 
85955
 
85956
 
85957
 
85958
 
85959
 
85960
 
85961
 
85962
 
85963
 
85964
 
85965
 
85966
 
85967
 
85968
 
85969
 
85970
 
85971
 
85972
 
85973
 
85974
 
85975
 
85976
 
85977
 
85978
 
85979
 
85980
 
85981
 
85982
 
85983
 
85984
 
85985
 
85986
 
85987
 
85988
 
85989
 
85990
 
85991
 
85992
 
85993
 
85994
 
85995
 
85996
 
85997
 
85998
 
85999
 
86000
 
86001
 
86002
 
86003
 
86004
 
86005
 
86006
 
86007
 
86008
 
86009
 
86010
 
86011
 
86012
 
86013
 
86014
 
86015
 
86016
 
86017
 
86018
 
86019
 
86020
 
86021
 
86022
 
86023
 
86024
 
86025
 
86026
 
86027
 
86028
 
86029
 
86030
 
86031
 
86032
 
86033
 
86034
 
86035
 
86036
 
86037
 
86038
 
86039
 
86040
 
86041
 
86042
 
86043
 
86044
 
86045
 
86046
 
86047
 
86048
 
86049
 
86050
 
86051
 
86052
 
86053
 
86054
 
86055
 
86056
 
86057
 
86058
 
86059
 
86060
 
86061
 
86062
 
86063
 
86064
 
86065
 
86066
 
86067
 
86068
 
86069
 
86070
 
86071
 
86072
 
86073
 
86074
 
86075
 
86076
 
86077
 
86078
 
86079
 
86080
 
86081
 
86082
 
86083
 
86084
 
86085
 
86086
 
86087
 
86088
 
86089
 
86090
 
86091
 
86092
 
86093
 
86094
 
86095
 
86096
 
86097
 
86098
 
86099
 
86100
 
86101
 
86102
 
86103
 
86104
 
86105
 
86106
 
86107
 
86108
 
86109
 
86110
 
86111
 
86112
 
86113
 
86114
 
86115
 
86116
 
86117
 
86118
 
86119
 
86120
 
86121
 
86122
 
86123
 
86124
 
86125
 
86126
 
86127
 
86128
 
86129
 
86130
 
86131
 
86132
 
86133
 
86134
 
86135
 
86136
 
86137
 
86138
 
86139
 
86140
 
86141
 
86142
 
86143
 
86144
 
86145
 
86146
 
86147
 
86148
 
86149
 
86150
 
86151
 
86152
 
86153
 
86154
 
86155
 
86156
 
86157
 
86158
 
86159
 
86160
 
86161
 
86162
 
86163
 
86164
 
86165
 
86166
 
86167
 
86168
 
86169
 
86170
 
86171
 
86172
 
86173
 
86174
 
86175
 
86176
 
86177
 
86178
 
86179
 
86180
 
86181
 
86182
 
86183
 
86184
 
86185
 
86186
 
86187
 
86188
 
86189
 
86190
 
86191
 
86192
 
86193
 
86194
 
86195
 
86196
 
86197
 
86198
 
86199
 
86200
 
86201
 
86202
 
86203
 
86204
 
86205
 
86206
 
86207
 
86208
 
86209
 
86210
 
86211
 
86212
 
86213
 
86214
 
86215
 
86216
 
86217
 
86218
 
86219
 
86220
 
86221
 
86222
 
86223
 
86224
 
86225
 
86226
 
86227
 
86228
 
86229
 
86230
 
86231
 
86232
 
86233
 
86234
 
86235
 
86236
 
86237
 
86238
 
86239
 
86240
 
86241
 
86242
 
86243
 
86244
 
86245
 
86246
 
86247
 
86248
 
86249
 
86250
 
86251
 
86252
 
86253
 
86254
 
86255
 
86256
 
86257
 
86258
 
86259
 
86260
 
86261
 
86262
 
86263
 
86264
 
86265
 
86266
 
86267
 
86268
 
86269
 
86270
 
86271
 
86272
 
86273
 
86274
 
86275
 
86276
 
86277
 
86278
 
86279
 
86280
 
86281
 
86282
 
86283
 
86284
 
86285
 
86286
 
86287
 
86288
 
86289
 
86290
 
86291
 
86292
 
86293
 
86294
 
86295
 
86296
 
86297
 
86298
 
86299
 
86300
 
86301
 
86302
 
86303
 
86304
 
86305
 
86306
 
86307
 
86308
 
86309
 
86310
 
86311
 
86312
 
86313
 
86314
 
86315
 
86316
 
86317
 
86318
 
86319
 
86320
 
86321
 
86322
 
86323
 
86324
 
86325
 
86326
 
86327
 
86328
 
86329
 
86330
 
86331
 
86332
 
86333
 
86334
 
86335
 
86336
 
86337
 
86338
 
86339
 
86340
 
86341
 
86342
 
86343
 
86344
 
86345
 
86346
 
86347
 
86348
 
86349
 
86350
 
86351
 
86352
 
86353
 
86354
 
86355
 
86356
 
86357
 
86358
 
86359
 
86360
 
86361
 
86362
 
86363
 
86364
 
86365
 
86366
 
86367
 
86368
 
86369
 
86370
 
86371
 
86372
 
86373
 
86374
 
86375
 
86376
 
86377
 
86378
 
86379
 
86380
 
86381
 
86382
 
86383
 
86384
 
86385
 
86386
 
86387
 
86388
 
86389
 
86390
 
86391
 
86392
 
86393
 
86394
 
86395
 
86396
 
86397
 
86398
 
86399
 
86400
 
86401
 
86402
 
86403
 
86404
 
86405
 
86406
 
86407
 
86408
 
86409
 
86410
 
86411
 
86412
 
86413
 
86414
 
86415
 
86416
 
86417
 
86418
 
86419
 
86420
 
86421
 
86422
 
86423
 
86424
 
86425
 
86426
 
86427
 
86428
 
86429
 
86430
 
86431
 
86432
 
86433
 
86434
 
86435
 
86436
 
86437
 
86438
 
86439
 
86440
 
86441
 
86442
 
86443
 
86444
 
86445
 
86446
 
86447
 
86448
 
86449
 
86450
 
86451
 
86452
 
86453
 
86454
 
86455
 
86456
 
86457
 
86458
 
86459
 
86460
 
86461
 
86462
 
86463
 
86464
 
86465
 
86466
 
86467
 
86468
 
86469
 
86470
 
86471
 
86472
 
86473
 
86474
 
86475
 
86476
 
86477
 
86478
 
86479
 
86480
 
86481
 
86482
 
86483
 
86484
 
86485
 
86486
 
86487
 
86488
 
86489
 
86490
 
86491
 
86492
 
86493
 
86494
 
86495
 
86496
 
86497
 
86498
 
86499
 
86500
 
86501
 
86502
 
86503
 
86504
 
86505
 
86506
 
86507
 
86508
 
86509
 
86510
 
86511
 
86512
 
86513
 
86514
 
86515
 
86516
 
86517
 
86518
 
86519
 
86520
 
86521
 
86522
 
86523
 
86524
 
86525
 
86526
 
86527
 
86528
 
86529
 
86530
 
86531
 
86532
 
86533
 
86534
 
86535
 
86536
 
86537
 
86538
 
86539
 
86540
 
86541
 
86542
 
86543
 
86544
 
86545
 
86546
 
86547
 
86548
 
86549
 
86550
 
86551
 
86552
 
86553
 
86554
 
86555
 
86556
 
86557
 
86558
 
86559
 
86560
 
86561
 
86562
 
86563
 
86564
 
86565
 
86566
 
86567
 
86568
 
86569
 
86570
 
86571
 
86572
 
86573
 
86574
 
86575
 
86576
 
86577
 
86578
 
86579
 
86580
 
86581
 
86582
 
86583
 
86584
 
86585
 
86586
 
86587
 
86588
 
86589
 
86590
 
86591
 
86592
 
86593
 
86594
 
86595
 
86596
 
86597
 
86598
 
86599
 
86600
 
86601
 
86602
 
86603
 
86604
 
86605
 
86606
 
86607
 
86608
 
86609
 
86610
 
86611
 
86612
 
86613
 
86614
 
86615
 
86616
 
86617
 
86618
 
86619
 
86620
 
86621
 
86622
 
86623
 
86624
 
86625
 
86626
 
86627
 
86628
 
86629
 
86630
 
86631
 
86632
 
86633
 
86634
 
86635
 
86636
 
86637
 
86638
 
86639
 
86640
 
86641
 
86642
 
86643
 
86644
 
86645
 
86646
 
86647
 
86648
 
86649
 
86650
 
86651
 
86652
 
86653
 
86654
 
86655
 
86656
 
86657
 
86658
 
86659
 
86660
 
86661
 
86662
 
86663
 
86664
 
86665
 
86666
 
86667
 
86668
 
86669
 
86670
 
86671
 
86672
 
86673
 
86674
 
86675
 
86676
 
86677
 
86678
 
86679
 
86680
 
86681
 
86682
 
86683
 
86684
 
86685
 
86686
 
86687
 
86688
 
86689
 
86690
 
86691
 
86692
 
86693
 
86694
 
86695
 
86696
 
86697
 
86698
 
86699
 
86700
 
86701
 
86702
 
86703
 
86704
 
86705
 
86706
 
86707
 
86708
 
86709
 
86710
 
86711
 
86712
 
86713
 
86714
 
86715
 
86716
 
86717
 
86718
 
86719
 
86720
 
86721
 
86722
 
86723
 
86724
 
86725
 
86726
 
86727
 
86728
 
86729
 
86730
 
86731
 
86732
 
86733
 
86734
 
86735
 
86736
 
86737
 
86738
 
86739
 
86740
 
86741
 
86742
 
86743
 
86744
 
86745
 
86746
 
86747
 
86748
 
86749
 
86750
 
86751
 
86752
 
86753
 
86754
 
86755
 
86756
 
86757
 
86758
 
86759
 
86760
 
86761
 
86762
 
86763
 
86764
 
86765
 
86766
 
86767
 
86768
 
86769
 
86770
 
86771
 
86772
 
86773
 
86774
 
86775
 
86776
 
86777
 
86778
 
86779
 
86780
 
86781
 
86782
 
86783
 
86784
 
86785
 
86786
 
86787
 
86788
 
86789
 
86790
 
86791
 
86792
 
86793
 
86794
 
86795
 
86796
 
86797
 
86798
 
86799
 
86800
 
86801
 
86802
 
86803
 
86804
 
86805
 
86806
 
86807
 
86808
 
86809
 
86810
 
86811
 
86812
 
86813
 
86814
 
86815
 
86816
 
86817
 
86818
 
86819
 
86820
 
86821
 
86822
 
86823
 
86824
 
86825
 
86826
 
86827
 
86828
 
86829
 
86830
 
86831
 
86832
 
86833
 
86834
 
86835
 
86836
 
86837
 
86838
 
86839
 
86840
 
86841
 
86842
 
86843
 
86844
 
86845
 
86846
 
86847
 
86848
 
86849
 
86850
 
86851
 
86852
 
86853
 
86854
 
86855
 
86856
 
86857
 
86858
 
86859
 
86860
 
86861
 
86862
 
86863
 
86864
 
86865
 
86866
 
86867
 
86868
 
86869
 
86870
 
86871
 
86872
 
86873
 
86874
 
86875
 
86876
 
86877
 
86878
 
86879
 
86880
 
86881
 
86882
 
86883
 
86884
 
86885
 
86886
 
86887
 
86888
 
86889
 
86890
 
86891
 
86892
 
86893
 
86894
 
86895
 
86896
 
86897
 
86898
 
86899
 
86900
 
86901
 
86902
 
86903
 
86904
 
86905
 
86906
 
86907
 
86908
 
86909
 
86910
 
86911
 
86912
 
86913
 
86914
 
86915
 
86916
 
86917
 
86918
 
86919
 
86920
 
86921
 
86922
 
86923
 
86924
 
86925
 
86926
 
86927
 
86928
 
86929
 
86930
 
86931
 
86932
 
86933
 
86934
 
86935
 
86936
 
86937
 
86938
 
86939
 
86940
 
86941
 
86942
 
86943
 
86944
 
86945
 
86946
 
86947
 
86948
 
86949
 
86950
 
86951
 
86952
 
86953
 
86954
 
86955
 
86956
 
86957
 
86958
 
86959
 
86960
 
86961
 
86962
 
86963
 
86964
 
86965
 
86966
 
86967
 
86968
 
86969
 
86970
 
86971
 
86972
 
86973
 
86974
 
86975
 
86976
 
86977
 
86978
 
86979
 
86980
 
86981
 
86982
 
86983
 
86984
 
86985
 
86986
 
86987
 
86988
 
86989
 
86990
 
86991
 
86992
 
86993
 
86994
 
86995
 
86996
 
86997
 
86998
 
86999
 
87000
 
87001
 
87002
 
87003
 
87004
 
87005
 
87006
 
87007
 
87008
 
87009
 
87010
 
87011
 
87012
 
87013
 
87014
 
87015
 
87016
 
87017
 
87018
 
87019
 
87020
 
87021
 
87022
 
87023
 
87024
 
87025
 
87026
 
87027
 
87028
 
87029
 
87030
 
87031
 
87032
 
87033
 
87034
 
87035
 
87036
 
87037
 
87038
 
87039
 
87040
 
87041
 
87042
 
87043
 
87044
 
87045
 
87046
 
87047
 
87048
 
87049
 
87050
 
87051
 
87052
 
87053
 
87054
 
87055
 
87056
 
87057
 
87058
 
87059
 
87060
 
87061
 
87062
 
87063
 
87064
 
87065
 
87066
 
87067
 
87068
 
87069
 
87070
 
87071
 
87072
 
87073
 
87074
 
87075
 
87076
 
87077
 
87078
 
87079
 
87080
 
87081
 
87082
 
87083
 
87084
 
87085
 
87086
 
87087
 
87088
 
87089
 
87090
 
87091
 
87092
 
87093
 
87094
 
87095
 
87096
 
87097
 
87098
 
87099
 
87100
 
87101
 
87102
 
87103
 
87104
 
87105
 
87106
 
87107
 
87108
 
87109
 
87110
 
87111
 
87112
 
87113
 
87114
 
87115
 
87116
 
87117
 
87118
 
87119
 
87120
 
87121
 
87122
 
87123
 
87124
 
87125
 
87126
 
87127
 
87128
 
87129
 
87130
 
87131
 
87132
 
87133
 
87134
 
87135
 
87136
 
87137
 
87138
 
87139
 
87140
 
87141
 
87142
 
87143
 
87144
 
87145
 
87146
 
87147
 
87148
 
87149
 
87150
 
87151
 
87152
 
87153
 
87154
 
87155
 
87156
 
87157
 
87158
 
87159
 
87160
 
87161
 
87162
 
87163
 
87164
 
87165
 
87166
 
87167
 
87168
 
87169
 
87170
 
87171
 
87172
 
87173
 
87174
 
87175
 
87176
 
87177
 
87178
 
87179
 
87180
 
87181
 
87182
 
87183
 
87184
 
87185
 
87186
 
87187
 
87188
 
87189
 
87190
 
87191
 
87192
 
87193
 
87194
 
87195
 
87196
 
87197
 
87198
 
87199
 
87200
 
87201
 
87202
 
87203
 
87204
 
87205
 
87206
 
87207
 
87208
 
87209
 
87210
 
87211
 
87212
 
87213
 
87214
 
87215
 
87216
 
87217
 
87218
 
87219
 
87220
 
87221
 
87222
 
87223
 
87224
 
87225
 
87226
 
87227
 
87228
 
87229
 
87230
 
87231
 
87232
 
87233
 
87234
 
87235
 
87236
 
87237
 
87238
 
87239
 
87240
 
87241
 
87242
 
87243
 
87244
 
87245
 
87246
 
87247
 
87248
 
87249
 
87250
 
87251
 
87252
 
87253
 
87254
 
87255
 
87256
 
87257
 
87258
 
87259
 
87260
 
87261
 
87262
 
87263
 
87264
 
87265
 
87266
 
87267
 
87268
 
87269
 
87270
 
87271
 
87272
 
87273
 
87274
 
87275
 
87276
 
87277
 
87278
 
87279
 
87280
 
87281
 
87282
 
87283
 
87284
 
87285
 
87286
 
87287
 
87288
 
87289
 
87290
 
87291
 
87292
 
87293
 
87294
 
87295
 
87296
 
87297
 
87298
 
87299
 
87300
 
87301
 
87302
 
87303
 
87304
 
87305
 
87306
 
87307
 
87308
 
87309
 
87310
 
87311
 
87312
 
87313
 
87314
 
87315
 
87316
 
87317
 
87318
 
87319
 
87320
 
87321
 
87322
 
87323
 
87324
 
87325
 
87326
 
87327
 
87328
 
87329
 
87330
 
87331
 
87332
 
87333
 
87334
 
87335
 
87336
 
87337
 
87338
 
87339
 
87340
 
87341
 
87342
 
87343
 
87344
 
87345
 
87346
 
87347
 
87348
 
87349
 
87350
 
87351
 
87352
 
87353
 
87354
 
87355
 
87356
 
87357
 
87358
 
87359
 
87360
 
87361
 
87362
 
87363
 
87364
 
87365
 
87366
 
87367
 
87368
 
87369
 
87370
 
87371
 
87372
 
87373
 
87374
 
87375
 
87376
 
87377
 
87378
 
87379
 
87380
 
87381
 
87382
 
87383
 
87384
 
87385
 
87386
 
87387
 
87388
 
87389
 
87390
 
87391
 
87392
 
87393
 
87394
 
87395
 
87396
 
87397
 
87398
 
87399
 
87400
 
87401
 
87402
 
87403
 
87404
 
87405
 
87406
 
87407
 
87408
 
87409
 
87410
 
87411
 
87412
 
87413
 
87414
 
87415
 
87416
 
87417
 
87418
 
87419
 
87420
 
87421
 
87422
 
87423
 
87424
 
87425
 
87426
 
87427
 
87428
 
87429
 
87430
 
87431
 
87432
 
87433
 
87434
 
87435
 
87436
 
87437
 
87438
 
87439
 
87440
 
87441
 
87442
 
87443
 
87444
 
87445
 
87446
 
87447
 
87448
 
87449
 
87450
 
87451
 
87452
 
87453
 
87454
 
87455
 
87456
 
87457
 
87458
 
87459
 
87460
 
87461
 
87462
 
87463
 
87464
 
87465
 
87466
 
87467
 
87468
 
87469
 
87470
 
87471
 
87472
 
87473
 
87474
 
87475
 
87476
 
87477
 
87478
 
87479
 
87480
 
87481
 
87482
 
87483
 
87484
 
87485
 
87486
 
87487
 
87488
 
87489
 
87490
 
87491
 
87492
 
87493
 
87494
 
87495
 
87496
 
87497
 
87498
 
87499
 
87500
 
87501
 
87502
 
87503
 
87504
 
87505
 
87506
 
87507
 
87508
 
87509
 
87510
 
87511
 
87512
 
87513
 
87514
 
87515
 
87516
 
87517
 
87518
 
87519
 
87520
 
87521
 
87522
 
87523
 
87524
 
87525
 
87526
 
87527
 
87528
 
87529
 
87530
 
87531
 
87532
 
87533
 
87534
 
87535
 
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
#######################################################################################
# GEF - Multi-Architecture GDB Enhanced Features for Exploiters & Reverse-Engineers
#   * Original: by @_hugsy_
#   * Improvement: by @bata_24
#
#######################################################################################
# This GEF solely supports GDB compiled with Python3 and running on Linux.
#
# Supported architecture is following (some architectures require qemu).
#   * x86-32 & x86-64
#   * arm v5,v6,v7
#   * aarch64 (armv8)
#   * mips & mipsn32 & mips64
#   * powerpc & powerpc64
#   * sparc & sparc32plus & sparc64
#   * riscv32 & riscv64
#   * s390x
#   * sh4
#   * m68k
#   * alpha
#   * hppa32 (pa-risc)
#   * or1k (openrisc)
#   * nios2
#   * microblaze
#   * xtensa
#   * cris
#   * loongarch64
#   * arc32 (v2, v3) & arc64
#   * csky
# See README.md for details.
#
# To start: in gdb, type `source /path/to/gef.py`
#
#######################################################################################
# gef is distributed under the MIT License (MIT)
#
# Copyright (c) 2021-2024 bata24 (@bata_24)
#
# This is a fork of GEF (https://github.com/hugsy/gef).
# This software is released under the MIT license.
# See https://opensource.org/licenses/MIT
#
# Copyright (c) 2013-2024 crazy rabbidz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
#######################################################################################
# Use this command when check by vulture
# vulture gef.py --ignore-names="*Command"
#
#######################################################################################
# Use this command when check by ruff
# ruff check gef.py --select B,C4,E,F --ignore C409,E402,E501,E731
#
# C409: Unnecessary `list` literal passed to `tuple()`
#   -> If the argument type is str or int, it must be list before.
# E402: module level import not at top of file
#   -> For faster startup speed, debug modules are loaded when needed.
# E501: line too long (> 79 characters)
#   -> I consider this rule to be nonsense in modern environment.
# E731: do not assign a lambda expression, use a def
#   -> It can be written more cleanly using lambdas.
#
#######################################################################################
# Use this command when check by codespell
# codespell gef.py
#


print("Loading GEF...")


import abc
import argparse
import binascii
import codecs
import collections
import configparser
import ctypes
import fcntl
import functools
import hashlib
import itertools
import os
import re
import struct
import subprocess
import sys
import tempfile
import time
import traceback


def http_get(url):
    """Basic HTTP wrapper for GET request."""
    import urllib.request
    try:
        req = urllib.request.Request(url)
        req.add_header("Cache-Control", "no-cache, no-store")
        http = urllib.request.urlopen(req, timeout=5)
        if http.getcode() != 200:
            return None
        return http.read()
    except Exception:
        return None


def update_gef(argv):
    """Try to update `gef` to the latest version."""
    gef_local = os.path.realpath(argv[0])
    hash_gef_local = hashlib.sha512(open(gef_local, "rb").read()).digest()
    gef_remote = "https://raw.githubusercontent.com/bata24/gef/dev/gef.py"
    gef_remote_data = http_get(gef_remote)
    if gef_remote_data is None:
        print("[-] Failed to get remote gef")
        return 1

    hash_gef_remote = hashlib.sha512(gef_remote_data).digest()
    if hash_gef_local == hash_gef_remote:
        print("[-] No update")
    else:
        with open(gef_local, "wb") as f:
            f.write(gef_remote_data)
        print("[+] Updated")
    return 0


try:
    import gdb
except ImportError:
    # if out of gdb, the only action allowed is to update gef.py
    if len(sys.argv) == 2 and sys.argv[1].lower() in ("--update", "--upgrade", "-u"):
        sys.exit(update_gef(sys.argv))
    print("[-] gef cannot run as standalone")
    sys.exit(0)


__gef__                     = None # keep GefCommand instance
__gef_commands__            = [] # gef command classes for registering
__gef_command_instances__   = {} # gef command instances
GCI                         = __gef_command_instances__ # short cut for debug # noqa: F841
__gef_alias_instances__     = {} # gef alias instances
GAI                         = __gef_alias_instances__ # short cut for debug # noqa: F841
current_arch                = None # keep Architecture instance

GEF_RC                      = os.getenv("GEF_RC") or os.path.join(os.getenv("HOME") or "~", ".gef.rc")
GEF_TEMP_DIR                = os.path.join(tempfile.gettempdir(), "gef")
GEF_FILEPATH                = os.path.expanduser(http_get.__code__.co_filename) # the full path of GEF
                            # note: __file__ will no longer be available from gdb 15
GEF_PROMPT                  = "gef> "
GEF_PROMPT_ON               = "\001\033[1;32m\002{:s}\001\033[0m\002".format(GEF_PROMPT)
GEF_PROMPT_OFF              = "\001\033[1;31m\002{:s}\001\033[0m\002".format(GEF_PROMPT)

GDB_MIN_VERSION             = (9, 2) # ubuntu 20.04
GDB_VERSION                 = tuple(map(int, re.search(r"(\d+)[^\d]+(\d+)", gdb.VERSION).groups()))

DEFAULT_PAGE_SIZE           = 1 << 12
DEFAULT_PAGE_SIZE_MASK_LOW  = DEFAULT_PAGE_SIZE - 1
DEFAULT_PAGE_SIZE_MASK_HIGH = ~DEFAULT_PAGE_SIZE_MASK_LOW

LEFT_ARROW                  = " <- "
RIGHT_ARROW                 = " -> "
HORIZONTAL_LINE             = "-"
VERTICAL_LINE               = "|"
BP_GLYPH                    = "*"

def perf(f): # noqa
    """Decorator wrapper to perf."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        import io
        import line_profiler
        pr = line_profiler.LineProfiler()
        pr.add_function(f)
        pr.enable()
        ret = f(*args, **kwargs)
        pr.disable()
        s = io.StringIO()
        pr.print_stats(stream=s)
        print(s.getvalue())
        return ret

    return wrapper


def cperf(f): # noqa
    """Decorator wrapper to perf."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        import cProfile
        import pstats
        import io
        pr = cProfile.Profile()
        pr.enable()
        ret = f(*args, **kwargs)
        pr.disable()
        s = io.StringIO()
        #sortby = pstats.SortKey.CUMULATIVE
        sortby = pstats.SortKey.TIME
        ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
        ps.print_stats(20)
        print(s.getvalue())
        return ret

    return wrapper


class DisplayHook:
    @staticmethod
    def pp(o, idt):
        """Makes a string for pretty print by recursively."""

        def I1(idt):
            """Adds an indent for current level."""
            return "  " * idt

        def I2(idt):
            """Adds an indent for next level."""
            return "  " * (idt + 1)

        def R1(o, idt):
            """Returns a string of the elements concatenated with comma (for list, tuple, set, ...)."""
            return ", ".join([DisplayHook.pp(x, idt + 1) for x in o])

        def R2(o, idt):
            """Returns a list of the elements with indent and comma (for list, tuple, set, ...)."""
            return [I2(idt) + DisplayHook.pp(x, idt + 1) + "," for x in o]

        def RD1(o, idt):
            """Returns a string of the elements concatenated with comma (for dict, ...)."""
            return ", ".join([DisplayHook.pp(k, idt + 1) + ": " + DisplayHook.pp(v, idt + 1) for k, v in o])

        def RD2(o, idt):
            """Returns a list of the elements with indent and comma (for dict, ...)."""
            return [I2(idt) + DisplayHook.pp(k, idt + 1) + ": " + DisplayHook.pp(v, idt + 1) + "," for k, v in o]

        def Z(s, e, o, idt):
            # Creates a string without newlines and returns it if it's short enough.
            f = s + R1(o, idt) + e
            if len(f) < width:
                return f
            # Returns a string with a newline for each element.
            f = [s] + R2(o, idt) + [I1(idt) + e]
            return "\n".join(f)

        def ZD(s, e, o, idt):
            # Creates a string without newlines and returns it if it's short enough.
            f = s + RD1(o, idt) + e
            if len(f) < width:
                return f
            # Returns a string with a newline for each element.
            f = [s] + RD2(o, idt) + [I1(idt) + e]
            return "\n".join(f)

        name = type(o).__name__
        width = GefUtil.get_terminal_size()[0] + len(I1(idt))

        if name in ("int", "long"):
            return hex(o)

        if name == "list":
            return Z("[", "]", o, idt)

        elif name == "tuple":
            return Z("(", ")", o, idt)

        elif name == "set":
            return Z("{", "}", o, idt)

        elif name == "dict":
            return ZD("{", "}", o.items(), idt)

        elif name == "dict_keys":
            return Z("dict_keys([", "])", o, idt)

        elif name == "dict_values":
            return Z("dict_values([", "])", o, idt)

        elif name == "dict_items":
            return ZD("dict_items([", "])", o, idt)

        elif name == "Zone":
            return re.sub(r"(zone_start=|zone_end=)(\d+)", lambda x:x.group(1) + hex(int(x.group(2))), str(o))

        elif name == "Table":
            f = "Table(arch={!s}, mode={!s}, table={{\n".format(repr(o.arch), repr(o.mode))
            f += "\n".join(RD2(o.table.items(), idt))
            f += "\n" + I1(idt) + "})"
            return f

        elif name == "Entry":
            f = "Entry(\n"
            f += I2(idt) + "name={!s},\n".format(repr(o.name))
            f += I2(idt) + "ret_regs={!s},\n".format(o.ret_regs)
            f += I2(idt) + "arg_regs={!s},\n".format(o.arg_regs)
            f += I2(idt) + "args_full={!s},\n".format(o.args_full)
            f += I2(idt) + "args={!s},\n".format(o.args)
            f += I1(idt) + ")"
            return f
        return repr(o)

    @staticmethod
    def displayhook(o): # noqa
        __builtins__._ = o # noqa

        if o is None:
            return

        out = DisplayHook.pp(o, 0)
        print(out)
        return


def hexon(): # noqa
    sys.displayhook = DisplayHook.displayhook # noqa
    return


def hexoff(): # noqa
    sys.displayhook = sys.__displayhook__ # noqa
    return


class Cache:
    __gef_caches__ = {
        "until_next": {},
        "this_session": {},
    }
    cached_context_legend = None
    cached_heap_base = None
    cached_main_arena = None

    @staticmethod
    def cache_until_next(f):
        """Decorator for short-term caching until si or ni is executed."""

        LIFE_TIME = "until_next"

        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            kw = tuple(kwargs.items())
            _id = id(f)

            try:
                return Cache.__gef_caches__[LIFE_TIME][f.__name__, _id][args, kw]
            except KeyError:
                ret = f(*args, **kwargs)
                if (f.__name__, _id) not in Cache.__gef_caches__[LIFE_TIME]:
                    Cache.__gef_caches__[LIFE_TIME][f.__name__, _id] = {}
                Cache.__gef_caches__[LIFE_TIME][f.__name__, _id][args, kw] = ret
                return ret

        return wrapper

    @staticmethod
    def cache_this_session(f):
        """Decorator for long-term caching for the duration of the session."""

        LIFE_TIME = "this_session"

        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            kw = tuple(kwargs.items())
            _id = id(f)

            try:
                return Cache.__gef_caches__[LIFE_TIME][f.__name__, _id][args, kw]
            except KeyError:
                ret = f(*args, **kwargs)
                if (f.__name__, _id) not in Cache.__gef_caches__[LIFE_TIME]:
                    Cache.__gef_caches__[LIFE_TIME][f.__name__, _id] = {}
                Cache.__gef_caches__[LIFE_TIME][f.__name__, _id][args, kw] = ret
                return ret

        return wrapper

    @staticmethod
    def reset_gef_caches(function=None, all=False):
        if function:
            for v in Cache.__gef_caches__.values():
                try:
                    del v[function.__name__, id(function)]
                except KeyError:
                    pass
            return

        Cache.__gef_caches__["until_next"] = {}

        if all:
            Cache.__gef_caches__["this_session"] = {}

        if all:
            Cache.cached_context_legend = None
            Cache.cached_main_arena = None
            Cache.cached_heap_base = None
        return


class Config:
    __gef_config__ = {} # keep gef configs
    __gef_config_orig__ = {} # for debugging

    @staticmethod
    @Cache.cache_until_next
    def get_gef_setting(name):
        """Read global gef settings.
        Return None if not found. A valid config setting can never return None, but False, 0 or ""."""
        setting = Config.__gef_config__.get(name, None)
        if not setting:
            return None
        return setting[0]

    @staticmethod
    def set_gef_setting(name, value, _type=None, _desc=None):
        """Set global gef settings.
        Raise ValueError if `name` doesn't exist and `type` and `desc` are not provided."""
        Cache.reset_gef_caches()

        if name not in Config.__gef_config__:
            # create new setting
            if _type is None or _desc is None:
                raise ValueError("Setting '{}' is undefined, need to provide type and description".format(name))
            Config.__gef_config__[name] = [_type(value), _type, _desc]
            return

        # set existing setting
        func = Config.__gef_config__[name][1]
        Config.__gef_config__[name][0] = func(value)
        return


def gef_print(x="", less=False, *args, **kwargs):
    """Wrapper around print(), using string buffering feature."""
    x = HighlightCommand.highlight_text(x)

    if less:
        try:
            less = GefUtil.which("less")
        except FileNotFoundError:
            less = False

    always_no_pager = Config.get_gef_setting("gef.always_no_pager")
    pager_min_lines = Config.get_gef_setting("gef.pager_min_lines")
    if less and not always_no_pager and len(x.splitlines()) > pager_min_lines:
        if not x:
            return
        tmp_fd, tmp_path = tempfile.mkstemp(dir=GEF_TEMP_DIR, suffix=".txt", prefix="gef_print_")
        os.fdopen(tmp_fd, "wb").write(String.str2bytes(x))
        os.system("{:s} -Rf {:s}".format(less, tmp_path))

        keep_pager_result = Config.get_gef_setting("gef.keep_pager_result")
        if keep_pager_result:
            print("result saved at {:s}".format(tmp_path))
        else:
            os.unlink(tmp_path)
    else:
        print(x, *args, **kwargs)
    return


class Color:
    """Used to colorify terminal output."""

    # https://en.wikipedia.org/wiki/ANSI_escape_code
    colors = {
        "normal"               : "\033[0m",

        "bold"                 : "\033[1m",
        "bold_off"             : "\033[21m",
        "highlight"            : "\033[2m",
        "highlight_off"        : "\033[22m",
        "italic"               : "\033[3m",
        "italic_off"           : "\033[23m",
        "underline"            : "\033[4m",
        "underline_off"        : "\033[24m",
        "blink"                : "\033[5m",
        "blink_off"            : "\033[25m",

        "black"                : "\033[30m",
        "red"                  : "\033[31m",
        "green"                : "\033[32m",
        "yellow"               : "\033[33m",
        "blue"                 : "\033[34m",
        "magenta"              : "\033[35m",
        "cyan"                 : "\033[36m",

        "bright_black"         : "\033[90m",
        "bright_red"           : "\033[91m",
        "bright_green"         : "\033[92m",
        "bright_yellow"        : "\033[93m",
        "bright_blue"          : "\033[94m",
        "bright_magenta"       : "\033[95m",
        "bright_cyan"          : "\033[96m",
        "bright_white"         : "\033[97m",

        "coral_red"            : "\033[38;2;239;133;125m",
        "sunshine_yellow"      : "\033[38;2;255;237;171m",
        "ice_green"            : "\033[38;2;163;214;204m",
        "wistaria"             : "\033[38;2;141;147;200m",
        "pink_almond"          : "\033[38;2;227;172;174m",
        "poppy_red"            : "\033[38;2;234;85;80m",
        "cream_yellow"         : "\033[38;2;255;243;184m",
        "turquoise_green"      : "\033[38;2;0;148;122m",
        "blue_lavender"        : "\033[38;2;164;168;212m",
        "rose_dust"            : "\033[38;2;230;192;192m",
        "_red"                 : "\033[38;2;234;85;80m",
        "naples_yellow"        : "\033[38;2;253;211;92m",
        "sea_green"            : "\033[38;2;0;172;151m",
        "pannsy"               : "\033[38;2;77;67;152m",
        "white"                : "\033[38;2;255;255;255m",
        "tomato_red"           : "\033[38;2;234;85;73m",
        "topaz"                : "\033[38;2;233;188;0m",
        "peppermint_green"     : "\033[38;2;0;172;154m",
        "violet"               : "\033[38;2;90;68;152m",
        "snow_white"           : "\033[38;2;250;253;255m",
        "vermilion"            : "\033[38;2;234;85;58m",
        "chrome_yellow"        : "\033[38;2;252;200;0m",
        "peacock_green"        : "\033[38;2;0;164;151m",
        "heliotrope"           : "\033[38;2;144;121;182m",
        "pink_white"           : "\033[38;2;254;249;251m",
        "scarlet"              : "\033[38;2;234;85;50m",
        "cream"                : "\033[38;2;227;215;163m",
        "nile_blue"            : "\033[38;2;44;180;173m",
        "deep_royal_purple"    : "\033[38;2;71;38;110m",
        "milky_white"          : "\033[38;2;255;255;249m",
        "carrot_orange"        : "\033[38;2;237;109;53m",
        "straw"                : "\033[38;2;236;224;147m",
        "saxe_blue"            : "\033[38;2;65;139;137m",
        "grape"                : "\033[38;2;86;37;110m",
        "amber_white"          : "\033[38;2;255;249;245m",
        "chinese_red"          : "\033[38;2;237;109;70m",
        "jasmine_yellow"       : "\033[38;2;237;222;123m",
        "slate_green"          : "\033[38;2;60;113;112m",
        "mauve"                : "\033[38;2;145;93;163m",
        "lavender_ice"         : "\033[38;2;247;246;251m",
        "terracotta"           : "\033[38;2;189;104;86m",
        "antique_gold"         : "\033[38;2;193;171;5m",
        "teal_green"           : "\033[38;2;0;106;108m",
        "iris"                 : "\033[38;2;199;165;204m",
        "pearl_white"          : "\033[38;2;247;246;245m",
        "cocoa_brown"          : "\033[38;2;152;96;94m",
        "olive"                : "\033[38;2;114;100;12m",
        "aqua_green"           : "\033[38;2;136;191;191m",
        "lilac"                : "\033[38;2;209;186;218m",
        "ivory"                : "\033[38;2;248;244;230m",
        "mahogany"             : "\033[38;2;107;63;49m",
        "olive_drab"           : "\033[38;2;102;90;26m",
        "aquamarine"           : "\033[38;2;103;181;183m",
        "lavender"             : "\033[38;2;202;184;217m",
        "powder_pink"          : "\033[38;2;245;236;244m",
        "chocolate"            : "\033[38;2;108;53;36m",
        "jaune_brillant"       : "\033[38;2;255;220;0m",
        "peacock_blue"         : "\033[38;2;0;158;159m",
        "crocus"               : "\033[38;2;183;159;203m",
        "silver_white"         : "\033[38;2;239;239;239m",
        "marron"               : "\033[38;2;106;25;23m",
        "_yellow"              : "\033[38;2;255;220;0m",
        "turquoise"            : "\033[38;2;0;155;159m",
        "lavender_mauve"       : "\033[38;2;166;136;189m",
        "frosty_gray"          : "\033[38;2;232;236;233m",
        "sepia"                : "\033[38;2;98;45;24m",
        "citrus"               : "\033[38;2;237;220;68m",
        "capri_blue"           : "\033[38;2;0;163;167m",
        "purple"               : "\033[38;2;155;114;176m",
        "silver_pink"          : "\033[38;2;238;234;236m",
        "coffee"               : "\033[38;2;123;85;68m",
        "limelight"            : "\033[38;2;255;247;153m",
        "cambridge_blue"       : "\033[38;2;37;183;192m",
        "royal_purple"         : "\033[38;2;127;17;132m",
        "beige_cameo"          : "\033[38;2;238;233;230m",
        "brown"                : "\033[38;2;143;101;82m",
        "canary_yellow"        : "\033[38;2;255;244;98m",
        "turquoise_blue"       : "\033[38;2;0;175;204m",
        "raisin"               : "\033[38;2;107;57;95m",
        "ecru"                 : "\033[38;2;238;231;224m",
        "burnt_sienna"         : "\033[38;2;187;85;53m",
        "mimosa"               : "\033[38;2;255;244;98m",
        "horizon_blue"         : "\033[38;2;130;205;221m",
        "plum"                 : "\033[38;2;108;36;99m",
        "pink_beige"           : "\033[38;2;237;228;225m",
        "amber_rose"           : "\033[38;2;230;191;178m",
        "lemon_yellow"         : "\033[38;2;255;243;82m",
        "summer_shower"        : "\033[38;2;161;216;226m",
        "raspberry"            : "\033[38;2;132;26;117m",
        "frosty_white"         : "\033[38;2;230;234;230m",
        "beige_rose"           : "\033[38;2;232;211;202m",
        "melon_yellow"         : "\033[38;2;224;222;148m",
        "_horizon_blue"        : "\033[38;2;161;216;230m",
        "framboise"            : "\033[38;2;154;13;124m",
        "oyster_white"         : "\033[38;2;234;232;225m",
        "salmon_pink"          : "\033[38;2;243;166;140m",
        "chartreuse_yellow"    : "\033[38;2;227;229;72m",
        "cerulean_blue"        : "\033[38;2;0;141;183m",
        "dahlia_purple"        : "\033[38;2;165;0;130m",
        "wisteria_mist"        : "\033[38;2;211;214;221m",
        "sahara"               : "\033[38;2;226;150;118m",
        "lime_yellow"          : "\033[38;2;234;238;162m",
        "duck_blue"            : "\033[38;2;0;113;153m",
        "orchid_purple"        : "\033[38;2;175;0;130m",
        "cloud"                : "\033[38;2;212;217;223m",
        "ash_rose"             : "\033[38;2;230;191;171m",
        "lime_green"           : "\033[38;2;230;235;148m",
        "marine_blue"          : "\033[38;2;0;104;136m",
        "raspberry_red"        : "\033[38;2;159;22;106m",
        "moon_gray"            : "\033[38;2;212;217;220m",
        "shell_pink"           : "\033[38;2;251;218;200m",
        "chartreuse_green"     : "\033[38;2;217;227;103m",
        "madonna_blue"         : "\033[38;2;0;96;141m",
        "orchid"               : "\033[38;2;217;170;205m",
        "china_clay"           : "\033[38;2;212;220;211m",
        "baby_pink"            : "\033[38;2;253;237;228m",
        "lettuce_green"        : "\033[38;2;209;222;76m",
        "egyptian_blue"        : "\033[38;2;0;115;168m",
        "lilla"                : "\033[38;2;224;181;211m",
        "sand_beige"           : "\033[38;2;220;214;210m",
        "nail_pink"            : "\033[38;2;252;228;214m",
        "olive_green"          : "\033[38;2;95;101;39m",
        "baby_blue"            : "\033[38;2;187;226;241m",
        "rose_tendre"          : "\033[38;2;230;175;207m",
        "orchid_mist"          : "\033[38;2;211;211;216m",
        "raw_sienna"           : "\033[38;2;225;123;52m",
        "moss_green"           : "\033[38;2;119;126;65m",
        "sky_blue"             : "\033[38;2;160;216;239m",
        "orchid_pink"          : "\033[38;2;218;129;178m",
        "reed_gray"            : "\033[38;2;212;217;214m",
        "caramel"              : "\033[38;2;188;97;30m",
        "grass_green"          : "\033[38;2;123;141;66m",
        "shadow_blue"          : "\033[38;2;113;155;173m",
        "cyclamen_pink"        : "\033[38;2;208;79;151m",
        "sky_gray"             : "\033[38;2;203;208;211m",
        "sunset"               : "\033[38;2;246;180;131m",
        "spring_green"         : "\033[38;2;156;187;28m",
        "_cyan"                : "\033[38;2;0;161;233m",
        "_magenta"             : "\033[38;2;228;0;127m",
        "lavender_gray"        : "\033[38;2;188;186;206m",
        "cinnamon"             : "\033[38;2;190;143;104m",
        "leaf_green"           : "\033[38;2;159;194;77m",
        "yacht_blue"           : "\033[38;2;64;158;204m",
        "bougainvillaea"       : "\033[38;2;230;47;139m",
        "silver"               : "\033[38;2;201;202;202m",
        "tan"                  : "\033[38;2;191;120;62m",
        "white_lily"           : "\033[38;2;240;246;218m",
        "chalk_blue"           : "\033[38;2;104;169;207m",
        "ruby"                 : "\033[38;2;199;0;103m",
        "pearl_gray"           : "\033[38;2;201;201;196m",
        "champagne"            : "\033[38;2;233;218;203m",
        "asparagus_green"      : "\033[38;2;219;235;196m",
        "pigeon_blue"          : "\033[38;2;136;181;211m",
        "claret"               : "\033[38;2;148;31;87m",
        "sand_gray"            : "\033[38;2;201;201;194m",
        "peach"                : "\033[38;2;251;216;181m",
        "citron_green"         : "\033[38;2;97;142;52m",
        "smoke_blue"           : "\033[38;2;164;193;215m",
        "azalee"               : "\033[38;2;216;52;115m",
        "marble_gray"          : "\033[38;2;192;197;194m",
        "cafe_au_lait"         : "\033[38;2;148;108;69m",
        "meadow_green"         : "\033[38;2;101;171;49m",
        "frosty_blue"          : "\033[38;2;187;219;243m",
        "cosmos"               : "\033[38;2;220;107;154m",
        "opal_gray"            : "\033[38;2;191;190;197m",
        "orange"               : "\033[38;2;238;120;0m",
        "apple_green"          : "\033[38;2;167;210;141m",
        "bleu_acide"           : "\033[38;2;0;110;176m",
        "lotus_pink"           : "\033[38;2;222;130;167m",
        "french_gray"          : "\033[38;2;141;160;182m",
        "apricot"              : "\033[38;2;247;185;119m",
        "ivy_green"            : "\033[38;2;87;138;61m",
        "cobalt_blue"          : "\033[38;2;0;104;183m",
        "old_orchid"           : "\033[38;2;227;173;193m",
        "mist"                 : "\033[38;2;180;174;177m",
        "amber"                : "\033[38;2;194;137;75m",
        "spinach_green"        : "\033[38;2;65;112;56m",
        "sapphire_blue"        : "\033[38;2;0;104;183m",
        "rose_mist"            : "\033[38;2;222;190;204m",
        "ash_blond"            : "\033[38;2;181;181;174m",
        "bronze"               : "\033[38;2;172;107;37m",
        "cactus"               : "\033[38;2;56;125;57m",
        "spectrum_blue"        : "\033[38;2;0;117;194m",
        "rose_dragee"          : "\033[38;2;229;193;205m",
        "fog"                  : "\033[38;2;171;177;181m",
        "vanilla"              : "\033[38;2;232;197;156m",
        "sky_green"            : "\033[38;2;190;224;194m",
        "_blue"                : "\033[38;2;0;117;194m",
        "cherry_pink"          : "\033[38;2;235;110;160m",
        "beige_gray"           : "\033[38;2;180;173;169m",
        "cork"                 : "\033[38;2;196;154;106m",
        "spearmint"            : "\033[38;2;121;192;110m",
        "zenith_blue"          : "\033[38;2;68;150;211m",
        "opera"                : "\033[38;2;233;83;136m",
        "silver_gray"          : "\033[38;2;175;175;176m",
        "burnt_umber"          : "\033[38;2;111;84;54m",
        "mint_green"           : "\033[38;2;137;201;151m",
        "heavenly_blue"        : "\033[38;2;104;164;217m",
        "rose_red"             : "\033[38;2;234;97;142m",
        "storm_gray"           : "\033[38;2;170;170;176m",
        "raw_umber"            : "\033[38;2;134;102;41m",
        "parrot_green"         : "\033[38;2;55;163;74m",
        "orchid_gray"          : "\033[38;2;188;199;215m",
        "old_lilac"            : "\033[38;2;176;119;140m",
        "green_fog"            : "\033[38;2;171;177;173m",
        "flesh"                : "\033[38;2;250;208;158m",
        "summer_green"         : "\033[38;2;0;153;68m",
        "powder_blue"          : "\033[38;2;188;205;219m",
        "cocoa"                : "\033[38;2;110;74;85m",
        "ash_gray"             : "\033[38;2;159;160;158m",
        "golden_yellow"        : "\033[38;2;246;174;84m",
        "opal_green"           : "\033[38;2;190;224;206m",
        "light_blue"           : "\033[38;2;178;203;228m",
        "wine_red"             : "\033[38;2;179;62;92m",
        "rose_gray"            : "\033[38;2;157;142;135m",
        "mandarin_orange"      : "\033[38;2;243;152;29m",
        "spray_green"          : "\033[38;2;164;213;189m",
        "_baby_blue"           : "\033[38;2;162;194;230m",
        "garnet"               : "\033[38;2;148;35;67m",
        "elephant_skin"        : "\033[38;2;159;159;152m",
        "marigold"             : "\033[38;2;243;152;0m",
        "bottle_green"         : "\033[38;2;0;77;37m",
        "day_dream"            : "\033[38;2;163;185;224m",
        "cochineal_red"        : "\033[38;2;200;44;85m",
        "battleship_gray"      : "\033[38;2;137;137;137m",
        "ecru_beige"           : "\033[38;2;246;229;204m",
        "cobalt_green"         : "\033[38;2;60;179;122m",
        "salvia_blue"          : "\033[38;2;148;173;218m",
        "strawberry"           : "\033[38;2;231;53;98m",
        "stone_gray"           : "\033[38;2;137;136;128m",
        "oyster"               : "\033[38;2;234;225;207m",
        "evergreen"            : "\033[38;2;0;152;79m",
        "hyacinth_blue"        : "\033[38;2;122;153;207m",
        "ruby_red"             : "\033[38;2;231;53;98m",
        "moss_gray"            : "\033[38;2;126;131;127m",
        "ochre"                : "\033[38;2;186;139;64m",
        "malachite_green"      : "\033[38;2;0;152;84m",
        "hyacinth"             : "\033[38;2;108;155;210m",
        "carmine"              : "\033[38;2;215;0;53m",
        "dove_gray"            : "\033[38;2;125;123;131m",
        "khaki"                : "\033[38;2;197;160;90m",
        "_green"               : "\033[38;2;0;169;96m",
        "midnight_blue"        : "\033[38;2;0;30;67m",
        "signal_red"           : "\033[38;2;232;56;61m",
        "gray"                 : "\033[38;2;125;125;125m",
        "buff"                 : "\033[38;2;202;172;113m",
        "emerald_green"        : "\033[38;2;0;169;104m",
        "navy_blue"            : "\033[38;2;32;47;85m",
        "burgundy"             : "\033[38;2;108;39;53m",
        "steel_gray"           : "\033[38;2;115;109;113m",
        "saffron_yellow"       : "\033[38;2;250;197;89m",
        "forest_green"         : "\033[38;2;40;140;102m",
        "prussian_blue"        : "\033[38;2;25;47;96m",
        "bordeaux"             : "\033[38;2;108;39;45m",
        "ivy_gray"             : "\033[38;2;102;108;103m",
        "pumpkin"              : "\033[38;2;229;163;35m",
        "viridian"             : "\033[38;2;0;136;90m",
        "iron_blue"            : "\033[38;2;25;47;96m",
        "camellia"             : "\033[38;2;218;83;110m",
        "slate_gray"           : "\033[38;2;98;96;99m",
        "yellow_ocher"         : "\033[38;2;196;151;47m",
        "holly_green"          : "\033[38;2;0;105;72m",
        "indigo"               : "\033[38;2;4;60;120m",
        "rose"                 : "\033[38;2;233;84;100m",
        "graphite"             : "\033[38;2;89;78;82m",
        "blond"                : "\033[38;2;242;213;138m",
        "billiard_green"       : "\033[38;2;0;92;66m",
        "ink_blue"             : "\033[38;2;0;63;142m",
        "rose_pink"            : "\033[38;2;241;156;167m",
        "charcoal_gray"        : "\033[38;2;78;69;74m",
        "beige"                : "\033[38;2;238;220;179m",
        "chrome_green"         : "\033[38;2;0;83;63m",
        "oriental_blue"        : "\033[38;2;38;73;157m",
        "pink"                 : "\033[38;2;245;178;178m",
        "taupe"                : "\033[38;2;80;73;70m",
        "biscuit"              : "\033[38;2;234;215;164m",
        "antique_green"        : "\033[38;2;84;145;127m",
        "ultramarine_blue"     : "\033[38;2;71;83;162m",
        "flamingo_pink"        : "\033[38;2;245;178;172m",
        "lamp_black"           : "\033[38;2;36;20;14m",
        "leghorn"              : "\033[38;2;255;233;169m",
        "water_green"          : "\033[38;2;165;201;193m",
        "ultramarine"          : "\033[38;2;67;77;162m",
        "old_rose"             : "\033[38;2;226;147;153m",
        "_black"               : "\033[38;2;0;0;0m",

        "__black"              : "\033[38;2;0;0;0m",
        "aliceblue"            : "\033[38;2;240;248;255m",
        "darkcyan"             : "\033[38;2;0;139;139m",
        "lightyellow"          : "\033[38;2;255;255;224m",
        "coral"                : "\033[38;2;255;127;80m",
        "dimgray"              : "\033[38;2;105;105;105m",
        "_lavender"            : "\033[38;2;230;230;250m",
        "teal"                 : "\033[38;2;0;128;128m",
        "lightgoldenrodyellow" : "\033[38;2;250;250;210m",
        "tomato"               : "\033[38;2;255;99;71m",
        "_gray"                : "\033[38;2;128;128;128m",
        "lightsteelblue"       : "\033[38;2;176;196;222m",
        "darkslategray"        : "\033[38;2;47;79;79m",
        "lemonchiffon"         : "\033[38;2;255;250;205m",
        "orangered"            : "\033[38;2;255;69;0m",
        "darkgray"             : "\033[38;2;169;169;169m",
        "lightslategray"       : "\033[38;2;119;136;153m",
        "darkgreen"            : "\033[38;2;0;100;0m",
        "wheat"                : "\033[38;2;245;222;179m",
        "__red"                : "\033[38;2;255;0;0m",
        "_silver"              : "\033[38;2;192;192;192m",
        "slategray"            : "\033[38;2;112;128;144m",
        "__green"              : "\033[38;2;0;128;0m",
        "burlywood"            : "\033[38;2;222;184;135m",
        "crimson"              : "\033[38;2;220;20;60m",
        "lightgray"            : "\033[38;2;211;211;211m",
        "steelblue"            : "\033[38;2;70;130;180m",
        "forestgreen"          : "\033[38;2;34;139;34m",
        "_tan"                 : "\033[38;2;210;180;140m",
        "mediumvioletred"      : "\033[38;2;199;21;133m",
        "gainsboro"            : "\033[38;2;220;220;220m",
        "royalblue"            : "\033[38;2;65;105;225m",
        "seagreen"             : "\033[38;2;46;139;87m",
        "_khaki"               : "\033[38;2;240;230;140m",
        "deeppink"             : "\033[38;2;255;20;147m",
        "whitesmoke"           : "\033[38;2;245;245;245m",
        "midnightblue"         : "\033[38;2;25;25;112m",
        "mediumseagreen"       : "\033[38;2;60;179;113m",
        "__yellow"             : "\033[38;2;255;255;0m",
        "hotpink"              : "\033[38;2;255;105;180m",
        "__white"              : "\033[38;2;255;255;255m",
        "navy"                 : "\033[38;2;0;0;128m",
        "mediumaquamarine"     : "\033[38;2;102;205;170m",
        "gold"                 : "\033[38;2;255;215;0m",
        "palevioletred"        : "\033[38;2;219;112;147m",
        "snow"                 : "\033[38;2;255;250;250m",
        "darkblue"             : "\033[38;2;0;0;139m",
        "darkseagreen"         : "\033[38;2;143;188;143m",
        "_orange"              : "\033[38;2;255;165;0m",
        "_pink"                : "\033[38;2;255;192;203m",
        "ghostwhite"           : "\033[38;2;248;248;255m",
        "mediumblue"           : "\033[38;2;0;0;205m",
        "_aquamarine"          : "\033[38;2;127;255;212m",
        "sandybrown"           : "\033[38;2;244;164;96m",
        "lightpink"            : "\033[38;2;255;182;193m",
        "floralwhite"          : "\033[38;2;255;250;240m",
        "__blue"               : "\033[38;2;0;0;255m",
        "palegreen"            : "\033[38;2;152;251;152m",
        "darkorange"           : "\033[38;2;255;140;0m",
        "thistle"              : "\033[38;2;216;191;216m",
        "linen"                : "\033[38;2;250;240;230m",
        "dodgerblue"           : "\033[38;2;30;144;255m",
        "lightgreen"           : "\033[38;2;144;238;144m",
        "goldenrod"            : "\033[38;2;218;165;32m",
        "__magenta"            : "\033[38;2;255;0;255m",
        "antiquewhite"         : "\033[38;2;250;235;215m",
        "cornflowerblue"       : "\033[38;2;100;149;237m",
        "springgreen"          : "\033[38;2;0;255;127m",
        "peru"                 : "\033[38;2;205;133;63m",
        "fuchsia"              : "\033[38;2;255;0;255m",
        "papayawhip"           : "\033[38;2;255;239;213m",
        "deepskyblue"          : "\033[38;2;0;191;255m",
        "mediumspringgreen"    : "\033[38;2;0;250;154m",
        "darkgoldenrod"        : "\033[38;2;184;134;11m",
        "_violet"              : "\033[38;2;238;130;238m",
        "blanchedalmond"       : "\033[38;2;255;235;205m",
        "lightskyblue"         : "\033[38;2;135;206;250m",
        "lawngreen"            : "\033[38;2;124;252;0m",
        "_chocolate"           : "\033[38;2;210;105;30m",
        "_plum"                : "\033[38;2;221;160;221m",
        "bisque"               : "\033[38;2;255;228;196m",
        "skyblue"              : "\033[38;2;135;206;235m",
        "chartreuse"           : "\033[38;2;127;255;0m",
        "sienna"               : "\033[38;2;160;82;45m",
        "_orchid"              : "\033[38;2;218;112;214m",
        "moccasin"             : "\033[38;2;255;228;181m",
        "lightblue"            : "\033[38;2;173;216;230m",
        "greenyellow"          : "\033[38;2;173;255;47m",
        "saddlebrown"          : "\033[38;2;139;69;19m",
        "mediumorchid"         : "\033[38;2;186;85;211m",
        "navajowhite"          : "\033[38;2;255;222;173m",
        "powderblue"           : "\033[38;2;176;224;230m",
        "lime"                 : "\033[38;2;0;255;0m",
        "maroon"               : "\033[38;2;128;0;0m",
        "darkorchid"           : "\033[38;2;153;50;204m",
        "peachpuff"            : "\033[38;2;255;218;185m",
        "paleturquoise"        : "\033[38;2;175;238;238m",
        "limegreen"            : "\033[38;2;50;205;50m",
        "darkred"              : "\033[38;2;139;0;0m",
        "darkviolet"           : "\033[38;2;148;0;211m",
        "mistyrose"            : "\033[38;2;255;228;225m",
        "lightcyan"            : "\033[38;2;224;255;255m",
        "yellowgreen"          : "\033[38;2;154;205;50m",
        "_brown"               : "\033[38;2;165;42;42m",
        "darkmagenta"          : "\033[38;2;139;0;139m",
        "lavenderblush"        : "\033[38;2;255;240;245m",
        "__cyan"               : "\033[38;2;0;255;255m",
        "darkolivegreen"       : "\033[38;2;85;107;47m",
        "firebrick"            : "\033[38;2;178;34;34m",
        "_purple"              : "\033[38;2;128;0;128m",
        "seashell"             : "\033[38;2;255;245;238m",
        "aqua"                 : "\033[38;2;0;255;255m",
        "olivedrab"            : "\033[38;2;107;142;35m",
        "indianred"            : "\033[38;2;205;92;92m",
        "_indigo"              : "\033[38;2;75;0;130m",
        "oldlace"              : "\033[38;2;253;245;230m",
        "_turquoise"           : "\033[38;2;64;224;208m",
        "_olive"               : "\033[38;2;128;128;0m",
        "rosybrown"            : "\033[38;2;188;143;143m",
        "darkslateblue"        : "\033[38;2;72;61;139m",
        "_ivory"               : "\033[38;2;255;255;240m",
        "mediumturquoise"      : "\033[38;2;72;209;204m",
        "darkkhaki"            : "\033[38;2;189;183;107m",
        "darksalmon"           : "\033[38;2;233;150;122m",
        "blueviolet"           : "\033[38;2;138;43;226m",
        "honeydew"             : "\033[38;2;240;255;240m",
        "darkturquoise"        : "\033[38;2;0;206;209m",
        "palegoldenrod"        : "\033[38;2;238;232;170m",
        "lightcoral"           : "\033[38;2;240;128;128m",
        "mediumpurple"         : "\033[38;2;147;112;219m",
        "mintcream"            : "\033[38;2;245;255;250m",
        "lightseagreen"        : "\033[38;2;32;178;170m",
        "cornsilk"             : "\033[38;2;255;248;220m",
        "salmon"               : "\033[38;2;250;128;114m",
        "slateblue"            : "\033[38;2;106;90;205m",
        "azure"                : "\033[38;2;240;255;255m",
        "cadetblue"            : "\033[38;2;95;158;160m",
        "_beige"               : "\033[38;2;245;245;220m",
        "lightsalmon"          : "\033[38;2;255;160;122m",
        "mediumslateblue"      : "\033[38;2;123;104;238m",
    }

    @staticmethod
    def boldify(msg):
        return Color.colorify(msg, "bold")

    @staticmethod
    def grayify(msg):
        return Color.colorify(msg, "bright_black")

    @staticmethod
    def redify(msg):
        return Color.colorify(msg, "red")

    @staticmethod
    def greenify(msg):
        return Color.colorify(msg, "green")

    @staticmethod
    def yellowify(msg):
        return Color.colorify(msg, "yellow")

    @staticmethod
    def blueify(msg):
        return Color.colorify(msg, "blue")

    @staticmethod
    def cyanify(msg):
        return Color.colorify(msg, "cyan")

    @staticmethod
    def colorify(text, attrs):
        """Color text according to the given attributes."""
        if Config.get_gef_setting("gef.disable_color") is True:
            return text

        colors = Color.colors
        msg = [colors[attr] for attr in attrs.split() if attr in colors]
        msg.append(str(text))
        if colors["bold"] in msg:
            msg.append(colors["bold_off"])
        if colors["highlight"] in msg:
            msg.append(colors["highlight_off"])
        if colors["italic"] in msg:
            msg.append(colors["italic_off"])
        if colors["underline"] in msg:
            msg.append(colors["underline_off"])
        if colors["blink"] in msg:
            msg.append(colors["blink_off"])
        msg.append(colors["normal"])
        return "".join(msg)

    @staticmethod
    def colorify_hex(value, attrs):
        text = "{:#x}".format(value)
        return Color.colorify(text, attrs)

    @staticmethod
    def remove_color(text):
        return re.sub(r"\x1B\[([0-9]{1,2}(;[0-9]{1,3})*)?m", "", text)


class Address:
    """GEF representation of memory addresses."""
    def __init__(self, *args, **kwargs):
        self.value = kwargs.get("value", 0)
        self.section = kwargs.get("section", None)
        self.info = kwargs.get("info", None)
        self.valid = kwargs.get("valid", True)
        return

    def __repr__(self):
        return '<{:s}.{:s} object at {:#x}, addr={:#x}, section={}, info={}, valid={}>'.format(
            self.__module__, self.__class__.__name__, id(self),
            self.value, bool(self.section), bool(self.section), bool(self.valid),
        )
    def __str__(self):
        value = AddressUtil.format_address(self.value)
        if not self.valid:
            return value
        line_color = ""
        if self.is_in_stack_segment():
            line_color = Config.get_gef_setting("theme.address_stack")
        elif self.is_in_heap_segment():
            line_color = Config.get_gef_setting("theme.address_heap")
        elif self.is_in_text_segment():
            line_color = Config.get_gef_setting("theme.address_code")
        elif self.is_in_writable():
            line_color = Config.get_gef_setting("theme.address_writable")
        elif self.is_in_readonly():
            line_color = Config.get_gef_setting("theme.address_readonly")
        elif self.is_valid_but_none():
            line_color = Config.get_gef_setting("theme.address_valid_but_none")
        if self.is_rwx():
            line_color += " " + Config.get_gef_setting("theme.address_rwx")
        return Color.colorify(value, line_color)

    def long_fmt(self):
        value = AddressUtil.format_address(self.value, long_fmt=True)
        if not self.valid:
            return value
        line_color = ""
        if self.is_in_stack_segment():
            line_color = Config.get_gef_setting("theme.address_stack")
        elif self.is_in_heap_segment():
            line_color = Config.get_gef_setting("theme.address_heap")
        elif self.is_in_text_segment():
            line_color = Config.get_gef_setting("theme.address_code")
        elif self.is_in_writable():
            line_color = Config.get_gef_setting("theme.address_writable")
        elif self.is_in_readonly():
            line_color = Config.get_gef_setting("theme.address_readonly")
        elif self.is_valid_but_none():
            line_color = Config.get_gef_setting("theme.address_valid_but_none")
        if self.is_rwx():
            line_color += " " + Config.get_gef_setting("theme.address_rwx")
        return Color.colorify(value, line_color)

    def is_rwx(self):
        if self.section is None:
            return False
        r = hasattr(self.section, "is_readable") and self.section.is_readable()
        w = hasattr(self.section, "is_writable") and self.section.is_writable()
        x = hasattr(self.section, "is_executable") and self.section.is_executable()
        return r and w and x

    def is_in_stack_segment(self):
        if self.section is None:
            return False
        return hasattr(self.section, "path") and self.section.path.startswith("[stack]")

    def is_in_heap_segment(self):
        if self.section is None:
            return False
        return hasattr(self.section, "path") and self.section.path.startswith("[heap]")

    def is_in_text_segment(self):
        if self.section is None:
            return False
        a = hasattr(self.info, "name") and ".text" in self.info.name
        e = hasattr(self.section, "is_executable") and self.section.is_executable()
        return a or e

    def is_in_writable(self):
        if self.section is None:
            return False
        w = hasattr(self.section, "is_writable") and self.section.is_writable()
        return w

    def is_in_readonly(self):
        if self.section is None:
            return False
        r = hasattr(self.section, "is_readable") and self.section.is_readable()
        w = hasattr(self.section, "is_writable") and self.section.is_writable()
        x = hasattr(self.section, "is_executable") and self.section.is_executable()
        return r and (not w) and (not x)

    def is_valid_but_none(self):
        if self.section is None:
            return False
        r = hasattr(self.section, "is_readable") and self.section.is_readable()
        x = hasattr(self.section, "is_executable") and self.section.is_executable()
        w = hasattr(self.section, "is_writable") and self.section.is_writable()
        return (not r) and (not w) and (not x)

    def dereference(self):
        # Even if the valid flag is not set, it still dereferences.
        # This is because the valid flag is not set during kernel debugging.
        addr = AddressUtil.align_address(int(self.value))
        derefed = AddressUtil.dereference(addr)
        if derefed is None:
            return None
        return int(derefed)


class AddressUtil:
    @staticmethod
    @Cache.cache_this_session
    def ptr_width():
        void = GefUtil.cached_lookup_type("void")
        if void is None:
            uintptr_t = GefUtil.cached_lookup_type("uintptr_t")
            return uintptr_t.sizeof
        else:
            return void.pointer().sizeof

    @staticmethod
    @Cache.cache_this_session
    def get_memory_alignment(in_bits=False):
        """Try to determine the size of a pointer on this system.
        First, try to parse it out of the ELF header.
        Next, use the size of `size_t`.
        Finally, try the size of $pc.
        If `in_bits` is set to True, the result is returned in bits, otherwise in bytes."""

        if is_x86_16():
            if current_arch.A20:
                return 2 if not in_bits else 21
            else:
                return 2 if not in_bits else 20

        if is_32bit():
            return 4 if not in_bits else 32
        elif is_64bit():
            return 8 if not in_bits else 64

        res = GefUtil.cached_lookup_type("size_t")
        if res is not None:
            return res.sizeof if not in_bits else res.sizeof * 8

        try:
            return gdb.parse_and_eval("$pc").type.sizeof
        except gdb.error:
            pass
        raise EnvironmentError("GEF is running under an unsupported mode")

    @staticmethod
    def is_msb_on(addr):
        """Return whether provided address MSB is on."""
        if AddressUtil.get_memory_alignment() == 4:
            return addr & 0x80000000
        return addr & 0x8000000000000000

    @staticmethod
    def get_format_address_width(memalign_size=None):
        if not is_alive():
            return 18
        if is_32bit() or memalign_size == 4:
            return 10
        if not is_in_kernel():
            return 14
        else:
            return 18

    @staticmethod
    def format_address(addr, memalign_size=None, long_fmt=False):
        """Format the address according to its size."""
        # if qemu-xxx(32bit arch) runs on x86-64 machine, memalign_size does not match
        # AddressUtil.get_memory_alignment(), so use the value forcibly if memalign_size is not None
        if memalign_size is None:
            memalign_size = AddressUtil.get_memory_alignment()

        if isinstance(addr, str):
            addr = int(addr, 16)

        addr = AddressUtil.align_address(addr, memalign_size)
        if memalign_size == 4:
            return "{:#010x}".format(addr)
        elif memalign_size == 2:
            return "{:#06x}".format(addr)
        elif memalign_size == 2.5:
            if current_arch.A20:
                return "{:#08x}".format(addr)
            else:
                return "{:#07x}".format(addr)
        if long_fmt:
            return "{:#018x}".format(addr)
        if is_in_kernel():
            return "{:#018x}".format(addr)
        return "{:#014x}".format(addr)

    @staticmethod
    def align_address(addr, memalign_size=None):
        """Align the provided address to the process's native length."""
        # if qemu-xxx(32bit arch) runs on x86-64 machine, memalign_size does not match
        # AddressUtil.get_memory_alignment(), so use the value forcibly if memalign_size is not None
        if memalign_size is None:
            memalign_size = AddressUtil.get_memory_alignment()

        if memalign_size == 8:
            return addr & 0xFFFFFFFFFFFFFFFF
        elif memalign_size == 4:
            return addr & 0xFFFFFFFF
        elif memalign_size == 2:
            return addr & 0xFFFF
        elif memalign_size == 2.5:
            if current_arch.A20:
                return addr & 0x1FFFFF
            else:
                return addr & 0x0FFFFF
        return None

    @staticmethod
    def align_address_to_size(addr, align):
        """Align the address to the given size."""
        return addr + ((align - (addr % align)) % align)

    @staticmethod
    def parse_address(addr):
        """Parse an address and return it as an Integer."""
        if String.is_hex(addr):
            return int(addr, 16)
        return to_unsigned_long(gdb.parse_and_eval(addr))

    @staticmethod
    def parse_string_range(s):
        """Parses an address range (e.g. 0x400000-0x401000)"""
        addrs = s.split("-")
        return [int(x, 16) for x in addrs]

    @staticmethod
    @Cache.cache_until_next
    def dereference(addr):
        """GEF wrapper for gdb dereference function."""

        def use_stdtype():
            if is_32bit():
                return "uint32_t"
            elif is_64bit():
                return "uint64_t"
            return "uint16_t"

        def use_default_type():
            if is_32bit():
                return "unsigned int"
            elif is_64bit():
                return "unsigned long"
            return "unsigned short"

        def use_golang_type():
            if is_32bit():
                return "uint32"
            elif is_64bit():
                return "uint64"
            return "uint16"

        def use_rust_type():
            if is_32bit():
                return "u32"
            elif is_64bit():
                return "u64"
            return "u16"

        try:
            ulong_t = GefUtil.cached_lookup_type(use_stdtype())
            if not ulong_t:
                ulong_t = GefUtil.cached_lookup_type(use_default_type())
                if not ulong_t:
                    ulong_t = GefUtil.cached_lookup_type(use_golang_type())
                    if not ulong_t:
                        ulong_t = GefUtil.cached_lookup_type(use_rust_type())
            unsigned_long_type = ulong_t.pointer()
            res = gdb.Value(addr).cast(unsigned_long_type).dereference()
            # GDB does lazy fetch by default so we need to force access to the value
            res.fetch_lazy()
            return res
        except gdb.MemoryError:
            pass
        return None

    @staticmethod
    @Cache.cache_this_session
    def get_recursive_dereference_blacklist():
        return eval(Config.get_gef_setting("dereference.blacklist")) or []

    @staticmethod
    @Cache.cache_until_next
    def recursive_dereference(addr, phys=False):
        """Create dereference array."""

        if not is_alive():
            return [addr], None

        recursion = Config.get_gef_setting("dereference.max_recursion") or 4
        blacklist = AddressUtil.get_recursive_dereference_blacklist()
        addr_list = []
        error = None

        while recursion > 0:
            # check loop
            if addr in addr_list:
                if addr == 0 and len(addr_list) == 1:
                    # the case that address 0x0 is valid and first element is 0x0 (i.e. telescope 0x0).
                    # but no error because it is generally unnecessary information.
                    addr_list.append(addr) # use [0, 0] instead of [0]
                else:
                    error = "[loop detected]"
                break

            # not loop
            addr_list.append(addr)

            # check blacklist
            if any(bstart <= addr < bend for bstart, bend in blacklist):
                error = "[blacklist detected]"
                break

            # check non-address
            if len(addr_list) > 1 and addr < 0x100:
                break

            # goto next
            if phys and len(addr_list) == 1:
                mem = read_physmem(addr, current_arch.ptrsize)
                unpack = u32 if current_arch.ptrsize == 4 else u64
                addr = unpack(mem)
            else:
                try:
                    addr = read_int_from_memory(addr)
                except gdb.MemoryError:
                    break
            recursion -= 1

        return addr_list, error

    @staticmethod
    @Cache.cache_until_next
    def recursive_dereference_to_string(value, skip_idx=0, phys=False):
        """Create string from dereference array"""
        string_color = Config.get_gef_setting("theme.dereference_string")
        nb_max_string_length = Config.get_gef_setting("context.nb_max_string_length")
        recursion = Config.get_gef_setting("dereference.max_recursion") or 4

        # dereference
        addrs, error = AddressUtil.recursive_dereference(value, phys=phys)

        # if addrs has one element and it is address with error (e.g.: address_A -> [loop detected]),
        # don't skip the element even if skip_idx=1
        if skip_idx == 1:
            if len(addrs) == 1:
                if error == "[loop detected]":
                    skip_idx = 0

        # add "..."
        if error is None:
            if addrs[-1] > 0x100 and is_valid_addr(addrs[-1]) and recursion > 1:
                error = "..."

        # replace to string if valid
        def to_ascii(v):
            s = ""
            while v & 0xff: # \0
                if chr(v & 0xff) in String.STRING_PRINTABLE:
                    s += chr(v & 0xff)
                else:
                    return ""
                v >>= 8
            return s

        last_elem = None
        if error is None:
            s = to_ascii(addrs[-1])
            if len(s) < 2:
                pass
            elif 2 <= len(s) < current_arch.ptrsize:
                fa = AddressUtil.format_address(addrs[-1], long_fmt=True)
                last_elem = "{:s} ({:s}?)".format(fa, Color.colorify(repr(s), string_color))
                addrs = addrs[:-1]
            else: # len(s) == current_arch.ptrsize
                if len(addrs) >= 2 and is_valid_addr(addrs[-2]):
                    # read more string
                    s = read_cstring_from_memory(addrs[-2], nb_max_string_length)
                    if s:
                        fa = AddressUtil.format_address(addrs[-1], long_fmt=True)
                        last_elem = "{:s} {:s}".format(fa, Color.colorify(repr(s), string_color))
                        addrs = addrs[:-1]
                    else:
                        # Ignore when the string that do not end with a null character
                        pass
                else:
                    # fallback
                    fa = AddressUtil.format_address(addrs[-1], long_fmt=True)
                    last_elem = "{:s} ({:s}?)".format(fa, Color.colorify(repr(s), string_color))
                    addrs = addrs[:-1]

        # others
        msg = []
        for addr in addrs[skip_idx:]:
            address = ProcessMap.lookup_address(addr)
            msg.append(address.long_fmt() + Symbol.get_symbol_string(addr))

        if error:
            msg.append(error)
        elif last_elem:
            msg.append(last_elem)

        return " {:s} ".format(RIGHT_ARROW).join(msg)


class Permission:
    """GEF representation of Linux permission."""
    NONE    = 0
    READ    = 1
    WRITE   = 2
    EXECUTE = 4
    ALL     = READ | WRITE | EXECUTE

    def __init__(self, **kwargs):
        self.value = kwargs.get("value", 0)
        return

    def __repr__(self):
        return '<{:s}.{:s} object at {:#x}, perm="{}">'.format(
            self.__module__, self.__class__.__name__, id(self), str(self),
        )

    def __or__(self, value):
        return self.value | value

    def __and__(self, value):
        return self.value & value

    def __xor__(self, value):
        return self.value ^ value

    def __eq__(self, value):
        return self.value == value

    def __ne__(self, value):
        return self.value != value

    def __str__(self):
        perm_str = ""
        perm_str += "r" if self & Permission.READ else "-"
        perm_str += "w" if self & Permission.WRITE else "-"
        perm_str += "x" if self & Permission.EXECUTE else "-"
        return perm_str

    @staticmethod
    def from_process_maps(perm_str):
        perm = Permission()
        if perm_str[0] == "r":
            perm.value += Permission.READ
        if perm_str[1] == "w":
            perm.value += Permission.WRITE
        if perm_str[2] == "x":
            perm.value += Permission.EXECUTE
        return perm


class Section:
    """GEF representation of process memory sections."""
    def __init__(self, *args, **kwargs):
        self.page_start = kwargs.get("page_start")
        self.page_end = kwargs.get("page_end")
        self.offset = kwargs.get("offset", 0)
        self.permission = kwargs.get("permission")
        self.inode = kwargs.get("inode", None)
        self.path = kwargs.get("path", "")
        return

    def __repr__(self):
        return '<{:s}.{:s} object at {:#x}, page_start={:#x}, page_end={:#x}, perm="{}", path="{:s}">'.format(
            self.__module__, self.__class__.__name__, id(self), self.page_start, self.page_end,
            self.permission, self.path,
        )

    def is_readable(self):
        v = self.permission.value
        return v and bool(v & Permission.READ)

    def is_writable(self):
        v = self.permission.value
        return v and bool(v & Permission.WRITE)

    def is_executable(self):
        v = self.permission.value
        return v and bool(v & Permission.EXECUTE)

    @property
    def size(self):
        if self.page_end is None or self.page_start is None:
            return -1
        return self.page_end - self.page_start


class Elf:
    """Basic ELF parsing."""
    # e_ident[EI_MAG0:EI_MAG3]
    ELF_MAGIC                = 0x7f454c46

    # e_ident[EI_CLASS]
    ELF_CLASS_NONE           = 0
    ELF_32_BITS              = 1
    ELF_64_BITS              = 2

    # e_ident[EI_DATA]
    ELF_DATA_NONE            = 0
    LITTLE_ENDIAN            = 1
    BIG_ENDIAN               = 2

    # e_ident[EI_OSABI]
    OSABI_SYSTEMV            = 0 # UNIX System V ABI
    OSABI_HPUX               = 1 # Hewlett-Packard HP-UX
    OSABI_NETBSD             = 2 # NetBSD
    OSABI_LINUX              = 3 # GNU Linux
    OSABI_HURD               = 4 # GNU Hurd
    OSABI_86OPEN             = 5 # 86Open Common IA32 ABI
    OSABI_SOLARIS            = 6 # Sun Solaris
    OSABI_AIX                = 7 # IBM AIX
    OSABI_IRIX               = 8 # SGI Irix
    OSABI_FREEBSD            = 9 # FreeBSD
    OSABI_TRU64              = 10 # Compaq TRU64 UNIX
    OSABI_MODESTO            = 11 # Novell Modesto
    OSABI_OPENBSD            = 12 # OpenBSD
    OSABI_OPENVMS            = 13 # OpenVMS
    OSABI_NSK                = 14 # Hewlett-Packard Non-Stop Kernel
    OSABI_AROS               = 15 # Amiga Research OS
    OSABI_FENIXOS            = 16 # The FenixOS highly scalable multi-core OS
    OSABI_CLOUDABI           = 17 # Nuxi CloudABI
    OSABI_OPENVOS            = 18 # Stratus Technologies OpenVOS
    OSABI_ARM_AEABI          = 64 # ARM EABI
    OSABI_ARM                = 97 # ARM
    OSABI_STANDALONE         = 255 # Standalone (embedded) application

    # e_type
    ET_NONE                  = 0
    ET_REL                   = 1
    ET_EXEC                  = 2
    ET_DYN                   = 3
    ET_CORE                  = 4

    # e_machine
    EM_NONE                  = 0 # No machine
    EM_M32                   = 1 # AT&T WE 32100
    EM_SPARC                 = 2 # SUN SPARC
    EM_386                   = 3 # Intel 80386
    EM_68K                   = 4 # Motorola m68k family
    EM_88K                   = 5 # Motorola m88k family
    EM_IAMCU                 = 6 # Intel MCU
    EM_860                   = 7 # Intel 80860
    EM_MIPS                  = 8 # MIPS R3000 big-endian
    EM_S370                  = 9 # IBM System/370 Processor
    EM_MIPS_RS3_LE           = 10 # MIPS RS3000 Little-endian
    #                          11-14 # Reserved for future use
    EM_PARISC                = 15 # Hewlett-Packard PA-RISC
    #                          16 # Reserved for future use
    EM_VPP500                = 17 # Fujitsu VPP500
    EM_SPARC32PLUS           = 18 # Enhanced instruction set SPARC
    EM_960                   = 19 # Intel 80960
    EM_PPC                   = 20 # PowerPC
    EM_PPC64                 = 21 # 64-bit PowerPC
    EM_S390                  = 22 # IBM System/390 Processor
    EM_SPU                   = 23 # IBM SPU/SPC
    #                          24-35 # Reserved for future use
    EM_V800                  = 36 # NEC V800
    EM_FR20                  = 37 # Fujitsu FR20
    EM_RH32                  = 38 # TRW RH-32
    EM_RCE                   = 39 # Motorola RCE
    EM_ARM                   = 40 # ARM 32-bit architecture (AARCH32)
    EM_ALPHA                 = 41 # Digital Alpha
    EM_SH                    = 42 # Hitachi SH
    EM_SPARCV9               = 43 # SPARC Version 9
    EM_TRICORE               = 44 # Siemens TriCore embedded processor
    EM_ARC                   = 45 # Argonaut RISC Core, Argonaut Technologies Inc.
    EM_H8_300                = 46 # Hitachi H8/300
    EM_H8_300H               = 47 # Hitachi H8/300H
    EM_H8S                   = 48 # Hitachi H8S
    EM_H8_500                = 49 # Hitachi H8/500
    EM_IA_64                 = 50 # Intel IA-64 processor architecture
    EM_MIPS_X                = 51 # Stanford MIPS-X
    EM_COLDFIRE              = 52 # Motorola ColdFire
    EM_68HC12                = 53 # Motorola M68HC12
    EM_MMA                   = 54 # Fujitsu MMA Multimedia Accelerator
    EM_PCP                   = 55 # Siemens PCP
    EM_NCPU                  = 56 # Sony nCPU embedded RISC processor
    EM_NDR1                  = 57 # Denso NDR1 microprocessor
    EM_STARCORE              = 58 # Motorola Star*Core processor
    EM_ME16                  = 59 # Toyota ME16 processor
    EM_ST100                 = 60 # STMicroelectronics ST100 processor
    EM_TINYJ                 = 61 # Advanced Logic Corp. TinyJ embedded processor family
    EM_X86_64                = 62 # AMD x86-64 architecture
    EM_PDSP                  = 63 # Sony DSP Processor
    EM_PDP10                 = 64 # Digital Equipment Corp. PDP-10
    EM_PDP11                 = 65 # Digital Equipment Corp. PDP-11
    EM_FX66                  = 66 # Siemens FX66 microcontroller
    EM_ST9PLUS               = 67 # STMicroelectronics ST9+ 8/16 bit microcontroller
    EM_ST7                   = 68 # STMicroelectronics ST7 8-bit microcontroller
    EM_68HC16                = 69 # Motorola MC68HC16 Microcontroller
    EM_68HC11                = 70 # Motorola MC68HC11 Microcontroller
    EM_68HC08                = 71 # Motorola MC68HC08 Microcontroller
    EM_68HC05                = 72 # Motorola MC68HC05 Microcontroller
    EM_SVX                   = 73 # Silicon Graphics SVx
    EM_ST19                  = 74 # STMicroelectronics ST19 8-bit microcontroller
    EM_VAX                   = 75 # Digital VAX
    EM_CRIS                  = 76 # Axis Communications 32-bit embedded processor
    EM_JAVELIN               = 77 # Infineon Technologies 32-bit embedded processor
    EM_FIREPATH              = 78 # Element 14 64-bit DSP Processor
    EM_ZSP                   = 79 # LSI Logic 16-bit DSP Processor
    EM_MMIX                  = 80 # Donald Knuth's educational 64-bit processor
    EM_HUANY                 = 81 # Harvard University machine-independent object files
    EM_PRISM                 = 82 # SiTera Prism
    EM_AVR                   = 83 # Atmel AVR 8-bit microcontroller
    EM_FR30                  = 84 # Fujitsu FR30
    EM_D10V                  = 85 # Mitsubishi D10V
    EM_D30V                  = 86 # Mitsubishi D30V
    EM_V850                  = 87 # NEC v850
    EM_M32R                  = 88 # Mitsubishi M32R
    EM_MN10300               = 89 # Matsushita MN10300
    EM_MN10200               = 90 # Matsushita MN10200
    EM_PJ                    = 91 # picoJava
    EM_OPENRISC              = 92 # OpenRISC 32-bit embedded processor
    EM_ARC_COMPACT           = 93 # ARC International ARCompact processor (old spelling/synonym: EM_ARC_A5)
    EM_XTENSA                = 94 # Tensilica Xtensa Architecture
    EM_VIDEOCORE             = 95 # Alphamosaic VideoCore processor
    EM_TMM_GPP               = 96 # Thompson Multimedia General Purpose Processor
    EM_NS32K                 = 97 # National Semiconductor 32000 series
    EM_TPC                   = 98 # Tenor Network TPC processor
    EM_SNP1K                 = 99 # Trebia SNP 1000 processor
    EM_ST200                 = 100 # STMicroelectronics ST200 microcontroller
    EM_IP2K                  = 101 # Ubicom IP2xxx microcontroller family
    EM_MAX                   = 102 # MAX Processor
    EM_CR                    = 103 # National Semiconductor CompactRISC microprocessor
    EM_F2MC16                = 104 # Fujitsu F2MC16
    EM_MSP430                = 105 # Texas Instruments embedded microcontroller msp430
    EM_BLACKFIN              = 106 # Analog Devices Blackfin (DSP) processor
    EM_SE_C33                = 107 # S1C33 Family of Seiko Epson processors
    EM_SEP                   = 108 # Sharp embedded microprocessor
    EM_ARCA                  = 109 # Arca RISC Microprocessor
    EM_UNICORE               = 110 # Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University
    EM_EXCESS                = 111 # eXcess: 16/32/64-bit configurable embedded CPU
    EM_DXP                   = 112 # Icera Semiconductor Inc. Deep Execution Processor
    EM_ALTERA_NIOS2          = 113 # Altera Nios II soft-core processor
    EM_CRX                   = 114 # National Semiconductor CompactRISC CRX microprocessor
    EM_XGATE                 = 115 # Motorola XGATE embedded processor
    EM_C166                  = 116 # Infineon C16x/XC16x processor
    EM_M16C                  = 117 # Renesas M16C series microprocessors
    EM_DSPIC30F              = 118 # Microchip Technology dsPIC30F Digital Signal Controller
    EM_CE                    = 119 # Freescale Communication Engine RISC core
    EM_M32C                  = 120 # Renesas M32C series microprocessors
    #                          121-130 # Reserved for future use
    EM_TSK3000               = 131 # Altium TSK3000 core
    EM_RS08                  = 132 # Freescale RS08 embedded processor
    EM_SHARC                 = 133 # Analog Devices SHARC family of 32-bit DSP processors
    EM_ECOG2                 = 134 # Cyan Technology eCOG2 microprocessor
    EM_SCORE7                = 135 # Sunplus S+core7 RISC processor
    EM_DSP24                 = 136 # New Japan Radio (NJR) 24-bit DSP Processor
    EM_VIDEOCORE3            = 137 # Broadcom VideoCore III processor
    EM_LATTICEMICO32         = 138 # RISC processor for Lattice FPGA architecture
    EM_SE_C17                = 139 # Seiko Epson C17 family
    EM_TI_C6000              = 140 # The Texas Instruments TMS320C6000 DSP family
    EM_TI_C2000              = 141 # The Texas Instruments TMS320C2000 DSP family
    EM_TI_C5500              = 142 # The Texas Instruments TMS320C55x DSP family
    EM_TI_ARP32              = 143 # Texas Instruments Application Specific RISC Processor, 32bit fetch
    EM_TI_PRU                = 144 # Texas Instruments Programmable Realtime Unit
    #                          145-159 # Reserved for future use
    EM_MMDSP_PLUS            = 160 # STMicroelectronics 64bit VLIW Data Signal Processor
    EM_CYPRESS_M8C           = 161 # Cypress M8C microprocessor
    EM_R32C                  = 162 # Renesas R32C series microprocessors
    EM_TRIMEDIA              = 163 # NXP Semiconductors TriMedia architecture family
    EM_QDSP6                 = 164 # QUALCOMM DSP6 Processor
    EM_8051                  = 165 # Intel 8051 and variants
    EM_STXP7X                = 166 # STMicroelectronics STxP7x family of configurable and extensible RISC processors
    EM_NDS32                 = 167 # Andes Technology compact code size embedded RISC processor family
    EM_ECOG1                 = 168 # Cyan Technology eCOG1X family
    EM_ECOG1X                = 168 # Cyan Technology eCOG1X family
    EM_MAXQ30                = 169 # Dallas Semiconductor MAXQ30 Core Micro-controllers
    EM_XIMO16                = 170 # New Japan Radio (NJR) 16-bit DSP Processor
    EM_MANIK                 = 171 # M2000 Reconfigurable RISC Microprocessor
    EM_CRAYNV2               = 172 # Cray Inc. NV2 vector architecture
    EM_RX                    = 173 # Renesas RX family
    EM_METAG                 = 174 # Imagination Technologies META processor architecture
    EM_MCST_ELBRUS           = 175 # MCST Elbrus general purpose hardware architecture
    EM_ECOG16                = 176 # Cyan Technology eCOG16 family
    EM_CR16                  = 177 # National Semiconductor CompactRISC CR16 16-bit microprocessor
    EM_ETPU                  = 178 # Freescale Extended Time Processing Unit
    EM_SLE9X                 = 179 # Infineon Technologies SLE9X core
    EM_L10M                  = 180 # Intel L10M
    EM_K10M                  = 181 # Intel K10M
    #                          182 # Reserved for future Intel use
    EM_AARCH64               = 183 # ARM 64-bit architecture (AARCH64)
    #                          184 # Reserved for future ARM use
    EM_AVR32                 = 185 # Atmel Corporation 32-bit microprocessor family
    EM_STM8                  = 186 # STMicroeletronics STM8 8-bit microcontroller
    EM_TILE64                = 187 # Tilera TILE64 multicore architecture family
    EM_TILEPRO               = 188 # Tilera TILEPro multicore architecture family
    EM_MICROBLAZE            = 189 # Xilinx MicroBlaze 32-bit RISC soft processor core
    EM_CUDA                  = 190 # NVIDIA CUDA architecture
    EM_TILEGX                = 191 # Tilera TILE-Gx multicore architecture family
    EM_CLOUDSHIELD           = 192 # CloudShield architecture family
    EM_COREA_1ST             = 193 # KIPO-KAIST Core-A 1st generation processor family
    EM_COREA_2ND             = 194 # KIPO-KAIST Core-A 2nd generation processor family
    EM_ARCV2                 = 195 # Synopsys ARCompact V2
    EM_OPEN8                 = 196 # Open8 8-bit RISC soft processor core
    EM_RL78                  = 197 # Renesas RL78 family
    EM_VIDEOCORE5            = 198 # Broadcom VideoCore V processor
    EM_78KOR                 = 199 # Renesas 78KOR family
    EM_56800EX               = 200 # Freescale 56800EX Digital Signal Controller (DSC)
    EM_BA1                   = 201 # Beyond BA1 CPU architecture
    EM_BA2                   = 202 # Beyond BA2 CPU architecture
    EM_XCORE                 = 203 # XMOS xCORE processor family
    EM_MCHP_PIC              = 204 # Microchip 8-bit PIC(r) family
    EM_INTELGT               = 205 # Intel Graphics Technology
    EM_INTEL206              = 206 # Reserved by Intel
    EM_INTEL207              = 207 # Reserved by Intel
    EM_INTEL208              = 208 # Reserved by Intel
    EM_INTEL209              = 209 # Reserved by Intel
    EM_KM32                  = 210 # KM211 KM32 32-bit processor
    EM_KMX32                 = 211 # KM211 KMX32 32-bit processor
    EM_KMX16                 = 212 # KM211 KMX16 16-bit processor
    EM_KMX8                  = 213 # KM211 KMX8 8-bit processor
    EM_KVARC                 = 214 # KM211 KVARC processor
    EM_CDP                   = 215 # Paneve CDP architecture family
    EM_COGE                  = 216 # Cognitive Smart Memory Processor
    EM_COOL                  = 217 # Bluechip Systems CoolEngine
    EM_NORC                  = 218 # Nanoradio Optimized RISC
    EM_CSR_KALIMBA           = 219 # CSR Kalimba architecture family
    EM_Z80                   = 220 # Zilog Z80
    EM_VISIUM                = 221 # Controls and Data Services VISIUMcore processor
    EM_FT32                  = 222 # FTDI Chip FT32 high performance 32-bit RISC architecture
    EM_MOXIE                 = 223 # Moxie processor family
    EM_AMDGPU                = 224 # AMD GPU architecture
    #                          225-242 # Reserved
    EM_RISCV                 = 243 # RISC-V
    EM_LANAI                 = 244 # Lanai 32-bit processor
    EM_CEVA                  = 245 # CEVA Processor Architecture Family
    EM_CEVA_X2               = 246 # CEVA X2 Processor Family
    EM_BPF                   = 247 # Linux BPF - in-kernel virtual machine
    EM_GRAPHCORE_IPU         = 248 # Graphcore Intelligent Processing Unit
    EM_IMG1                  = 249 # Imagination Technologies
    EM_NFP                   = 250 # Netronome Flow Processor
    EM_VE                    = 251 # NEC Vector Engine
    EM_CSKY                  = 252 # C-SKY processor family
    EM_ARC_COMPACT3_64       = 253 # Synopsys ARCv2.3 64-bit
    EM_MCS6502               = 254 # MOS Technology MCS 6502 processor
    EM_ARC_COMPACT3          = 255 # Synopsys ARCv2.3 32-bit
    EM_KVX                   = 256 # Kalray VLIW core of the MPPA processor family
    EM_65816                 = 257 # WDC 65816/65C816
    EM_LOONGARCH             = 258 # LoongArch
    EM_KF32                  = 259 # ChipON KungFu32
    EM_U16_U8CORE            = 260 # LAPIS nX-U16/U8
    EM_TACHYUM               = 261 # Tachyum
    EM_56800EF               = 262 # NXP 56800EF Digital Signal Controller (DSC)

    EM_AVR_UNOFFICIAL        = 0x1057 # AVR (unofficial)
    EM_MSP430_UNOFFICIAL     = 0x1059 # MSP430 (unofficial)
    EM_EPIPHANY_UNOFFICIAL   = 0x1223 # Adapteva Epiphany (unofficial)
    EM_AVR32_UNOFFICIAL      = 0x18ad # Atmel AVR32 (unofficial)
    EM_MT_UNOFFICIAL         = 0x2530 # Morpho MT (unofficial)
    EM_FR30_UNOFFICIAL       = 0x3330 # FR30 (unofficial)
    EM_OPENRISC_OLD          = 0x3426 # OpenRISC (obsolete)
    EM_WEBASSEMBLY           = 0x4157 # Web Assembly binaries (unofficial)
    EM_C166_UNOFFICIAL       = 0x4688 # Infineon C166 (unofficial)
    EM_S12Z                  = 0x4DEF # Freescale S12Z
    EM_FRV_UNOFFICIAL        = 0x5441 # Cygnus FR-V (unofficial)
    EM_DLX_UNOFFICIAL        = 0x5aa5 # DLX (unofficial)
    EM_D10V_UNOFFICIAL       = 0x7650 # Cygnus D10V (unofficial)
    EM_D30V_UNOFFICIAL       = 0x7676 # Cygnus D30V (unofficial)
    EM_IP2K_UNOFFICIAL       = 0x8217 # Ubicom IP2xxx (unofficial)
    EM_OPENRISC_OLD2         = 0x8472 # OpenRISC (obsolete)
    EM_PPC_UNOFFICIAL        = 0x9025 # Cygnus PowerPC (unofficial)
    EM_ALPHA_UNOFFICIAL      = 0x9026 # Digital Alpha (unofficial)
    EM_M32R_UNOFFICIAL       = 0x9041 # Cygnus M32R (unofficial)
    EM_V850_UNOFFICIAL       = 0x9080 # Cygnus V859 (unofficial)
    EM_S390_OLD              = 0xa390 # IBM S/390 (obsolete)
    EM_XTENSA_UNOFFICIAL     = 0xabc7 # Old Xtensa (unofficial)
    EM_XSTORMY_UNOFFICIAL    = 0xad45 # xstormy16 (unofficial)
    EM_MICROBLAZE_UNOFFICIAL = 0xbaab # Old MicroBlaze (unofficial)
    EM_MN10300_UNOFFICIAL    = 0xbeef # Cygnus MN10300 (unofficial)
    EM_MN10200_UNOFFICIAL    = 0xdead # Cygnus MN10200 (unofficial)
    EM_MEP_UNOFFICIAL        = 0xf00d # Toshiba MeP (unofficial)
    EM_M32C_UNOFFICIAL       = 0xfeb0 # Renesas M32C (unofficial)
    EM_IQ2000_UNOFFICIAL     = 0xfeba # Vitesse IQ2000 (unofficial)
    EM_NIOS_UNOFFICIAL       = 0xfebb # NIOS (unofficial)
    EM_MOXIE_UNOFFICIAL      = 0xfeed # Moxie (unofficial)

    # e_version
    EV_NONE                  = 0
    EV_CURRENT               = 1

    # default values
    e_magic                  = ELF_MAGIC
    e_class                  = ELF_64_BITS
    e_endianness             = LITTLE_ENDIAN
    e_eiversion              = None
    e_osabi                  = None
    e_abiversion             = None
    e_pad                    = None # noqa: F841
    e_type                   = ET_EXEC
    e_machine                = EM_X86_64
    e_version                = None
    e_entry                  = 0x00
    e_phoff                  = None
    e_shoff                  = None
    e_flags                  = None
    e_ehsize                 = None
    e_phentsize              = None
    e_phnum                  = None
    e_shentsize              = None
    e_shnum                  = None
    e_shstrndx               = None

    @staticmethod
    @Cache.cache_until_next
    def get_elf(filepath=None):
        """Return an Elf object with caching."""
        return Elf(filepath)

    def __init__(self, elf=None):
        """Instantiate an ELF object."""
        if elf is None:
            elf = Path.get_filepath()
        if isinstance(elf, str):
            if not os.access(elf, os.R_OK):
                err("'{:s}' not found/readable".format(elf))
                self.e_magic = None
                return
            self.fd = open(elf, "rb")
            self.addr = None
            self.pos = 0
            self.filename = elf
        elif isinstance(elf, int):
            self.fd = None
            self.addr = elf
            self.pos = 0
            self.filename = None
        else:
            raise

        # off 0x0
        self.e_magic, self.e_class, self.e_endianness, self.e_eiversion = struct.unpack(">IBBB", self.read(7))
        # adjust endianness in bin reading
        endian = "<" if self.e_endianness == Elf.LITTLE_ENDIAN else ">"
        # off 0x7
        self.e_osabi, self.e_abiversion = struct.unpack("{}BB".format(endian), self.read(2))
        # off 0x9
        self.e_pad = self.read(7) # noqa
        # off 0x10
        self.e_type, self.e_machine, self.e_version = struct.unpack("{}HHI".format(endian), self.read(8))
        # off 0x18
        if self.e_class == Elf.ELF_64_BITS:
            self.e_entry, self.e_phoff, self.e_shoff = struct.unpack("{}QQQ".format(endian), self.read(24))
        else:
            self.e_entry, self.e_phoff, self.e_shoff = struct.unpack("{}III".format(endian), self.read(12))
        self.e_flags, self.e_ehsize, self.e_phentsize, self.e_phnum = struct.unpack("{}IHHH".format(endian), self.read(10))
        self.e_shentsize, self.e_shnum, self.e_shstrndx = struct.unpack("{}HHH".format(endian), self.read(6))

        # phdr
        self.phdrs = []
        for i in range(self.e_phnum):
            phdr = Elf.Phdr(self, self.e_phoff + self.e_phentsize * i)
            self.phdrs.append(phdr)

        # shdr
        self.shdrs = []
        for i in range(self.e_shnum):
            try:
                shdr = Elf.Shdr(self, self.e_shoff + self.e_shentsize * i)
                self.shdrs.append(shdr)
            except gdb.MemoryError:
                # Perspective failure. Probably it occurs when parsing ELF loaded into memory.
                # Even if the ELF is loaded, the section header is not loaded. Therefore, it is ignored.
                self.shdrs = []
                break
        else:
            # multiple SHT_NULLs are treated as abnormal
            if sum([x.sh_type == Elf.Shdr.SHT_NULL for x in self.shdrs]) > 1:
                self.shdrs = []

        if self.fd is not None:
            self.fd.close()
            self.fd = None

        # It will be unusable after initialization.
        self.read = None
        self.seek = None
        return

    def __repr__(self):
        if not hasattr(self, "filename"):
            msg = '<{:s}.{:s} object at {:#x}, invalid>'.format(
                self.__module__, self.__class__.__name__, id(self),
            )
        elif self.filename:
            msg = '<{:s}.{:s} object at {:#x}, filename="{:s}">'.format(
                self.__module__, self.__class__.__name__, id(self), self.filename,
            )
        else:
            msg = "<{:s}.{:s} object at {:#x}, address={:#x}>".format(
                self.__module__, self.__class__.__name__, id(self), self.addr,
            )
        return msg

    def read(self, size):
        if self.fd is not None:
            v = self.fd.read(size)
        elif self.addr is not None:
            v = read_memory(self.addr + self.pos, size)
        else:
            raise
        self.pos += size
        return v

    def seek(self, off):
        if self.fd is not None:
            self.fd.seek(off, 0)
        elif self.addr is not None:
            self.pos = off
        else:
            raise
        return

    def is_valid(self):
        return self.e_magic == Elf.ELF_MAGIC

    def get_bits(self):
        if self.e_class == Elf.ELF_64_BITS:
            return 64
        if self.e_class == Elf.ELF_32_BITS:
            return 32
        raise

    def get_phdr(self, p_type):
        for phdr in self.phdrs:
            if phdr.p_type == p_type:
                return phdr
        return None

    def get_shdr(self, name):
        for shdr in self.shdrs:
            if shdr.sh_name == name:
                return shdr
        return None

    def read_phdr(self, p_type):
        phdr = self.get_phdr(p_type)
        if phdr is None:
            return None

        if self.filename:
            fd = open(self.filename, "rb")
            fd.seek(phdr.p_offset)
            data = fd.read(phdr.p_filesz)
            fd.close()
            return data

        if self.addr:
            read_addr = phdr.p_vaddr
            if self.is_pie():
                read_addr += self.addr

            data = read_memory(read_addr, phdr.p_memsz)
            return data

        return None

    def read_shdr(self, name):
        shdr = self.get_shdr(name)
        if shdr is None:
            return None

        if self.filename:
            fd = open(self.filename, "rb")
            fd.seek(shdr.sh_offset)
            data = fd.read(shdr.sh_size)
            fd.close()
            return data

        if self.addr:
            if shdr.sh_addr > 0:
                read_addr = shdr.sh_addr
            else:
                # e.g. .comment section of vdso
                """
                [ #] Name                      Type Address Offset Size EntSiz Flags Link Info Align
                ...
                [13] .altinstr_replacement PROGBITS  0x106f 0x106f 0x3c    0x0 AX     0x0  0x0   0x1
                [14] .comment              PROGBITS     0x0 0x10ab 0x25    0x1 MS     0x0  0x0   0x1
                [15] .shstrtab               STRTAB     0x0 0x10d0 0x9e    0x0        0x0  0x0   0x1
                """
                read_addr = shdr.sh_offset

            if self.is_pie():
                read_addr += self.addr

            data = read_memory(read_addr, shdr.sh_size)
            return data

        return None

    def is_static(self):
        # note: static-pie has no PT_INTERP
        return not bool(self.get_phdr(Elf.Phdr.PT_INTERP))

    def has_dynamic(self):
        # note: static-pie has PT_DYNAMIC
        return bool(self.get_phdr(Elf.Phdr.PT_DYNAMIC))

    def is_stripped(self):
        return not bool(self.get_shdr(".symtab"))

    def has_debuginfo(self):
        return bool(self.get_shdr(".debug_info"))

    def has_canary_heuristic(self):
        try:
            objdump_command = GefUtil.which("objdump")
        except FileNotFoundError:
            return None # it means unknown

        # heuristic search
        if self.e_machine in (Elf.EM_X86_64, Elf.EM_386):
            if self.e_machine == Elf.EM_X86_64:
                kw = b"%fs:0x28"
            else: # 32-bit
                kw = b"%gs:0x14"

            proc = subprocess.Popen(
                [objdump_command, "-d", self.filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
            )
            for _ in range(0x10000):
                if kw in proc.stdout.readline():
                    proc.kill()
                    return True
            proc.kill()
            return False
        return None # it means unknown

    def is_pie(self):
        return self.e_type == Elf.ET_DYN

    def is_nx(self):
        phdr = self.get_phdr(Elf.Phdr.PT_GNU_STACK)
        if phdr:
            return not bool(phdr.p_flags & Elf.Phdr.PF_X)
        return False

    def is_relro(self):
        # both partial and full have PT_GNU_RELRO
        return bool(self.get_phdr(Elf.Phdr.PT_GNU_RELRO))

    def get_dynamic_data(self):
        # find dynamic
        phdr = self.get_phdr(Elf.Phdr.PT_DYNAMIC)
        if phdr is None:
            return None

        # read dynamic
        fd = open(self.filename, "rb")
        fd.seek(phdr.p_offset)
        data = fd.read(phdr.p_filesz)
        fd.close()

        # unpack
        data = slice_unpack(data, self.get_bits() // 8)
        return data

    def is_full_relro(self):
        data = self.get_dynamic_data()
        if data is None:
            return False

        # check
        for tag, value in slicer(data, 2):
            if tag == 0x18: # DT_BIND_NOW
                return True
            if tag == 0x1e: # DT_FLAGS
                return bool(value & 0x08) # DF_BIND_NOW
        return False

    def has_rpath(self):
        data = self.get_dynamic_data()
        if data is None:
            return False

        for tag, _ in slicer(data, 2):
            if tag == 0xf: # DT_RPATH
                return True
        return False

    def has_runpath(self):
        data = self.get_dynamic_data()
        if data is None:
            return False

        for tag, _ in slicer(data, 2):
            if tag == 0x1d: # DT_RUNPATH
                return True
        return False

    def has_pac_heuristic(self):
        pac_ops = [
            b"paciasp", b"pacia", b"pacibsp", b"pacib", b"pacda", b"pacdb", b"pacga",
            b"autiasp", b"autia", b"autibsp", b"autib", b"autda", b"autdb",
            b"retaa", b"retab", b"braa", b"brab", b"blraa", b"blrab",
            b"eretaa", b"eretab", b"ldraa", b"ldrab"
        ]

        try:
            objdump_command = GefUtil.which("objdump")
        except FileNotFoundError:
            return None # it means unknown

        proc = subprocess.Popen(
            [objdump_command, "-d", self.filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
        )
        for _ in range(0x10000):
            line = proc.stdout.readline().strip()
            if not line:
                continue
            if line.split()[-1] in pac_ops:
                proc.kill()
                return True
        proc.kill()
        return False

    def checksec(self):
        """Check the following security properties of the ELF binary.
        Canary, NX, PIE, RELRO, Fortify, Static, Symbol, Debuginfo, CET,
        RPATH/RUNPATH, and Clang CFI/SafeStack."""

        def exists_sym(dynstr, strtab, keywords):
            if dynstr:
                for kw in keywords:
                    if kw in dynstr:
                        return True
            if strtab:
                for kw in keywords:
                    if kw in strtab:
                        return True
            return False

        def get_features_from_note(note):
            note = note[0x10:] # skip header
            while note:
                pr_type, note = u32(note[:4]), note[4:]
                pr_datasz, note = u32(note[:4]), note[4:]
                pr_data, note = note[:pr_datasz], note[pr_datasz:]

                if pr_type == 0xc0000002: # GNU_PROPERTY_X86_FEATURE_1_AND
                    if pr_datasz == 4:
                        return u32(pr_data)

                pr_padding = 0
                while (pr_datasz + pr_padding) % current_arch.ptrsize:
                    pr_padding += 1
                note = note[pr_padding:]
            return 0

        dynstr = self.read_shdr(".dynstr")
        if dynstr:
            dynstr = dynstr.split(b"\0")
        strtab = self.read_shdr(".strtab")
        if strtab:
            strtab = strtab.split(b"\0")

        sec = {}

        # Static
        sec["Static"] = self.is_static()

        # Symbol
        sec["Symbol"] = not self.is_stripped()

        # Debuginfo
        sec["Debuginfo"] = self.has_debuginfo()

        # Canary
        if self.is_static() and self.is_stripped():
            sec["Canary"] = self.has_canary_heuristic()
        else:
            keywords = [
                b"__stack_chk_fail",
                b"__stack_chk_fail_local",
                b"__stack_chk_guard", # for non-x86
                b"__intel_security_cookie", # for intel compiler
            ]
            sec["Canary"] = exists_sym(dynstr, strtab, keywords)

        # NX
        sec["NX"] = self.is_nx()

        # PIE
        sec["PIE"] = self.is_pie()

        # RELRO
        sec["Partial RELRO"] = self.is_relro()
        sec["Full RELRO"] = sec["Partial RELRO"] and self.is_full_relro()

        # Fortify
        if self.is_static() and self.is_stripped():
            sec["Fortify"] = None # it means unknown
        else:
            keywords = [
                b"__memcpy_chk",
                b"__memmove_chk",
                b"__mempcpy_chk",
                b"__memset_chk",
                b"__printf_chk",
                b"__fprintf_chk",
                b"__dprintf_chk",
                b"__sprintf_chk",
                b"__asprintf_chk",
                b"__snprintf_chk",
                b"__wprintf_chk",
                b"__fwprintf_chk",
                b"__swprintf_chk",
                b"__obstack_printf_chk",
                b"__vprintf_chk",
                b"__vfprintf_chk",
                b"__vdprintf_chk",
                b"__vsprintf_chk",
                b"__vasprintf_chk",
                b"__vsnprintf_chk",
                b"__vwprintf_chk",
                b"__vfwprintf_chk",
                b"__vswprintf_chk",
                b"__obstack_vprintf_chk",
                b"__syslog_chk",
                b"__vsyslog_chk",
            ]
            sec["Fortify"] = exists_sym(dynstr, strtab, keywords)

        # CET flags via Ehdr
        if self.e_machine in (Elf.EM_X86_64, Elf.EM_386):
            sec["CET IBT flag"] = False
            sec["CET SHSTK flag"] = False
            note_gnu_property = self.read_phdr(Elf.Phdr.PT_GNU_PROPERTY)
            if note_gnu_property:
                features = get_features_from_note(note_gnu_property)
                sec["CET IBT flag"] = features & 1 # GNU_PROPERTY_X86_FEATURE_1_IBT
                sec["CET SHSTK flag"] = features & 2 # GNU_PROPERTY_X86_FEATURE_1_SHSTK

        # PAC
        if self.e_machine == Elf.EM_AARCH64:
            sec["PAC"] = self.has_pac_heuristic()

        # RPATH
        sec["RPATH"] = self.has_rpath()

        # RUNPATH
        sec["RUNPATH"] = self.has_runpath()

        # Clang CFI (detected only when `-fno-sanitize-trap=all`)
        if self.is_static() and self.is_stripped():
            sec["Clang CFI"] = None
        else:
            sec["Clang CFI"] = exists_sym(dynstr, strtab, ["__ubsan_handle_cfi_"])

        # Clang SafeStack
        if self.is_static() and self.is_stripped():
            sec["Clang SafeStack"] = None
        else:
            sec["Clang SafeStack"] = exists_sym(dynstr, strtab, ["__safestack_init"])
        return sec

    class Phdr:
        # p_type
        PT_NULL          = 0
        PT_LOAD          = 1
        PT_DYNAMIC       = 2
        PT_INTERP        = 3
        PT_NOTE          = 4
        PT_SHLIB         = 5
        PT_PHDR          = 6
        PT_TLS           = 7
        #PT_LOOS          = 0x60000000
        PT_GNU_EH_FRAME  = 0x6474e550
        PT_GNU_STACK     = 0x6474e551
        PT_GNU_RELRO     = 0x6474e552
        PT_GNU_PROPERTY  = 0x6474e553
        #PT_LOSUNW        = 0x6ffffffa
        PT_SUNWBSS       = 0x6ffffffa
        PT_SUNWSTACK     = 0x6ffffffb
        #PT_HISUNW        = 0x6fffffff
        #PT_HIOS          = 0x6fffffff
        #PT_LOPROC        = 0x70000000
        #PT_HIPROC        = 0x7fffffff
        # arch specific values
        PT_MIPS_REGINFO  = 0x70000000
        PT_MIPS_RTPROC   = 0x70000001
        PT_MIPS_OPTIONS  = 0x70000002
        PT_MIPS_ABIFLAGS = 0x70000003
        PT_IA_64_UNWIND  = 0x70000001 # noqa: F841
        PT_HP_TLS        = 0x60000000 # noqa: F841
        PT_HP_CORE_NONE  = 0x60000001 # noqa: F841
        PT_HP_CORE_VERSION = 0x60000002 # noqa: F841
        PT_HP_CORE_KERNEL = 0x60000003 # noqa: F841
        PT_HP_CORE_COMM  = 0x60000004 # noqa: F841
        PT_HP_CORE_PROC  = 0x60000005 # noqa: F841
        PT_HP_CORE_LOADABLE = 0x60000006 # noqa: F841
        PT_HP_CORE_STACK = 0x60000007 # noqa: F841
        PT_HP_CORE_SHM   = 0x60000008 # noqa: F841
        PT_HP_CORE_MMF   = 0x60000009 # noqa: F841
        PT_HP_PARALLEL   = 0x6000000a # noqa: F841
        PT_HP_FASTBIND   = 0x6000000b # noqa: F841
        PT_HP_OPT_ANNOT  = 0x6000000c # noqa: F841
        PT_HP_HSL_ANNOT  = 0x6000000d # noqa: F841
        PT_HP_STACK      = 0x6000000ea # noqa: F841
        PT_PARISC_ARCHEXT = 0x70000000 # noqa: F841
        PT_PARISC_UNWIND = 0x70000001 # noqa: F841

        # p_flags
        PF_X             = 1
        PF_W             = 2
        PF_R             = 4
        # arch specific values
        PF_HP_PAGE_SIZE  = 0x00100000 # noqa: F841
        PF_HP_FAR_SHARED = 0x00200000 # noqa: F841
        PF_HP_NEAR_SHARED = 0x00400000 # noqa: F841
        PF_HP_CODE       = 0x01000000 # noqa: F841
        PF_HP_MODIFY     = 0x02000000 # noqa: F841
        PF_HP_LAZYSWAP   = 0x04000000 # noqa: F841
        PF_HP_SBP        = 0x08000000 # noqa: F841
        PF_PARISC_SBP    = 0x08000000 # noqa: F841

        p_type           = None
        p_flags          = None
        p_offset         = None
        p_vaddr          = None
        p_paddr          = None
        p_filesz         = None
        p_memsz          = None
        p_align          = None

        def __init__(self, elf, off):
            if elf is None:
                return None
            elf.seek(off)
            endian = "<" if elf.e_endianness == Elf.LITTLE_ENDIAN else ">"
            if elf.e_class == Elf.ELF_64_BITS:
                self.p_type, self.p_flags, self.p_offset = struct.unpack("{}IIQ".format(endian), elf.read(16))
                self.p_vaddr, self.p_paddr = struct.unpack("{}QQ".format(endian), elf.read(16))
                self.p_filesz, self.p_memsz, self.p_align = struct.unpack("{}QQQ".format(endian), elf.read(24))
            else:
                self.p_type, self.p_offset = struct.unpack("{}II".format(endian), elf.read(8))
                self.p_vaddr, self.p_paddr = struct.unpack("{}II".format(endian), elf.read(8))
                self.p_filesz, self.p_memsz, self.p_flags, self.p_align = struct.unpack("{}IIII".format(endian), elf.read(16))

        def __repr__(self):
            for e in dir(self):
                if e.startswith("PT_"):
                    if self.p_type == getattr(self, e):
                        return "<{:s}.{:s} object at {:#x}, p_type={:s}>".format(
                            self.__module__, self.__class__.__name__, id(self), e,
                        )
            return "<{:s}.{:s} object at {:#x}, p_type={:#x}>".format(
                self.__module__, self.__class__.__name__, id(self), self.p_type,
            )

    class Shdr:
        # sh_type
        SHT_NULL             = 0
        SHT_PROGBITS         = 1
        SHT_SYMTAB           = 2
        SHT_STRTAB           = 3
        SHT_RELA             = 4
        SHT_HASH             = 5
        SHT_DYNAMIC          = 6
        SHT_NOTE             = 7
        SHT_NOBITS           = 8
        SHT_REL              = 9
        SHT_SHLIB            = 10
        SHT_DYNSYM           = 11
        SHT_INIT_ARRAY       = 14
        SHT_FINI_ARRAY       = 15
        SHT_PREINIT_ARRAY    = 16
        SHT_GROUP            = 17
        SHT_SYMTAB_SHNDX     = 18
        SHT_RELR             = 19
        #SHT_LOOS             = 0x60000000
        SHT_GNU_ATTRIBUTES   = 0x6ffffff5
        SHT_GNU_HASH         = 0x6ffffff6
        SHT_GNU_LIBLIST      = 0x6ffffff7
        SHT_CHECKSUM         = 0x6ffffff8
        #SHT_LOSUNW           = 0x6ffffffa
        SHT_SUNW_move        = 0x6ffffffa
        SHT_SUNW_COMDAT      = 0x6ffffffb
        SHT_SUNW_syminfo     = 0x6ffffffc
        SHT_GNU_verdef       = 0x6ffffffd
        SHT_GNU_verneed      = 0x6ffffffe
        SHT_GNU_versym       = 0x6fffffff
        #SHT_HISUNW           = 0x6fffffff
        #SHT_HIOS             = 0x6fffffff
        #SHT_LOPROC           = 0x70000000
        #SHT_HIPROC           = 0x7fffffff
        #SHT_LOUSER           = 0x80000000
        #SHT_HIUSER           = 0x8fffffff
        # arch specific values
        SHT_PARISC_EXT       = 0x70000000 # noqa: F841
        SHT_PARISC_UNWIND    = 0x70000001 # noqa: F841
        SHT_PARISC_DOC       = 0x70000002 # noqa: F841
        SHT_MIPS_LIST        = 0x70000000 # noqa: F841
        SHT_MIPS_CONFLICT    = 0x70000002 # noqa: F841
        SHT_MIPS_GPTAB       = 0x70000003 # noqa: F841
        SHT_MIPS_UCODE       = 0x70000004 # noqa: F841
        SHT_MIPS_DEBUG       = 0x70000005 # noqa: F841
        SHT_MIPS_REGINFO     = 0x70000006 # noqa: F841
        SHT_MIPS_PACKAGE     = 0x70000007 # noqa: F841
        SHT_MIPS_PACKSYM     = 0x70000008 # noqa: F841
        SHT_MIPS_RELD        = 0x70000009 # noqa: F841
        SHT_MIPS_IFACE       = 0x7000000b # noqa: F841
        SHT_MIPS_CONTENT     = 0x7000000c # noqa: F841
        SHT_MIPS_OPTIONS     = 0x7000000d # noqa: F841
        SHT_MIPS_SHDR        = 0x70000010 # noqa: F841
        SHT_MIPS_FDESC       = 0x70000011 # noqa: F841
        SHT_MIPS_EXTSYM      = 0x70000012 # noqa: F841
        SHT_MIPS_DENSE       = 0x70000013 # noqa: F841
        SHT_MIPS_PDESC       = 0x70000014 # noqa: F841
        SHT_MIPS_LOCSYM      = 0x70000015 # noqa: F841
        SHT_MIPS_AUXSYM      = 0x70000016 # noqa: F841
        SHT_MIPS_OPTSYM      = 0x70000017 # noqa: F841
        SHT_MIPS_LOCSTR      = 0x70000018 # noqa: F841
        SHT_MIPS_LINE        = 0x70000019 # noqa: F841
        SHT_MIPS_RFDESC      = 0x7000001a # noqa: F841
        SHT_MIPS_DELTASYM    = 0x7000001b # noqa: F841
        SHT_MIPS_DELTAINST   = 0x7000001c # noqa: F841
        SHT_MIPS_DELTACLASS  = 0x7000001d # noqa: F841
        SHT_MIPS_DWARF       = 0x7000001e # noqa: F841
        SHT_MIPS_DELTADECL   = 0x7000001f # noqa: F841
        SHT_MIPS_SYMBOL_LIB  = 0x70000020 # noqa: F841
        SHT_MIPS_EVENTS      = 0x70000021 # noqa: F841
        SHT_MIPS_TRANSLATE   = 0x70000022 # noqa: F841
        SHT_MIPS_PIXIE       = 0x70000023 # noqa: F841
        SHT_MIPS_XLATE       = 0x70000024 # noqa: F841
        SHT_MIPS_XLATE_DEBUG = 0x70000025 # noqa: F841
        SHT_MIPS_WHIRL       = 0x70000026 # noqa: F841
        SHT_MIPS_EH_REGION   = 0x70000027 # noqa: F841
        SHT_MIPS_XLATE_OLD   = 0x70000028 # noqa: F841
        SHT_MIPS_PDR_EXCEPTION = 0x70000029 # noqa: F841

        # sh_flags
        SHF_WRITE            = 1
        SHF_ALLOC            = 2
        SHF_EXECINSTR        = 4
        SHF_MERGE            = 0x10
        SHF_STRINGS          = 0x20
        SHF_INFO_LINK        = 0x40
        SHF_LINK_ORDER       = 0x80
        SHF_OS_NONCONFORMING = 0x100
        SHF_GROUP            = 0x200
        SHF_TLS              = 0x400
        SHF_COMPRESSED       = 0x800
        SHF_RELA_LIVEPATCH   = 0x00100000 # noqa: F841
        SHF_RO_AFTER_INIT    = 0x00200000 # noqa: F841
        SHF_ORDERED          = 0x40000000 # noqa: F841
        SHF_EXCLUDE          = 0x80000000
        # arch specific values
        SHF_MIPS_NODUPES     = 0x01000000 # noqa: F841
        SHF_MIPS_NAMES       = 0x02000000 # noqa: F841
        SHF_MIPS_LOCAL       = 0x04000000 # noqa: F841
        SHF_MIPS_NOSTRIP     = 0x08000000 # noqa: F841
        SHF_MIPS_GPREL       = 0x10000000 # noqa: F841
        SHF_MIPS_MERGE       = 0x20000000 # noqa: F841
        SHF_MIPS_ADDR        = 0x40000000 # noqa: F841
        SHF_MIPS_STRING      = 0x80000000 # noqa: F841
        SHF_PARISC_SHORT     = 0x20000000 # noqa: F841
        SHF_PARISC_HUGE      = 0x40000000 # noqa: F841
        SHF_PARISC_SBP       = 0x80000000 # noqa: F841
        SHF_ALPHA_GPREL      = 0x10000000 # noqa: F841
        SHF_IA_64_SHORT      = 0x10000000 # noqa: F841

        sh_name              = None
        sh_type              = None
        sh_flags             = None
        sh_addr              = None
        sh_offset            = None
        sh_size              = None
        sh_link              = None
        sh_info              = None
        sh_addralign         = None
        sh_entsize           = None

        def __init__(self, elf, off):
            if elf is None:
                return None
            elf.seek(off)
            endian = "<" if elf.e_endianness == Elf.LITTLE_ENDIAN else ">"
            if elf.e_class == Elf.ELF_64_BITS:
                self.sh_name, self.sh_type, self.sh_flags = struct.unpack("{}IIQ".format(endian), elf.read(16))
                self.sh_addr, self.sh_offset = struct.unpack("{}QQ".format(endian), elf.read(16))
                self.sh_size, self.sh_link, self.sh_info = struct.unpack("{}QII".format(endian), elf.read(16))
                self.sh_addralign, self.sh_entsize = struct.unpack("{}QQ".format(endian), elf.read(16))
            else:
                self.sh_name, self.sh_type, self.sh_flags = struct.unpack("{}III".format(endian), elf.read(12))
                self.sh_addr, self.sh_offset = struct.unpack("{}II".format(endian), elf.read(8))
                self.sh_size, self.sh_link, self.sh_info = struct.unpack("{}III".format(endian), elf.read(12))
                self.sh_addralign, self.sh_entsize = struct.unpack("{}II".format(endian), elf.read(8))

            # name
            stroff = elf.e_shoff + elf.e_shentsize * elf.e_shstrndx

            if elf.e_class == Elf.ELF_64_BITS:
                elf.seek(stroff + 16 + 8)
                offset = struct.unpack("{}Q".format(endian), elf.read(8))[0]
            else:
                elf.seek(stroff + 12 + 4)
                offset = struct.unpack("{}I".format(endian), elf.read(4))[0]
            elf.seek(offset + self.sh_name)
            self.sh_name = ""
            while True:
                c = ord(elf.read(1))
                if c == 0:
                    break
                self.sh_name += chr(c)
            return

        def __repr__(self):
            return '<{:s}.{:s} object at {:#x}, sh_name="{:s}">'.format(
                self.__module__, self.__class__.__name__, id(self), self.sh_name,
            )


class Instruction:
    """GEF representation of a CPU instruction."""
    def __init__(self, address, location, mnemo, operands, opcodes):
        # example:
        #   address: 0x55555555a7d0
        #   location: "" or "<main+0>"
        #   mnemo: "lea"
        #   operands: ['rcx', '[rip+0x11ee5]        # 0x55555556c69a']
        #   opcodes: b'H\x8d\r\xe5\x1e\x01\x00'
        self.address = address
        self.location = location
        self.mnemonic = mnemo

        # merge symbol includes ","; e.g.: <... , ...>
        if len(operands) > 1:
            operands, o = operands[:-1], operands[-1]
            while o.count("<") < o.count(">"):
                operands, oo = operands[:-1], operands[-1]
                o = oo + ", " + o
            operands += [o]

        self.operands = operands
        self.opcodes = opcodes
        return

    RE_SPLIT_LAST_OPERAND_X86_64 = re.compile(r"(.*?)\s+(#.+)$")
    RE_SPLIT_LAST_OPERAND_ARM64 = re.compile(r"//.+$")
    RE_SPLIT_LAST_OPERAND_ARM32 = re.compile(r";.+$")
    RE_SPLIT_LAST_OPERAND_MICROBLAZE = re.compile(r"//.+$")
    RE_SPLIT_LAST_OPERAND_LOONGARCH64 = re.compile(r"(# .*)$")
    RE_SPLIT_ELEM = re.compile(r"([*%\[\](): ]|(?<![#@%])(?<=.)[-+]|<.+>)")
    RE_IS_DIGIT_COMMENT = re.compile(r"#?-?(0x[0-9a-f]+|\d+)")
    RE_SPLIT_SYMBOL = re.compile(r"(.*?)<(.+)>(.*)$")
    RE_SPLIT_SYMBOL_OFFSET = re.compile(r"(.+)\+(\d+)$")

    # Allow formatting an instruction with {:o} to show opcodes.
    # The number of bytes to display can be configured, e.g. {:4o} to only show 4 bytes of the opcodes
    def __format__(self, format_spec):
        if len(format_spec) == 0:
            return str(self)
        if format_spec[-1] not in ["o", "O"]:
            return str(self)

        to_highlight = format_spec[-1] == "O"

        # format address
        if to_highlight:
            color_address = Config.get_gef_setting("theme.disassemble_address_highlight")
        else:
            color_address = Config.get_gef_setting("theme.disassemble_address")
        address = Color.colorify(hex(self.address), color_address)

        # format opcode
        if format_spec in ["o", "O"]: # no specified length
            opcodes_len = len(self.opcodes)
        else:
            opcodes_len = int(format_spec[:-1])

        if opcodes_len == 0:
            opcodes_text = ""
        else:
            opcodes_text = "".join("{:02x}".format(b) for b in self.opcodes) # e.g.: "488d0de51e0100"
            # ex1: spec:"4o", opcodes:01020304   -> 01020304
            # ex2: spec:"4o", opcodes:0102030405 -> 010203..
            if opcodes_len < len(self.opcodes):
                opcodes_text = opcodes_text[:opcodes_len * 2 - 2] + ".."

        if to_highlight:
            color_opcode = Config.get_gef_setting("theme.disassemble_opcode_highlight")
        else:
            color_opcode = Config.get_gef_setting("theme.disassemble_opcode")
        opcodes_text = Color.colorify("{:{:d}}".format(opcodes_text, opcodes_len * 2), color_opcode)

        # format location
        location = self.smartify_text(self.location)

        # format mnemonic
        if current_arch.is_syscall(self):
            is_branch = True
        elif current_arch.is_call(self):
            is_branch = True
        elif current_arch.is_jump(self):
            is_branch = True
        elif current_arch.is_ret(self):
            is_branch = True
        elif current_arch.is_conditional_branch(self):
            is_branch = True
        else:
            is_branch = False

        if is_branch:
            if to_highlight:
                color_mnemonic = Config.get_gef_setting("theme.disassemble_mnemonic_branch_highlight")
            else:
                color_mnemonic = Config.get_gef_setting("theme.disassemble_mnemonic_branch")
        else:
            if to_highlight:
                color_mnemonic = Config.get_gef_setting("theme.disassemble_mnemonic_normal_highlight")
            else:
                color_mnemonic = Config.get_gef_setting("theme.disassemble_mnemonic_normal")
        mnemonic = Color.colorify("{:6s}".format(self.mnemonic), color_mnemonic)

        # break down last operands
        operands = self.operands[::]

        # ;, #, //
        additional_1 = ""
        if len(operands) > 0:
            last_operands = operands[-1]
            if is_x86_64():
                r = self.RE_SPLIT_LAST_OPERAND_X86_64.match(last_operands) # r"(.*?)\s+(#.+)$"
                if r:
                    last_operands = r.group(1)
                    additional_1 = r.group(2)
                    operands = operands[:-1] + [last_operands]
            elif is_arm64():
                r = self.RE_SPLIT_LAST_OPERAND_ARM64.match(last_operands) # r"//.+$"
                if r:
                    additional_1 = last_operands
                    operands = operands[:-1]
            elif is_arm32():
                r = self.RE_SPLIT_LAST_OPERAND_ARM32.match(last_operands) # r";.+$"
                if r:
                    additional_1 = last_operands
                    operands = operands[:-1]
            elif is_microblaze():
                r = self.RE_SPLIT_LAST_OPERAND_MICROBLAZE.match(last_operands) # r"//.+$"
                if r:
                    additional_1 = last_operands
                    operands = operands[:-1]
            elif is_loongarch64():
                r = self.RE_SPLIT_LAST_OPERAND_LOONGARCH64.match(last_operands) # r"(# .*)$"
                if r:
                    additional_1 = r.group(1)
                    operands = operands[:-1]

        def hexlify_symbol_offset(x):
            r1 = self.RE_SPLIT_SYMBOL.match(x) # r"(.*?)<(.+)>(.*)$"
            if not r1:
                return x
            r2 = self.RE_SPLIT_SYMBOL_OFFSET.match(r1.group(2)) # r"(.+)\+(\d+)$"
            if r2:
                sym_x = "{}+{:#x}".format(self.smartify_text(r2.group(1)), int(r2.group(2)))
            else:
                sym_x = self.smartify_text(r1.group(2))
            return "{:s}<{:s}>{:s}".format(r1.group(1), sym_x, r1.group(3))

        additional_1 = hexlify_symbol_offset(additional_1)

        # format operands
        if to_highlight:
            color_operands_normal = Config.get_gef_setting("theme.disassemble_operands_normal_highlight")
            color_operands_const = Config.get_gef_setting("theme.disassemble_operands_const_highlight")
            color_operands_symbol = Config.get_gef_setting("theme.disassemble_operands_symbol_highlight")
        else:
            color_operands_normal = Config.get_gef_setting("theme.disassemble_operands_normal")
            color_operands_const = Config.get_gef_setting("theme.disassemble_operands_const")
            color_operands_symbol = Config.get_gef_setting("theme.disassemble_operands_symbol")
        colored_operands = []
        # extract -> coloring -> join
        for o1 in operands:
            colored_o1 = []
            # split by *, [, ], (, ), %, :, space, non-first +, - (without #, @, %), <...>
            for o2 in self.RE_SPLIT_ELEM.split(o1): # r"([*%\[\](): ]|(?<![#@%])(?<=.)[-+]|<.+>)"
                o2 = o2.strip()
                if o2 == "":
                    continue
                if o2[0] == "<":
                    colored_o1.append(hexlify_symbol_offset(o2))
                    colored_o1.append(" ")
                elif o2 in ["-", "+", "*"]:
                    colored_o1.append(Color.colorify(o2, color_operands_symbol))
                    colored_o1.append(" ")
                elif o2 in [":", "%"]:
                    if colored_o1 and colored_o1[-1] == " ":
                        colored_o1 = colored_o1[:-1]
                    colored_o1.append(Color.colorify(o2, color_operands_symbol))
                elif o2 in ["[", "("]:
                    colored_o1.append(Color.colorify(o2, color_operands_symbol))
                elif o2 in ["]", ")"]:
                    if colored_o1 and colored_o1[-1] == " ":
                        colored_o1 = colored_o1[:-1]
                    colored_o1.append(Color.colorify(o2, color_operands_symbol))
                elif self.RE_IS_DIGIT_COMMENT.match(o2): # r"#?-?(0x[0-9a-f]+|\d+)"
                    colored_o1.append(Color.colorify(o2, color_operands_const))
                    colored_o1.append(" ")
                else:
                    colored_o1.append(Color.colorify(o2, color_operands_normal))
                    colored_o1.append(" ")
            colored_operands.append("".join(colored_o1).strip())
        operands = Color.colorify(", ", color_operands_symbol).join(colored_operands)

        # the case that gdb does not append symbol but symbol exists
        if is_branch and "<" not in operands and self.operands and self.operands[-1]:
            addr = ContextCommand.get_branch_addr(self)
            sym = Symbol.get_symbol_string(addr).lstrip()
            additional_1 = sym

        # formatting
        out = "{:s} {:s}   {:s}   {:s} {:s} {:s}".format(
            address, opcodes_text, location, mnemonic, operands, additional_1,
        )
        return out

    def __repr__(self):
        return '<{:s}.{:s} object at {:#x}, asm="{:s}">'.format(
            self.__module__, self.__class__.__name__, id(self), str(self),
        )

    def __str__(self):
        location = self.smartify_text(self.location)
        if not location:
            location = "<NO_SYMBOL>"
        operands = self.smartify_text(", ".join(self.operands))
        return "{:#10x} {:20s} {:6s} {:s}".format(self.address, location, self.mnemonic, operands)

    def is_valid(self):
        return "(bad)" not in self.mnemonic

    @staticmethod
    def smartify_text(text):
        smart_cpp_function_name = Config.get_gef_setting("context.smart_cpp_function_name")
        if not smart_cpp_function_name:
            return text

        if text is None:
            return text

        if len(text) == 0:
            return text

        text = re.sub(r"\bstd::__1::", "", text)

        old_text = text[::]
        while True:
            text = re.sub(r"\([^(]+?\)", "__MARKER_GEF__", text)
            if text == old_text:
                break
            old_text = text[::]
        text = re.sub("__MARKER_GEF__", "(...)", text)

        m = re.match(r"^(\s*\<)(.*)(\>\s*)$", text)
        if m:
            text_0, text, text_end = m.group(1), m.group(2), m.group(3)
        else:
            text_0, text, text_end = "", text, ""

        while True:
            text = re.sub(r"\<[^<]+?\>", "__MARKER_GEF__", text)
            if text == old_text:
                break
            old_text = text[::]
        text = re.sub("__MARKER_GEF__", "<...>", text)
        if text_0:
            text = text_0 + text
        if text_end:
            text = text + text_end
        return text


class GlibcHeap:
    class HeapInfo:
        """GEF representation of heap_info"""

        def __init__(self, addr):
            self.__addr = addr

            if is_64bit():
                MALLOC_ALIGNMENT = 0x10
            elif (is_x86_32() or is_riscv32() or is_ppc32()) and get_libc_version() >= (2, 26):
                MALLOC_ALIGNMENT = 0x10
            else:
                MALLOC_ALIGNMENT = 0x8
            self.MALLOC_ALIGN_MASK = MALLOC_ALIGNMENT - 1

            self.char_t = GefUtil.cached_lookup_type("char")
            self.size_t = GefUtil.cached_lookup_type("size_t")
            if not self.size_t:
                ptr_type = "unsigned long" if current_arch.ptrsize == 8 else "unsigned int"
                self.size_t = GefUtil.cached_lookup_type(ptr_type)
            return

        # struct offsets
        @property
        def addr(self):
            return self.__addr

        @property
        def ar_ptr_addr(self):
            return self.__addr

        @property
        def prev_addr(self):
            return self.ar_ptr_addr + self.char_t.pointer().sizeof

        @property
        def size_addr(self):
            return self.prev_addr + self.char_t.pointer().sizeof

        @property
        def mprotect_size_addr(self):
            return self.size_addr + self.size_t.sizeof

        @property
        def pagesize_addr(self):
            if get_libc_version() >= (2, 35):
                return self.mprotect_size_addr + self.size_t.sizeof
            else:
                return None

        @property
        def pad_addr(self):
            if get_libc_version() >= (2, 35):
                return self.pagesize_addr + self.size_t.sizeof
            else:
                return self.mprotect_size_addr + self.size_t.sizeof

        @property
        def sizeof(self):
            if get_libc_version() >= (2, 35):
                end = self.pad_addr + (-3 * self.size_t.sizeof) & self.MALLOC_ALIGN_MASK
            else:
                end = self.pad_addr + (-6 * self.size_t.sizeof) & self.MALLOC_ALIGN_MASK
            return end - self.__addr

        # struct members
        @property
        def ar_ptr(self):
            return self.get_char_t_pointer(self.ar_ptr_addr)

        @property
        def prev(self):
            return self.get_char_t_pointer(self.prev_addr)

        @property
        def size(self):
            return self.get_size_t(self.size_addr)

        @property
        def mprotect_size(self):
            return self.get_size_t(self.mprotect_size_addr)

        @property
        def pagesize(self):
            if get_libc_version() >= (2, 35):
                return self.get_size_t(self.pagesize_addr)
            else:
                return None

        @property
        def pad(self):
            if get_libc_version() >= (2, 35):
                length = (-3 * self.size_t.sizeof) & self.MALLOC_ALIGN_MASK
            else:
                length = (-6 * self.size_t.sizeof) & self.MALLOC_ALIGN_MASK
            return self.get_char_t_array(self.pad_addr, length)

        # helper methods
        def get_size_t(self, addr):
            return AddressUtil.dereference(addr).cast(self.size_t)

        def get_char_t_pointer(self, addr):
            char_t_pointer = self.char_t.pointer()
            return AddressUtil.dereference(addr).cast(char_t_pointer)

        def get_char_t_array(self, addr, length):
            char_t_array = self.char_t.array(length)
            return AddressUtil.dereference(addr).cast(char_t_array)

        def __getitem__(self, item):
            return getattr(self, item)

    class MallocPar:
        """GEF representation of malloc_par"""
        def __init__(self, addr):
            self.__addr = addr

            self.char_t = GefUtil.cached_lookup_type("char")
            self.int_t = GefUtil.cached_lookup_type("int")
            self.long_t = GefUtil.cached_lookup_type("long")
            self.size_t = GefUtil.cached_lookup_type("size_t")
            if not self.size_t:
                ptr_type = "unsigned long" if current_arch.ptrsize == 8 else "unsigned int"
                self.size_t = GefUtil.cached_lookup_type(ptr_type)
            return

        # struct offsets
        @property
        def addr(self):
            return self.__addr

        @property
        def trim_threshold_addr(self):
            return self.__addr

        @property
        def top_pad_addr(self):
            return self.trim_threshold_addr + self.long_t.sizeof

        @property
        def mmap_threshold_addr(self):
            return self.top_pad_addr + self.size_t.sizeof

        @property
        def arena_test_addr(self):
            return self.mmap_threshold_addr + self.size_t.sizeof

        @property
        def arena_max_addr(self):
            return self.arena_test_addr + self.size_t.sizeof

        @property
        def thp_pagesize_addr(self):
            if get_libc_version() >= (2, 35):
                return self.arena_max_addr + self.size_t.sizeof
            else:
                return None

        @property
        def hp_pagesize_addr(self):
            if get_libc_version() >= (2, 35):
                return self.thp_pagesize_addr + self.size_t.sizeof
            else:
                return None

        @property
        def hp_flags_addr(self):
            if get_libc_version() >= (2, 35):
                return self.hp_pagesize_addr + self.size_t.sizeof
            else:
                return None

        @property
        def n_mmaps_addr(self):
            if get_libc_version() >= (2, 35):
                return self.hp_flags_addr + self.int_t.sizeof
            else:
                return self.arena_max_addr + self.size_t.sizeof

        @property
        def n_mmaps_max_addr(self):
            return self.n_mmaps_addr + self.int_t.sizeof

        @property
        def max_n_mmaps_addr(self):
            return self.n_mmaps_max_addr + self.int_t.sizeof

        @property
        def no_dyn_threshold_addr(self):
            return self.max_n_mmaps_addr + self.int_t.sizeof

        @property
        def pagesize_addr(self):
            if get_libc_version() >= (2, 15):
                return None
            else:
                return self.max_n_mmaps_addr + self.int_t.sizeof

        @property
        def mmapped_mem_addr(self):
            if get_libc_version() >= (2, 15):
                return AddressUtil.align_address_to_size(self.no_dyn_threshold_addr + self.int_t.sizeof, current_arch.ptrsize)
            else:
                return AddressUtil.align_address_to_size(self.pagesize_addr + self.int_t.sizeof, current_arch.ptrsize)

        @property
        def max_mmapped_mem_addr(self):
            return self.mmapped_mem_addr + self.size_t.sizeof

        @property
        def max_total_mem_addr(self):
            if get_libc_version() >= (2, 24):
                return None
            else:
                return self.mmapped_mem_addr + self.size_t.sizeof

        @property
        def sbrk_base_addr(self):
            if get_libc_version() >= (2, 24):
                return self.max_mmapped_mem_addr + self.size_t.sizeof
            else:
                return self.max_total_mem_addr + self.size_t.sizeof

        @property
        def tcache_bins_addr(self):
            if get_libc_version() >= (2, 26):
                return self.sbrk_base_addr + self.char_t.pointer().sizeof
            else:
                return None

        @property
        def tcache_max_bytes_addr(self):
            if get_libc_version() >= (2, 26):
                return self.tcache_bins_addr + self.size_t.sizeof
            else:
                return None

        @property
        def tcache_count_addr(self):
            if get_libc_version() >= (2, 26):
                return self.tcache_max_bytes_addr + self.size_t.sizeof
            else:
                return None

        @property
        def tcache_unsorted_limit_addr(self):
            if get_libc_version() >= (2, 26):
                return self.tcache_count_addr + self.size_t.sizeof
            else:
                return None

        @property
        def sizeof(self):
            if get_libc_version() >= (2, 26):
                end = self.tcache_unsorted_limit_addr + self.size_t.sizeof
            else:
                end = self.sbrk_base_addr + self.char_t.pointer().sizeof
            return end - self.__addr

        # struct members
        @property
        def trim_threshold(self):
            return self.get_long_t(self.trim_threshold_addr)

        @property
        def top_pad(self):
            return self.get_size_t(self.top_pad_addr)

        @property
        def mmap_threshold(self):
            return self.get_size_t(self.mmap_threshold_addr)

        @property
        def arena_test(self):
            return self.get_size_t(self.arena_test_addr)

        @property
        def arena_max(self):
            return self.get_size_t(self.arena_max_addr)

        @property
        def thp_pagesize(self):
            if get_libc_version() >= (2, 35):
                return self.get_size_t(self.thp_pagesize_addr)
            else:
                return None

        @property
        def hp_pagesize(self):
            if get_libc_version() >= (2, 35):
                return self.get_size_t(self.hp_pagesize_addr)
            else:
                return None

        @property
        def hp_flags(self):
            if get_libc_version() >= (2, 35):
                return self.get_int_t(self.hp_flags_addr)
            else:
                return None

        @property
        def n_mmaps(self):
            return self.get_int_t(self.n_mmaps_addr)

        @property
        def n_mmaps_max(self):
            return self.get_int_t(self.n_mmaps_max_addr)

        @property
        def max_n_mmaps(self):
            return self.get_int_t(self.max_n_mmaps_addr)

        @property
        def no_dyn_threshold(self):
            return self.get_int_t(self.no_dyn_threshold_addr)

        @property
        def pagesize(self):
            if get_libc_version() >= (2, 15):
                return None
            else:
                return self.get_int_t(self.pagesize_addr)

        @property
        def mmapped_mem(self):
            return self.get_size_t(self.mmapped_mem_addr)

        @property
        def max_mmapped_mem(self):
            return self.get_size_t(self.max_mmapped_mem_addr)

        @property
        def max_total_mem(self):
            if get_libc_version() >= (2, 24):
                return None
            else:
                return self.get_size_t(self.max_total_mem_addr)

        @property
        def sbrk_base(self):
            return self.get_char_t_pointer(self.sbrk_base_addr)

        @property
        def tcache_bins(self):
            if get_libc_version() >= (2, 26):
                return self.get_size_t(self.tcache_bins_addr)
            else:
                return None

        @property
        def tcache_max_bytes(self):
            if get_libc_version() >= (2, 26):
                return self.get_size_t(self.tcache_max_bytes_addr)
            else:
                return None

        @property
        def tcache_count(self):
            if get_libc_version() >= (2, 26):
                return self.get_size_t(self.tcache_count_addr)
            else:
                return None
            self.tcache_count # avoid to be detected as unused # noqa: B018

        @property
        def tcache_unsorted_limit(self):
            if get_libc_version() >= (2, 26):
                return self.get_size_t(self.tcache_unsorted_limit_addr)
            else:
                return None

        # helper methods
        def get_size_t(self, addr):
            return AddressUtil.dereference(addr).cast(self.size_t)

        def get_int_t(self, addr):
            return AddressUtil.dereference(addr).cast(self.int_t)

        def get_long_t(self, addr):
            return AddressUtil.dereference(addr).cast(self.long_t)

        def get_char_t_pointer(self, addr):
            char_t_pointer = self.char_t.pointer()
            return AddressUtil.dereference(addr).cast(char_t_pointer)

        def __getitem__(self, item):
            return getattr(self, item)

    @staticmethod
    @Cache.cache_until_next
    def search_for_mp_():
        """search mp_ from main_arena, then return addr."""
        main_arena_ptr = GlibcHeap.search_for_main_arena_from_tls()
        if main_arena_ptr is None:
            return None
        main_arena = read_int_from_memory(main_arena_ptr)

        heap_base = HeapbaseCommand.heap_base()
        if heap_base is None:
            return None

        offsetof_sbrk_base = GlibcHeap.MallocPar(0).sbrk_base_addr
        current = main_arena - GlibcHeap.MallocPar(0).sizeof
        for _ in range(0, 500):
            try:
                x = read_int_from_memory(current)
            except gdb.MemoryError:
                return None
            if x == heap_base:
                mp_ = current - offsetof_sbrk_base
                return mp_
            current -= current_arch.ptrsize
        return None

    class MallocStateStruct:
        """GEF representation of malloc_state"""
        def __init__(self, addr):
            if (is_x86_32() or is_riscv32() or is_ppc32()) and get_libc_version() >= (2, 26):
                # MALLOC_ALIGNMENT is changed from libc 2.26.
                # for x86_32, MALLOC_ALIGNMENT = 16, so NFASTBINS = 11.
                self.num_fastbins = 11
            else:
                self.num_fastbins = 10

            self.num_bins = 254
            self.num_binmap = 4
            self.__addr = addr

            self.int_t = GefUtil.cached_lookup_type("int")
            self.size_t = GefUtil.cached_lookup_type("size_t")
            if not self.size_t:
                ptr_type = "unsigned long" if current_arch.ptrsize == 8 else "unsigned int"
                self.size_t = GefUtil.cached_lookup_type(ptr_type)
            return

        # struct offsets
        @property
        def addr(self):
            return self.__addr

        @property
        def mutex_addr(self):
            return self.__addr

        @property
        def flags_addr(self):
            return self.mutex_addr + self.int_t.sizeof

        @property
        def have_fastchunks_addr(self):
            if get_libc_version() >= (2, 27):
                return self.flags_addr + self.int_t.sizeof
            else:
                return None

        @property
        def fastbins_addr(self):
            if get_libc_version() >= (2, 27):
                fastbin_offset = AddressUtil.align_address_to_size(self.int_t.sizeof * 3, self.size_t.sizeof)
            else:
                fastbin_offset = self.int_t.sizeof * 2
            return self.__addr + fastbin_offset

        @property
        def top_addr(self):
            return self.fastbins_addr + self.size_t.sizeof * self.num_fastbins

        @property
        def last_remainder_addr(self):
            return self.top_addr + self.size_t.sizeof

        @property
        def bins_addr(self):
            return self.last_remainder_addr + self.size_t.sizeof

        @property
        def binmap_addr(self):
            return self.bins_addr + self.size_t.sizeof * self.num_bins

        @property
        def next_addr(self):
            return self.binmap_addr + self.int_t.sizeof * self.num_binmap

        @property
        def next_free_addr(self):
            if get_libc_version() >= (2, 19):
                return self.next_addr + self.size_t.sizeof
            else:
                # before glibc 2.19, the existence of next_free depends on the environment.
                # however, it seems that it is more likely that it does not exist, so I return None.
                return None

        @property
        def attached_threads_addr(self):
            if get_libc_version() >= (2, 23):
                return self.next_free_addr + self.size_t.sizeof
            else:
                return None

        @property
        def system_mem_addr(self):
            if get_libc_version() >= (2, 23):
                return self.attached_threads_addr + self.size_t.sizeof
            elif get_libc_version() >= (2, 19):
                return self.next_free_addr + self.size_t.sizeof
            else:
                return self.next_addr + self.size_t.sizeof

        @property
        def max_system_mem_addr(self):
            return self.system_mem_addr + self.size_t.sizeof

        @property
        def struct_size(self):
            return self.max_system_mem_addr + self.size_t.sizeof - self.__addr

        # struct members
        @property
        def mutex(self):
            return self.get_int_t(self.mutex_addr)

        @property
        def flags(self):
            return self.get_int_t(self.flags_addr)

        @property
        def have_fastchunks(self):
            if get_libc_version() >= (2, 27):
                return self.get_int_t(self.have_fastchunks_addr)
            else:
                return None

        @property
        def fastbinsY(self):
            return self.get_size_t_array(self.fastbins_addr, self.num_fastbins)

        @property
        def top(self):
            return self.get_size_t_pointer(self.top_addr)

        @property
        def last_remainder(self):
            return self.get_size_t_pointer(self.last_remainder_addr)

        @property
        def bins(self):
            return self.get_size_t_array(self.bins_addr, self.num_bins)

        @property
        def binmap(self):
            return self.get_int_t_array(self.binmap_addr, self.num_binmap)

        @property
        def next(self):
            return self.get_size_t_pointer(self.next_addr)

        @property
        def next_free(self):
            if get_libc_version() >= (2, 19):
                return self.get_size_t_pointer(self.next_free_addr)
            else:
                return None

        @property
        def attached_threads(self):
            if get_libc_version() >= (2, 23):
                return self.get_size_t(self.attached_threads_addr)
            else:
                return None

        @property
        def system_mem(self):
            return self.get_size_t(self.system_mem_addr)

        @property
        def max_system_mem(self):
            return self.get_size_t(self.max_system_mem_addr)

        # helper methods
        def get_size_t(self, addr):
            return AddressUtil.dereference(addr).cast(self.size_t)

        def get_int_t(self, addr):
            return AddressUtil.dereference(addr).cast(self.int_t)

        def get_size_t_pointer(self, addr):
            size_t_pointer = self.size_t.pointer()
            return AddressUtil.dereference(addr).cast(size_t_pointer)

        def get_size_t_array(self, addr, length):
            size_t_array = self.size_t.array(length)
            return AddressUtil.dereference(addr).cast(size_t_array)

        def get_int_t_array(self, addr, length):
            int_t_array = self.int_t.array(length)
            return AddressUtil.dereference(addr).cast(int_t_array)

        def __getitem__(self, item):
            return getattr(self, item)

    @staticmethod
    @Cache.cache_until_next
    def search_for_main_arena_from_tls():
        """search main arena from TLS, then return &addr."""

        """
        [x64]
        0x7ffff7f986f8|+0x0038|007: 0x0000555555559010  ->  0x0000000000000000
        0x7ffff7f98700|+0x0040|008: 0x0000000000000000
        0x7ffff7f98708|+0x0048|009: 0x00007ffff7e19c80 <main_arena>  ->  0x0000000000000000
        0x7ffff7f98710|+0x0050|010: 0x0000000000000000
        0x7ffff7f98718|+0x0058|011: 0x0000000000000000
        0x7ffff7f98720|+0x0060|012: 0x0000000000000000
        0x7ffff7f98728|+0x0068|013: 0x0000000000000000
        0x7ffff7f98730|+0x0070|014: 0x0000000000000000
        0x7ffff7f98738|+0x0078|015: 0x0000000000000000
        -- TLS --
        0x7ffff7f98740|+0x0000|000: 0x00007ffff7f98740  ->  [loop detected]
        0x7ffff7f98748|+0x0008|001: 0x00007ffff7f99160  ->  0x0000000000000001
        0x7ffff7f98750|+0x0010|002: 0x00007ffff7f98740  ->  [loop detected]

        [x86]
        0xf7fbf4d0|+0x00d0|052: 0x5655a010  ->  0x00000000
        0xf7fbf4d4|+0x00d4|053: 0x00000000
        0xf7fbf4d8|+0x00d8|054: 0xf7e2a7c0 <main_arena>  ->  0x00000000
        0xf7fbf4dc|+0x00dc|055: 0x00000000
        0xf7fbf4e0|+0x00e0|056: 0x00000000
        0xf7fbf4e4|+0x00e4|057: 0x00000000
        0xf7fbf4e8|+0x00e8|058: 0x00000000
        0xf7fbf4ec|+0x00ec|059: 0x00000000
        0xf7fbf4f0|+0x00f0|060: 0x00000000
        0xf7fbf4f4|+0x00f4|061: 0x00000000
        0xf7fbf4f8|+0x00f8|062: 0x00000000
        0xf7fbf4fc|+0x00fc|063: 0x00000000
        -- TLS --
        0xf7fbf500|+0x0100|064: 0xf7fbf500  ->  [loop detected]
        0xf7fbf504|+0x0104|065: 0xf7fbfa88  ->  0x00000001
        0xf7fbf508|+0x0108|066: 0xf7fbf500  ->  [loop detected]

        [ARM]
        -- TLS --
        0x0007d580|+0x0000|000: 0x0007a3c8 <_dl_static_dtv+0x8>  ->  0x00000000
        0x0007d584|+0x0004|001: 0x00000000
        0x0007d588|+0x0008|002: 0x00079fa0 <_nl_global_locale>  ->  ...
        0x0007d58c|+0x000c|003: 0x00079fa0 <_nl_global_locale>  ->  ...
        0x0007d590|+0x0010|004: 0x00079fa4 <_nl_global_locale+0x4>  ->  ...
        0x0007d594|+0x0014|005: 0x00079fb0 <_nl_global_locale+0x10>  ->  ...
        0x0007d598|+0x0018|006: 0x00000000
        0x0007d59c|+0x001c|007: 0x00079660 <main_arena>  ->  0x00000000
        0x0007d5a0|+0x0020|008: 0x0007d908  ->  0x00000000
        0x0007d5a4|+0x0024|009: 0x00000000
        0x0007d5a8|+0x0028|010: 0x00000000

        [ARM64]
        -- TLS --
        0x0000004997c0|+0x0000|000: 0x0000000000493078 <_dl_static_dtv+0x10>  ->  0x0000000000000000
        0x0000004997c8|+0x0008|001: 0x0000000000000000
        0x0000004997d0|+0x0010|002: 0x0000000000492838 <_nl_global_locale>  ->  ...
        0x0000004997d8|+0x0018|003: 0x0000000000492840 <_nl_global_locale+0x8>  ->  ...
        0x0000004997e0|+0x0020|004: 0x0000000000492838 <_nl_global_locale>  ->  ...
        0x0000004997e8|+0x0028|005: 0x0000000000492858 <_nl_global_locale+0x20>  ->  ...
        0x0000004997f0|+0x0030|006: 0x0000000000000000
        0x0000004997f8|+0x0038|007: 0x0000000000491678 <main_arena>  ->  0x0000000000000000
        0x000000499800|+0x0040|008: 0x0000000000499b90  ->  0x0000000000000000
        0x000000499808|+0x0048|009: 0x0000000000000000
        0x000000499810|+0x0050|010: 0x0000000000000000
        0x000000499818|+0x0058|011: 0x000000000045e780 <_nl_C_LC_CTYPE_class+0x100>  ->  0x0002000200020002
        0x000000499820|+0x0060|012: 0x000000000045de80 <_nl_C_LC_CTYPE_toupper+0x200>  ->  0x0000000100000000
        0x000000499828|+0x0068|013: 0x000000000045d880 <_nl_C_LC_CTYPE_tolower+0x200>  ->  0x0000000100000000
        0x000000499830|+0x0070|014: 0x0000000000000000
        0x000000499838|+0x0078|015: 0x0000000000000000
        """

        selected_thread = gdb.selected_thread()
        threads = gdb.selected_inferior().threads()
        main_thread = [th for th in threads if th.num == 1][0]
        main_thread.switch()

        if is_x86() or is_sparc64() or is_s390x():
            direction = -1
        else:
            direction = 1

        tls = current_arch.get_tls()
        if tls is None:
            return None
        for i in range(1, 500):
            addr = tls + (current_arch.ptrsize * i) * direction

            if is_m68k():
                addr += 2

            if not is_valid_addr(addr):
                break

            candidate_arena_addr = read_int_from_memory(addr)
            if not is_valid_addr(candidate_arena_addr):
                continue

            candidate_arena = GlibcHeap.MallocStateStruct(candidate_arena_addr)
            system_mem = candidate_arena.system_mem
            if system_mem < gef_getpagesize():
                continue

            top = candidate_arena.top
            if not is_valid_addr(top):
                continue

            _next = to_unsigned_long(candidate_arena.next)
            while True:
                if not is_valid_addr(_next):
                    break
                if candidate_arena_addr == _next:
                    selected_thread.switch() # revert thread
                    return addr
                _next = to_unsigned_long(GlibcHeap.MallocStateStruct(_next).next)

        # not found
        selected_thread.switch() # revert thread
        return None

    class GlibcArena:
        """Glibc arena class"""
        TCACHE_MAX_BINS = 0x40

        def __init__(self, arena_addr=None):
            # get address
            if arena_addr is None:
                self.__addr = self.search_for_main_arena()
                self.__is_main_arena = True
            else:
                self.__addr = arena_addr
                self.__is_main_arena = arena_addr == self.search_for_main_arena()

            # get type
            try:
                arena = gdb.parse_and_eval("*{:#x}".format(self.__addr))
                malloc_state_t = GefUtil.cached_lookup_type("struct malloc_state")
                self.__arena = arena.cast(malloc_state_t)
                self.__size = malloc_state_t.sizeof
            except RuntimeError:
                self.__arena = GlibcHeap.MallocStateStruct(self.__addr)
                self.__size = self.__arena.struct_size

            # cache for frequent use (see __getattr__)
            self.top = int(self.top)
            self.last_remainder = int(self.last_remainder)
            return

        def __getitem__(self, item):
            return self.__arena[item]

        def __getattr__(self, item):
            return self.__arena[item]

        def __int__(self):
            return self.__addr

        def search_for_main_arena(self):
            if Cache.cached_main_arena:
                return Cache.cached_main_arena

            # plan 1 (directly)
            try:
                Cache.cached_main_arena = AddressUtil.parse_address("&main_arena")
                return Cache.cached_main_arena
            except gdb.error:
                pass

            # plan 2 (from __malloc_hook)
            if get_libc_version() < (2, 34):
                try:
                    malloc_hook_addr = AddressUtil.parse_address("(void *)&__malloc_hook")
                    if is_x86():
                        Cache.cached_main_arena = AddressUtil.align_address_to_size(malloc_hook_addr + current_arch.ptrsize, 0x20)
                    elif is_arm64():
                        mstate_size = GlibcHeap.MallocStateStruct("*0").struct_size
                        Cache.cached_main_arena = malloc_hook_addr - current_arch.ptrsize * 2 - mstate_size
                    elif is_arm32():
                        mstate_size = GlibcHeap.MallocStateStruct("*0").struct_size
                        Cache.cached_main_arena = malloc_hook_addr - current_arch.ptrsize - mstate_size
                    else:
                        raise
                    return Cache.cached_main_arena
                except gdb.error:
                    pass

            # plan 3 (from TLS)
            ptr = GlibcHeap.search_for_main_arena_from_tls()
            if ptr:
                Cache.cached_main_arena = read_int_from_memory(ptr)
                return Cache.cached_main_arena

            raise OSError("Cannot find main_arena for {}".format(current_arch.arch))

        @property
        def is_main_arena(self):
            return self.__is_main_arena

        @property
        def addr(self):
            return self.__addr

        @property
        def name(self):
            if self.is_main_arena:
                return "main_arena"
            else:
                return "*{:#x}".format(self.__addr)

        @property
        def size(self):
            # arena aligned_size
            if current_arch.ptrsize == 4:
                aligned_size = (self.__size + 7) & ~0b111
            else:
                aligned_size = (self.__size + 15) & ~0b1111
            return aligned_size

        @property
        def heap_base(self):
            if self.is_main_arena:
                return HeapbaseCommand.heap_base()
            else:
                return self.addr + self.size

        def tcachebins_addr(self, i):
            if self.heap_base is None:
                return None

            if (is_x86_32() or is_riscv32() or is_ppc32()) and not self.is_main_arena:
                arch_offset = 0
            elif is_32bit():
                arch_offset = 0
            else:
                arch_offset = 0x10

            if get_libc_version() < (2, 30):
                offset = self.TCACHE_MAX_BINS + i * current_arch.ptrsize
            else:
                offset = 2 * self.TCACHE_MAX_BINS + i * current_arch.ptrsize
            return self.heap_base + arch_offset + offset

        def fastbins_addr(self, i):
            if hasattr(self.__arena, "fastbins_addr"):
                fastbins_addr = self.__arena.fastbins_addr
            else:
                fastbins_type = [x for x in self.__arena.type.fields() if x.name == "fastbinsY"][0]
                fastbins_addr = self.__addr + fastbins_type.bitpos // 8
            return fastbins_addr + i * current_arch.ptrsize

        def top_addr(self):
            if hasattr(self.__arena, "top_addr"):
                top_addr = self.__arena.top_addr
            else:
                top_type = [x for x in self.__arena.type.fields() if x.name == "top"][0]
                top_addr = self.__addr + top_type.bitpos // 8
            return top_addr

        def last_remainder_addr(self):
            if hasattr(self.__arena, "last_remainder_addr"):
                last_remainder_addr = self.__arena.last_remainder_addr
            else:
                last_remainder_type = [x for x in self.__arena.type.fields() if x.name == "last_remainder"][0]
                last_remainder_addr = self.__addr + last_remainder_type.bitpos // 8
            return last_remainder_addr

        def bins_addr(self, i):
            if hasattr(self.__arena, "bins_addr"):
                bins_addr = self.__arena.bins_addr
            else:
                bins_type = [x for x in self.__arena.type.fields() if x.name == "bins"][0]
                bins_addr = self.__addr + bins_type.bitpos // 8
            return bins_addr + i * current_arch.ptrsize * 2

        def next_addr(self):
            if hasattr(self.__arena, "next_addr"):
                next_addr = self.__arena.next_addr
            else:
                next_type = [x for x in self.__arena.type.fields() if x.name == "next"][0]
                next_addr = self.__addr + next_type.bitpos // 8
            return next_addr

        def next_free_addr(self):
            if hasattr(self.__arena, "next_free_addr"):
                next_free_addr = self.__arena.next_free_addr
            else:
                next_free_type = [x for x in self.__arena.type.fields() if x.name == "next_free"][0]
                next_free_addr = self.__addr + next_free_type.bitpos // 8
            return next_free_addr

        def system_mem_addr(self):
            if hasattr(self.__arena, "system_mem_addr"):
                system_mem_addr = self.__arena.system_mem_addr
            else:
                system_mem_type = [x for x in self.__arena.type.fields() if x.name == "system_mem"][0]
                system_mem_addr = self.__addr + system_mem_type.bitpos // 8
            return system_mem_addr

        def tcachebin(self, i):
            """Return head chunk in tcache[i]."""
            tcache_i_head = self.tcachebins_addr(i)
            if not tcache_i_head:
                return None
            addr = AddressUtil.dereference(tcache_i_head)
            if not addr:
                return None
            return GlibcHeap.GlibcChunk(int(addr))

        def fastbin(self, i):
            """Return head chunk in fastbinsY[i]."""
            addr = int(self.fastbinsY[i])
            if addr == 0:
                return None
            return GlibcHeap.GlibcChunk(addr + 2 * current_arch.ptrsize)

        def bin(self, i):
            idx = i * 2
            fd = int(self.bins[idx])
            bw = int(self.bins[idx + 1])
            return fd, bw

        def get_next(self):
            try:
                addr_next = int(self.next)
                if addr_next == 0:
                    return None
                if addr_next == GlibcHeap.get_main_arena().addr:
                    return None
                next_arena = GlibcHeap.GlibcArena(addr_next)
                str(next_arena) # check memory error
                return next_arena
            except gdb.error:
                return None

        def __str__(self):
            arena = Color.colorify("Arena", Config.get_gef_setting("theme.heap_arena_label"))
            if self.heap_base is None:
                heap_base = "uninitialized"
            else:
                heap_base = str(ProcessMap.lookup_address(self.heap_base))
            arena_addr = str(ProcessMap.lookup_address(self.__addr))
            top = str(ProcessMap.lookup_address(self.top))
            last_remainder = str(ProcessMap.lookup_address(self.last_remainder))
            next = str(ProcessMap.lookup_address(int(self.next)))
            system_mem = int(self.system_mem)
            try:
                next_free = int(self.next_free)
                fmt = "{:s}(addr={:s}, heap_base={:s}, top={:s}, last_remainder={:s}, next={:s}, next_free={:#x}, system_mem={:#x})"
                args = (arena, arena_addr, heap_base, top, last_remainder, next, next_free, system_mem)
            except gdb.error:
                fmt = "{:s}(addr={:s}, heap_base={:s}, top={:s}, last_remainder={:s}, next={:s}, system_mem={:#x})"
                args = (arena, arena_addr, heap_base, top, last_remainder, next, system_mem)
            return fmt.format(*args)

        def tcache_list(self):
            if get_libc_version() < (2, 26):
                info("No Tcache in this version of libc")
                return {}
            if self.heap_base is None:
                return {}

            chunks_all = {}
            for i in range(self.TCACHE_MAX_BINS):
                try:
                    chunk = self.tcachebin(i)
                except gdb.MemoryError:
                    err("tcache[{:d}] is corrupted.".format(i))
                    continue
                chunks = []
                while True:
                    if chunk is None:
                        break
                    if chunk.address in chunks:
                        err("tcache[{:d}] has a loop.".format(i))
                        break # loop detected
                    chunks.append(chunk.address)
                    next_chunk = chunk.get_fwd_ptr(True)
                    if next_chunk == 0:
                        break
                    if next_chunk is None:
                        err("tcache[{:d}] is corrupted.".format(i))
                        break
                    chunk = GlibcHeap.GlibcChunk(next_chunk)
                chunks_all[i] = chunks
            return chunks_all

        def fastbins_list(self):
            def fastbin_index(sz):
                return (sz >> 4) - 2 if SIZE_SZ == 8 else (sz >> 3) - 2

            SIZE_SZ = current_arch.ptrsize
            MAX_FAST_SIZE = (80 * SIZE_SZ // 4)
            NFASTBINS = fastbin_index(MAX_FAST_SIZE) - 1
            chunks_all = {}
            for i in range(NFASTBINS):
                try:
                    chunk = self.fastbin(i)
                except gdb.MemoryError:
                    err("fastbins[{:d}] is corrupted.".format(i))
                    continue
                chunks = []
                while True:
                    if chunk is None:
                        break
                    if chunk.address in chunks:
                        err("fastbins[{:d}] has a loop.".format(i))
                        break # loop detected
                    chunks.append(chunk.address)
                    next_chunk = chunk.get_fwd_ptr(True)
                    if next_chunk == 0:
                        break
                    if next_chunk is None:
                        err("fastbins[{:d}] is corrupted.".format(i))
                        break
                    chunk = GlibcHeap.GlibcChunk(next_chunk, from_base=True)
                chunks_all[i] = chunks
            return chunks_all

        def bins_list(self, index):
            try:
                fw, bk = self.bin(index)
            except gdb.MemoryError:
                return [] # invalid
            if bk == 0x00 and fw == 0x00:
                return [] # invalid
            head = GlibcHeap.GlibcChunk(bk, from_base=True).fwd
            if fw == head:
                return [] # no entry
            chunks = []
            while fw != head:
                chunk = GlibcHeap.GlibcChunk(fw, from_base=True)
                if chunk.chunk_base_address in chunks:
                    err("bins[{:d}] has a loop.".format(index))
                    break
                chunks.append(chunk.chunk_base_address)
                fw = chunk.fwd
                if fw is None:
                    err("bins[{:d}] is corrupted.".format(index))
                    break
            return chunks

        def unsortedbin_list(self):
            chunks_all = {}
            chunks_all[0] = self.bins_list(0)
            return chunks_all

        def smallbins_list(self):
            chunks_all = {}
            for i in range(1, 63):
                chunks_all[i] = self.bins_list(i)
            return chunks_all

        def largebins_list(self):
            chunks_all = {}
            for i in range(63, 126):
                chunks_all[i] = self.bins_list(i)
            return chunks_all

        def reset_bins_info(self):
            self.cached_tcache_list = self.tcache_list()
            self.cached_tcache_addr_list = set().union(*self.cached_tcache_list.values())

            self.cached_fastbins_list = self.fastbins_list()
            self.cached_fastbins_addr_list = set().union(*self.cached_fastbins_list.values())

            self.cached_unsortedbin_list = self.unsortedbin_list()
            self.cached_unsortedbin_addr_list = self.cached_unsortedbin_list[0]

            self.cached_smallbins_list = self.smallbins_list()
            self.cached_smallbins_addr_list = set().union(*self.cached_smallbins_list.values())

            self.cached_largebins_list = self.largebins_list()
            self.cached_largebins_addr_list = set().union(*self.cached_largebins_list.values())

            self.bins_dict_for_address = {}
            for tcache_idx, tcache_list in self.cached_tcache_list.items():
                for address in set(tcache_list):
                    pos = ",".join([str(i + 1) for i, x in enumerate(tcache_list) if x == address])
                    sz = GlibcHeap.get_binsize_table()["tcache"][tcache_idx]["size"]
                    m = "tcache[idx={:d},sz={:#x}][{:s}/{:d}]".format(tcache_idx, sz, pos, len(tcache_list))
                    self.bins_dict_for_address[address] = self.bins_dict_for_address.get(address, []) + [m]
            for fastbin_idx, fastbin_list in self.cached_fastbins_list.items():
                for address in set(fastbin_list):
                    pos = ",".join([str(i + 1) for i, x in enumerate(fastbin_list) if x == address])
                    sz = GlibcHeap.get_binsize_table()["fastbins"][fastbin_idx]["size"]
                    m = "fastbins[idx={:d},sz={:#x}][{:s}/{:d}]".format(fastbin_idx, sz, pos, len(fastbin_list))
                    self.bins_dict_for_address[address] = self.bins_dict_for_address.get(address, []) + [m]

            self.bins_dict_for_base_address = {}
            for _, unsortedbin_list in self.cached_unsortedbin_list.items():
                for base_address in set(unsortedbin_list):
                    pos = ",".join([str(i + 1) for i, x in enumerate(unsortedbin_list) if x == base_address])
                    m = "unsortedbins[{:s}/{:d}]".format(pos, len(unsortedbin_list))
                    self.bins_dict_for_base_address[base_address] = self.bins_dict_for_base_address.get(base_address, []) + [m]
            for smallbin_idx, smallbin_list in self.cached_smallbins_list.items():
                for base_address in set(smallbin_list):
                    pos = ",".join([str(i + 1) for i, x in enumerate(smallbin_list) if x == base_address])
                    sz = GlibcHeap.get_binsize_table()["small_bins"][smallbin_idx]["size"]
                    m = "smallbins[idx={:d},sz={:#x}][{:s}/{:d}]".format(smallbin_idx, sz, pos, len(smallbin_list))
                    self.bins_dict_for_base_address[base_address] = self.bins_dict_for_base_address.get(base_address, []) + [m]
            for largebin_idx, largebin_list in self.cached_largebins_list.items():
                for base_address in set(largebin_list):
                    pos = ",".join([str(i + 1) for i, x in enumerate(largebin_list) if x == base_address])
                    sz_min = GlibcHeap.get_binsize_table()["large_bins"][largebin_idx]["size_min"]
                    sz_max = GlibcHeap.get_binsize_table()["large_bins"][largebin_idx]["size_max"]
                    m = "largebins[idx={:d},sz={:#x}-{:#x}][{:s}/{:d}]".format(largebin_idx, sz_min, sz_max, pos, len(largebin_list))
                    self.bins_dict_for_base_address[base_address] = self.bins_dict_for_base_address.get(base_address, []) + [m]
            return

        def is_chunk_in_tcache(self, chunk):
            return chunk.address in self.cached_tcache_addr_list

        def is_chunk_in_fastbins(self, chunk):
            return chunk.address in self.cached_fastbins_addr_list

        def is_chunk_in_unsortedbin(self, chunk):
            return chunk.chunk_base_address in self.cached_unsortedbin_addr_list

        def is_chunk_in_smallbins(self, chunk):
            return chunk.chunk_base_address in self.cached_smallbins_addr_list

        def is_chunk_in_largebins(self, chunk):
            return chunk.chunk_base_address in self.cached_largebins_addr_list

        def make_bins_info(self, address_or_chunk, skip_top=False):
            if isinstance(address_or_chunk, GlibcHeap.GlibcChunk):
                address = address_or_chunk.address
                base_address = address_or_chunk.chunk_base_address
            elif isinstance(address_or_chunk, int):
                address = address_or_chunk
                base_address = address_or_chunk

            info = []
            info.extend(self.bins_dict_for_address.get(address, []))
            info.extend(self.bins_dict_for_base_address.get(base_address, []))
            if not skip_top:
                if base_address == self.top:
                    info.append("top")
            return info

    @staticmethod
    def get_arena(address):
        if address is None or is_valid_addr(address):
            try:
                arena = GlibcHeap.GlibcArena(address)
                str(arena) # check memory error
                return arena
            except (OSError, AttributeError, gdb.MemoryError):
                err("Failed to get the arena, heap commands may not work properly.")
                return None
        else:
            # interpret `address` as the number following next from main_arena, not the address of arena.
            arena_number = address

            # main_arena
            arenas = []
            arena = GlibcHeap.get_main_arena()
            while arena:
                arenas.append(arena)
                arena = arena.get_next()

            if arena_number >= len(arenas):
                err("Failed to get the arena, heap commands may not work properly.")
                return None

            return arenas[arena_number]

    @staticmethod
    def get_main_arena():
        return GlibcHeap.get_arena(None)

    @staticmethod
    def get_all_arenas():
        arenas = []
        arena = GlibcHeap.get_main_arena()
        while arena:
            arenas.append(arena)
            arena = arena.get_next()
        return arenas

    class GlibcChunk:
        """Glibc chunk class."""
        def __init__(self, addr, from_base=False):
            self.ptrsize = current_arch.ptrsize
            if from_base:
                self.chunk_base_address = addr
                self.address = addr + 2 * self.ptrsize
            else:
                self.chunk_base_address = AddressUtil.align_address(addr - 2 * self.ptrsize)
                self.address = addr

            self.size_addr = AddressUtil.align_address(self.address - self.ptrsize)
            self.prev_size_addr = self.chunk_base_address
            return

        def get_chunk_size(self):
            return read_int_from_memory(self.size_addr) & (~0x07)

        @property
        def size(self):
            return self.get_chunk_size()

        def get_usable_size(self):
            cursz = self.get_chunk_size()
            if cursz == 0:
                return cursz
            if self.has_m_bit():
                return cursz - 2 * self.ptrsize
            return cursz - self.ptrsize

        def get_prev_chunk_size(self):
            return read_int_from_memory(self.prev_size_addr)

        def get_next_chunk(self):
            try:
                addr = self.address + self.get_chunk_size()
                return GlibcHeap.GlibcChunk(addr)
            except gdb.MemoryError:
                return None

        # if freed functions
        def get_fwd_ptr(self, sll):
            try:
                # Not a single-linked-list (sll) or no Safe-Linking support yet
                if not sll or get_libc_version() < (2, 32):
                    return read_int_from_memory(self.address)
                # Unmask ("reveal") the Safe-Linking pointer
                else:
                    return read_int_from_memory(self.address) ^ (self.address >> 12)
            except gdb.MemoryError:
                return None

        @property
        def fwd(self):
            return self.get_fwd_ptr(False)

        fd = fwd # for compat

        def get_bkw_ptr(self):
            return read_int_from_memory(self.address + self.ptrsize)

        @property
        def bck(self):
            return self.get_bkw_ptr()

        bk = bck # for compat

        def get_fd_nextsize_ptr(self):
            return read_int_from_memory(self.address + self.ptrsize * 2)

        @property
        def fd_nextsize(self):
            return self.get_fd_nextsize_ptr()

        def get_bk_nextsize_ptr(self):
            return read_int_from_memory(self.address + self.ptrsize * 3)

        @property
        def bk_nextsize(self):
            return self.get_bk_nextsize_ptr()
        # endif freed functions

        def has_p_bit(self):
            return read_int_from_memory(self.size_addr) & 0x01

        def has_m_bit(self):
            return read_int_from_memory(self.size_addr) & 0x02

        def has_n_bit(self):
            return read_int_from_memory(self.size_addr) & 0x04

        def is_used(self):
            """Check if the current block is used by:
            - checking the M bit is true
            - or checking that next chunk PREV_INUSE flag is true"""
            if self.has_m_bit():
                return True
            next_chunk = self.get_next_chunk()
            try:
                return True if next_chunk.has_p_bit() else False
            except gdb.MemoryError as e:
                # top?
                if (next_chunk.chunk_base_address & 0xfff) == 0:
                    if is_valid_addr(next_chunk.chunk_base_address - 1):
                        return False
                raise gdb.MemoryError from e

        def str_chunk_size_flag(self):
            msg = []
            if self.has_p_bit():
                msg.append("  PREV_INUSE flag: {}".format(Color.greenify("On")))
            else:
                msg.append("  PREV_INUSE flag: {}".format(Color.redify("Off")))
            if self.has_m_bit():
                msg.append("  IS_MMAPPED flag: {}".format(Color.greenify("On")))
            else:
                msg.append("  IS_MMAPPED flag: {}".format(Color.redify("Off")))
            if self.has_n_bit():
                msg.append("  NON_MAIN_ARENA flag: {}".format(Color.greenify("On")))
            else:
                msg.append("  NON_MAIN_ARENA flag: {}".format(Color.redify("Off")))
            return "\n".join(msg)

        def _str_sizes(self):
            msg = []
            failed = False

            try:
                msg.append("  Chunk size: {:#x}".format(self.get_chunk_size()))
                msg.append("  Usable size: {:#x}".format(self.get_usable_size()))
            except gdb.MemoryError:
                msg.append("  Chunk size: Cannot read at {:#x} (corrupted?)".format(self.size_addr))
                failed = True

            if self.has_p_bit():
                msg.append("  Previous chunk size: ??? (PREV_INUSE flag: On)")
            else:
                try:
                    msg.append("  Previous chunk size: {:#x}".format(self.get_prev_chunk_size()))
                except gdb.MemoryError:
                    msg.append("  Previous chunk size: Cannot read at {:#x} (corrupted?)".format(self.chunk_base_address))
                    failed = True

            if not failed:
                msg.append(self.str_chunk_size_flag())

            return "\n".join(msg)

        def _str_pointers(self):
            fwd = self.address
            bkw = self.address + self.ptrsize

            msg = []
            try:
                msg.append("  Forward pointer: {:#x}".format(self.get_fwd_ptr(False)))
            except gdb.MemoryError:
                msg.append("  Forward pointer: {:#x} (corrupted?)".format(fwd))

            try:
                msg.append("  Backward pointer: {:#x}".format(self.get_bkw_ptr()))
            except gdb.MemoryError:
                msg.append("  Backward pointer: {:#x} (corrupted?)".format(bkw))

            return "\n".join(msg)

        def str_as_alloced(self):
            return self._str_sizes()

        def str_as_freed(self):
            return "{}\n\n{}".format(self._str_sizes(), self._str_pointers())

        def flags_as_string(self):
            flags = []
            if self.has_p_bit():
                flags.append(Color.colorify("PREV_INUSE", Config.get_gef_setting("theme.heap_chunk_flag_prev_inuse")))
            if self.has_m_bit():
                flags.append(Color.colorify("IS_MMAPPED", Config.get_gef_setting("theme.heap_chunk_flag_is_mmapped")))
            if self.has_n_bit():
                flags.append(Color.colorify("NON_MAIN_ARENA", Config.get_gef_setting("theme.heap_chunk_flag_non_main_arena")))
            return "|".join(flags)

        def to_str(self, arena):
            chunk_c = Color.colorify("Chunk", Config.get_gef_setting("theme.heap_chunk_label"))
            size_c = Color.colorify_hex(self.get_chunk_size(), Config.get_gef_setting("theme.heap_chunk_size"))
            base_c = Color.colorify_hex(self.chunk_base_address, Config.get_gef_setting("theme.heap_chunk_address_freed"))
            addr_c = Color.colorify_hex(self.address, Config.get_gef_setting("theme.heap_chunk_address_freed"))
            flags = self.flags_as_string()

            # large bins
            if arena.is_chunk_in_largebins(self):
                fd = ProcessMap.lookup_address(self.fd)
                bk = ProcessMap.lookup_address(self.bk)
                if is_valid_addr(self.fd_nextsize) or is_valid_addr(self.bk_nextsize):
                    # largebin and valid (fd|bk)_nextsize
                    fd_nextsize = ProcessMap.lookup_address(self.fd_nextsize)
                    bk_nextsize = ProcessMap.lookup_address(self.bk_nextsize)
                    fmt = "{:s}(base={:s}, addr={:s}, size={:s}, flags={:s}, fd={!s}, bk={!s}, fd_nextsize={!s}, bk_nextsize={!s})"
                    msg = fmt.format(chunk_c, base_c, addr_c, size_c, flags, fd, bk, fd_nextsize, bk_nextsize)
                else:
                    fmt = "{:s}(base={:s}, addr={:s}, size={:s}, flags={:s}, fd={!s}, bk={!s})"
                    msg = fmt.format(chunk_c, base_c, addr_c, size_c, flags, fd, bk)

            # small bins / unsorted bin
            elif arena.is_chunk_in_smallbins(self) or arena.is_chunk_in_unsortedbin(self):
                fd = ProcessMap.lookup_address(self.fd)
                bk = ProcessMap.lookup_address(self.bk)
                fmt = "{:s}(base={:s}, addr={:s}, size={:s}, flags={:s}, fd={!s}, bk={!s})"
                msg = fmt.format(chunk_c, base_c, addr_c, size_c, flags, fd, bk)

            # tcache / fastbins
            elif arena.is_chunk_in_fastbins(self) or arena.is_chunk_in_tcache(self):
                fd = self.get_fwd_ptr(sll=False)
                if get_libc_version() < (2, 32):
                    fd = ProcessMap.lookup_address(fd)
                    fmt = "{:s}(base={:s}. addr={:s}, size={:s}, flags={:s}, fd={!s})"
                    msg = fmt.format(chunk_c, base_c, addr_c, size_c, flags, fd)
                else:
                    decoded_fd = ProcessMap.lookup_address(self.get_fwd_ptr(sll=True))
                    fmt = "{:s}(base={:s}, addr={:s}, size={:s}, flags={:s}, fd={:#x}(={!s}))"
                    msg = fmt.format(chunk_c, base_c, addr_c, size_c, flags, fd, decoded_fd)

            # top
            elif arena.top == self.chunk_base_address:
                fmt = "{:s}(base={:s}, addr={:s}, size={:s}, flags={:s})"
                msg = fmt.format(chunk_c, base_c, addr_c, size_c, flags)

            # used chunk
            else:
                base_c = Color.colorify_hex(self.chunk_base_address, Config.get_gef_setting("theme.heap_chunk_address_used"))
                addr_c = Color.colorify_hex(self.address, Config.get_gef_setting("theme.heap_chunk_address_used"))
                fmt = "{:s}(base={:s}, addr={:s}, size={:s}, flags={:s})"
                msg = fmt.format(chunk_c, base_c, addr_c, size_c, flags)
            return msg

        def psprint(self, arena):
            arena.reset_bins_info()
            msg = []
            msg.append(self.to_str(arena))
            if self.is_used():
                msg.append(self.str_as_alloced())
            else:
                msg.append(self.str_as_freed())
            return "\n".join(msg)

    @staticmethod
    @Cache.cache_this_session
    def get_binsize_table():
        table = {
            "tcache": {},
            "fastbins": {},
            "unsorted_bin": {},
            "small_bins": {},
            "large_bins": {},
        }

        if is_64bit():
            MIN_SIZE = 0x20
        else:
            MIN_SIZE = 0x10

        # tcache
        for i in range(64):
            # MALLOC_ALIGNMENT is changed from libc 2.26.
            # for x86_32, tcache 0x8 align is no longer used.
            # but for ARM32, or maybe other arch, still 0x8 align is used.
            if is_64bit():
                size = MIN_SIZE + i * 0x10
            elif (is_x86_32() or is_riscv32() or is_ppc32()) and get_libc_version() >= (2, 26):
                size = MIN_SIZE + i * 0x10
            else:
                size = MIN_SIZE + i * 0x8
            table["tcache"][i] = {"size": size}

        # fastbins
        if is_64bit():
            for i in range(7):
                size = MIN_SIZE + i * 0x10
                table["fastbins"][i] = {"size": size}
        elif (is_x86_32() or is_riscv32() or is_ppc32()) and get_libc_version() >= (2, 26):
            # MALLOC_ALIGNMENT is changed from libc 2.26.
            # for x86_32, fastbin exists every 8 bytes, but only used every 16 bytes.
            table["fastbins"][0] = {"size": 0x10}
            table["fastbins"][2] = {"size": 0x20}
            table["fastbins"][4] = {"size": 0x30}
            table["fastbins"][6] = {"size": 0x40}
        else:
            for i in range(7):
                size = MIN_SIZE + i * 8
                table["fastbins"][i] = {"size": size}

        # unsorted bins
        table["unsorted_bin"][0] = {}

        # smallbins
        for i in range(1, 63):
            if is_64bit() or (is_x86_32() and get_libc_version() >= (2, 26)):
                size = MIN_SIZE + (i - 1) * 0x10
            else:
                size = MIN_SIZE + (i - 1) * 0x8
            table["small_bins"][i] = {"size": size}

        # largebins
        if is_64bit():
            table["large_bins"][63] = {"size_min": 0x400, "size_max": 0x440}
            table["large_bins"][64] = {"size_min": 0x440, "size_max": 0x480}
            table["large_bins"][65] = {"size_min": 0x480, "size_max": 0x4c0}
            table["large_bins"][66] = {"size_min": 0x4c0, "size_max": 0x500}
            table["large_bins"][67] = {"size_min": 0x500, "size_max": 0x540}
            table["large_bins"][68] = {"size_min": 0x540, "size_max": 0x580}
            table["large_bins"][69] = {"size_min": 0x580, "size_max": 0x5c0}
            table["large_bins"][70] = {"size_min": 0x5c0, "size_max": 0x600}
            table["large_bins"][71] = {"size_min": 0x600, "size_max": 0x640}
            table["large_bins"][72] = {"size_min": 0x640, "size_max": 0x680}
            table["large_bins"][73] = {"size_min": 0x680, "size_max": 0x6c0}
            table["large_bins"][74] = {"size_min": 0x6c0, "size_max": 0x700}
            table["large_bins"][75] = {"size_min": 0x700, "size_max": 0x740}
            table["large_bins"][76] = {"size_min": 0x740, "size_max": 0x780}
            table["large_bins"][77] = {"size_min": 0x780, "size_max": 0x7c0}
            table["large_bins"][78] = {"size_min": 0x7c0, "size_max": 0x800}
            table["large_bins"][79] = {"size_min": 0x800, "size_max": 0x840}
            table["large_bins"][80] = {"size_min": 0x840, "size_max": 0x880}
            table["large_bins"][81] = {"size_min": 0x880, "size_max": 0x8c0}
            table["large_bins"][82] = {"size_min": 0x8c0, "size_max": 0x900}
            table["large_bins"][83] = {"size_min": 0x900, "size_max": 0x940}
            table["large_bins"][84] = {"size_min": 0x940, "size_max": 0x980}
            table["large_bins"][85] = {"size_min": 0x980, "size_max": 0x9c0}
            table["large_bins"][86] = {"size_min": 0x9c0, "size_max": 0xa00}
            table["large_bins"][87] = {"size_min": 0xa00, "size_max": 0xa40}
            table["large_bins"][88] = {"size_min": 0xa40, "size_max": 0xa80}
            table["large_bins"][89] = {"size_min": 0xa80, "size_max": 0xac0}
            table["large_bins"][90] = {"size_min": 0xac0, "size_max": 0xb00}
            table["large_bins"][91] = {"size_min": 0xb00, "size_max": 0xb40}
            table["large_bins"][92] = {"size_min": 0xb40, "size_max": 0xb80}
            table["large_bins"][93] = {"size_min": 0xb80, "size_max": 0xbc0}
            table["large_bins"][94] = {"size_min": 0xbc0, "size_max": 0xc00}
            table["large_bins"][95] = {"size_min": 0xc00, "size_max": 0xc40}
            table["large_bins"][96] = {"size_min": 0xc40, "size_max": 0xe00}
        elif is_x86_32() and get_libc_version() >= (2, 26):
            table["large_bins"][63] = {"size_min": 0x3f0, "size_max": 0x400}
            table["large_bins"][64] = {"size_min": 0x400, "size_max": 0x440}
            table["large_bins"][65] = {"size_min": 0x440, "size_max": 0x480}
            table["large_bins"][66] = {"size_min": 0x480, "size_max": 0x4c0}
            table["large_bins"][67] = {"size_min": 0x4c0, "size_max": 0x500}
            table["large_bins"][68] = {"size_min": 0x500, "size_max": 0x540}
            table["large_bins"][69] = {"size_min": 0x540, "size_max": 0x580}
            table["large_bins"][70] = {"size_min": 0x580, "size_max": 0x5c0}
            table["large_bins"][71] = {"size_min": 0x5c0, "size_max": 0x600}
            table["large_bins"][72] = {"size_min": 0x600, "size_max": 0x640}
            table["large_bins"][73] = {"size_min": 0x640, "size_max": 0x680}
            table["large_bins"][74] = {"size_min": 0x680, "size_max": 0x6c0}
            table["large_bins"][75] = {"size_min": 0x6c0, "size_max": 0x700}
            table["large_bins"][76] = {"size_min": 0x700, "size_max": 0x740}
            table["large_bins"][77] = {"size_min": 0x740, "size_max": 0x780}
            table["large_bins"][78] = {"size_min": 0x780, "size_max": 0x7c0}
            table["large_bins"][79] = {"size_min": 0x7c0, "size_max": 0x800}
            table["large_bins"][80] = {"size_min": 0x800, "size_max": 0x840}
            table["large_bins"][81] = {"size_min": 0x840, "size_max": 0x880}
            table["large_bins"][82] = {"size_min": 0x880, "size_max": 0x8c0}
            table["large_bins"][83] = {"size_min": 0x8c0, "size_max": 0x900}
            table["large_bins"][84] = {"size_min": 0x900, "size_max": 0x940}
            table["large_bins"][85] = {"size_min": 0x940, "size_max": 0x980}
            table["large_bins"][86] = {"size_min": 0x980, "size_max": 0x9c0}
            table["large_bins"][87] = {"size_min": 0x9c0, "size_max": 0xa00}
            table["large_bins"][88] = {"size_min": 0xa00, "size_max": 0xa40}
            table["large_bins"][89] = {"size_min": 0xa40, "size_max": 0xa80}
            table["large_bins"][90] = {"size_min": 0xa80, "size_max": 0xac0}
            table["large_bins"][91] = {"size_min": 0xac0, "size_max": 0xb00}
            table["large_bins"][92] = {"size_min": 0xb00, "size_max": 0xb40}
            table["large_bins"][93] = {"size_min": 0xb40, "size_max": 0xb80}
            # table["large_bins"][94] is unused
            table["large_bins"][95] = {"size_min": 0xb80, "size_max": 0xc00}
            table["large_bins"][96] = {"size_min": 0xc00, "size_max": 0xe00}
        else:
            table["large_bins"][63] = {"size_min": 0x200, "size_max": 0x240}
            table["large_bins"][64] = {"size_min": 0x240, "size_max": 0x280}
            table["large_bins"][65] = {"size_min": 0x280, "size_max": 0x2c0}
            table["large_bins"][66] = {"size_min": 0x2c0, "size_max": 0x300}
            table["large_bins"][67] = {"size_min": 0x300, "size_max": 0x340}
            table["large_bins"][68] = {"size_min": 0x340, "size_max": 0x380}
            table["large_bins"][69] = {"size_min": 0x380, "size_max": 0x3c0}
            table["large_bins"][70] = {"size_min": 0x3c0, "size_max": 0x400}
            table["large_bins"][71] = {"size_min": 0x400, "size_max": 0x440}
            table["large_bins"][72] = {"size_min": 0x440, "size_max": 0x480}
            table["large_bins"][73] = {"size_min": 0x480, "size_max": 0x4c0}
            table["large_bins"][74] = {"size_min": 0x4c0, "size_max": 0x500}
            table["large_bins"][75] = {"size_min": 0x500, "size_max": 0x540}
            table["large_bins"][76] = {"size_min": 0x540, "size_max": 0x580}
            table["large_bins"][77] = {"size_min": 0x580, "size_max": 0x5c0}
            table["large_bins"][78] = {"size_min": 0x5c0, "size_max": 0x600}
            table["large_bins"][79] = {"size_min": 0x600, "size_max": 0x640}
            table["large_bins"][80] = {"size_min": 0x640, "size_max": 0x680}
            table["large_bins"][81] = {"size_min": 0x680, "size_max": 0x6c0}
            table["large_bins"][82] = {"size_min": 0x6c0, "size_max": 0x700}
            table["large_bins"][83] = {"size_min": 0x700, "size_max": 0x740}
            table["large_bins"][84] = {"size_min": 0x740, "size_max": 0x780}
            table["large_bins"][85] = {"size_min": 0x780, "size_max": 0x7c0}
            table["large_bins"][86] = {"size_min": 0x7c0, "size_max": 0x800}
            table["large_bins"][87] = {"size_min": 0x800, "size_max": 0x840}
            table["large_bins"][88] = {"size_min": 0x840, "size_max": 0x880}
            table["large_bins"][89] = {"size_min": 0x880, "size_max": 0x8c0}
            table["large_bins"][90] = {"size_min": 0x8c0, "size_max": 0x900}
            table["large_bins"][91] = {"size_min": 0x900, "size_max": 0x940}
            table["large_bins"][92] = {"size_min": 0x940, "size_max": 0x980}
            table["large_bins"][93] = {"size_min": 0x980, "size_max": 0x9c0}
            table["large_bins"][94] = {"size_min": 0x9c0, "size_max": 0xa00}
            table["large_bins"][95] = {"size_min": 0xa00, "size_max": 0xc00}
            table["large_bins"][96] = {"size_min": 0xc00, "size_max": 0xe00}

        table["large_bins"][97] = {"size_min": 0xe00, "size_max": 0x1000}
        table["large_bins"][98] = {"size_min": 0x1000, "size_max": 0x1200}
        table["large_bins"][99] = {"size_min": 0x1200, "size_max": 0x1400}
        table["large_bins"][100] = {"size_min": 0x1400, "size_max": 0x1600}
        table["large_bins"][101] = {"size_min": 0x1600, "size_max": 0x1800}
        table["large_bins"][102] = {"size_min": 0x1800, "size_max": 0x1a00}
        table["large_bins"][103] = {"size_min": 0x1a00, "size_max": 0x1c00}
        table["large_bins"][104] = {"size_min": 0x1c00, "size_max": 0x1e00}
        table["large_bins"][105] = {"size_min": 0x1e00, "size_max": 0x2000}
        table["large_bins"][106] = {"size_min": 0x2000, "size_max": 0x2200}
        table["large_bins"][107] = {"size_min": 0x2200, "size_max": 0x2400}
        table["large_bins"][108] = {"size_min": 0x2400, "size_max": 0x2600}
        table["large_bins"][109] = {"size_min": 0x2600, "size_max": 0x2800}
        table["large_bins"][110] = {"size_min": 0x2800, "size_max": 0x2a00}
        table["large_bins"][111] = {"size_min": 0x2a00, "size_max": 0x3000}
        table["large_bins"][112] = {"size_min": 0x3000, "size_max": 0x4000}
        table["large_bins"][113] = {"size_min": 0x4000, "size_max": 0x5000}
        table["large_bins"][114] = {"size_min": 0x5000, "size_max": 0x6000}
        table["large_bins"][115] = {"size_min": 0x6000, "size_max": 0x7000}
        table["large_bins"][116] = {"size_min": 0x7000, "size_max": 0x8000}
        table["large_bins"][117] = {"size_min": 0x8000, "size_max": 0x9000}
        table["large_bins"][118] = {"size_min": 0x9000, "size_max": 0xa000}
        table["large_bins"][119] = {"size_min": 0xa000, "size_max": 0x10000}
        table["large_bins"][120] = {"size_min": 0x10000, "size_max": 0x18000}
        table["large_bins"][121] = {"size_min": 0x18000, "size_max": 0x20000}
        table["large_bins"][122] = {"size_min": 0x20000, "size_max": 0x28000}
        table["large_bins"][123] = {"size_min": 0x28000, "size_max": 0x40000}
        table["large_bins"][124] = {"size_min": 0x40000, "size_max": 0x80000}
        table["large_bins"][125] = {"size_min": 0x80000, "size_max": 0x0}
        table["large_bins"][126] = {"size_min": 0x0, "size_max": 0x0} # maybe unused
        return table


def get_libc_version():
    RE_LIBC_PATH = re.compile(r"libc6?[-_](\d+)\.(\d+)\.so")
    RE_GLIBC_VERSION = re.compile(rb"glibc (\d+)\.(\d+)")

    def get_libc_version_from_path():
        Cache.reset_gef_caches(all=True) # get_process_maps may be caching old information

        sections = ProcessMap.get_process_maps()
        for section in sections:
            r = RE_LIBC_PATH.search(section.path)
            if r:
                return tuple(int(x) for x in r.groups())

            if "libc" not in section.path:
                continue

            if is_container_attach():
                real_libc_path = Path.append_proc_root(section.path)
                if not os.path.exists(real_libc_path):
                    continue
                data = open(real_libc_path, "rb").read()

            elif is_remote_debug():
                if is_qemu_user():
                    data = None
                    for maps in ProcessMap.get_process_maps(outer=True):
                        if os.path.basename(maps.path) != os.path.basename(section.path):
                            continue
                        if maps.size != section.size:
                            continue
                        real_libc_path = maps.path
                        data = open(real_libc_path, "rb").read()
                        break
                else:
                    data = Path.read_remote_file(section.path)
                if not data:
                    continue
            else:
                if not os.path.exists(section.path):
                    continue
                data = open(section.path, "rb").read()

            r = RE_GLIBC_VERSION.search(data)
            if r:
                return tuple(int(x) for x in r.groups())
        return None

    def get_system_libc_version():
        res = GefUtil.gef_execute_external(["cat", "/proc/self/maps"], as_list=True)
        libc_targets = ("libc-2.", "libc.so.6")
        for line in res:
            if not any(kw in line for kw in libc_targets):
                continue
            path = line.split()[-1]
            if not os.path.exists(path):
                continue
            data = open(path, "rb").read()
            r = RE_GLIBC_VERSION.search(data)
            if r:
                return tuple(int(x) for x in r.groups())
        return None

    # use cache
    libc_assume_version = eval(Config.get_gef_setting("libc.assume_version"))
    if libc_assume_version != ():
        return libc_assume_version

    # resolve
    libc_version = get_libc_version_from_path()
    if libc_version is None:
        libc_version = get_system_libc_version()
    if libc_version is None:
        libc_version = (2, 39) # assume Ubuntu 24.04

    # set cache
    Config.set_gef_setting("libc.assume_version", libc_version)
    return libc_version


def titlify(text, color=None, msg_color=None):
    """Print a centered title."""
    cols = GefUtil.get_terminal_size()[1]
    if color is None:
        color = Config.get_gef_setting("theme.default_title_line")
    if msg_color is None:
        msg_color = Config.get_gef_setting("theme.default_title_message")

    msg = []
    if text:
        nb = (cols - len(text) - 2) // 2
        msg.append(Color.colorify("{} ".format(HORIZONTAL_LINE * nb), color))
        msg.append(Color.colorify(text, msg_color))
        msg.append(Color.colorify(" {}".format(HORIZONTAL_LINE * nb), color))
    else:
        msg.append(Color.colorify("{}".format(HORIZONTAL_LINE * cols), color))
    return "".join(msg)


def err(msg):
    """The wrapper of gef_print for error level message."""
    gef_print("{} {}".format(Color.colorify("[!]", "bold red"), msg))
    return


def warn(msg):
    """The wrapper of gef_print for warning level message."""
    gef_print("{} {}".format(Color.colorify("[*]", "bold yellow"), msg))
    return


def ok(msg):
    """The wrapper of gef_print for ok level message."""
    gef_print("{} {}".format(Color.colorify("[+]", "bold green"), msg))
    return


def info(msg):
    """The wrapper of gef_print for information level message."""
    gef_print("{} {}".format(Color.colorify("[+]", "bold blue"), msg))
    return


class String:
    STRING_ASCII_LOWERCASE = "abcdefghijklmnopqrstuvwxyz"
    STRING_ASCII_UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    STRING_ASCII_LETTERS = STRING_ASCII_LOWERCASE + STRING_ASCII_UPPERCASE
    STRING_DIGITS = "0123456789"
    STRING_HEXDIGITS = "0123456789abcdefABCDEF"
    STRING_PUNCTUATION = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
    STRING_WHITESPACE = " \t\n\r\x0b\x0c"
    STRING_PRINTABLE = STRING_DIGITS + STRING_ASCII_LETTERS + STRING_PUNCTUATION + STRING_WHITESPACE

    @staticmethod
    def gef_pystring(x):
        """Returns a sanitized version as string of the bytes list given in input."""
        res = str(x, encoding="utf-8")
        substs = [("\n", "\\n"), ("\r", "\\r"), ("\t", "\\t"), ("\v", "\\v"), ("\b", "\\b"), ]
        for x, y in substs:
            res = res.replace(x, y)
        return res

    @staticmethod
    def str2bytes(x):
        """Helper function for str -> bytes."""
        if isinstance(x, bytes):
            return x
        if isinstance(x, str):
            try:
                return bytes(ord(xx) for xx in x)
            except ValueError:
                # If str is UTF-8 multi-byte string, raise an error.
                # e.g.: `pi String.str2bytes(b"\xc5\x82".decode("utf-8"))`
                # In that case, you should simply encode it as UTF-8.
                return x.encode("utf-8")
        raise

    @staticmethod
    def bytes2str(x):
        """Helper function for bytes -> str."""
        if isinstance(x, str):
            return x
        if isinstance(x, bytes):
            return "".join(chr(xx) for xx in x)
        raise

    @staticmethod
    def is_hex(pattern):
        """Return whether provided string is a hexadecimal value."""
        if not pattern.startswith("0x") and not pattern.startswith("0X"):
            return False
        return len(pattern) % 2 == 0 and all(c in String.STRING_HEXDIGITS for c in pattern[2:])


def slicer(data, n):
    """Helper function for slice."""
    return [data[i:i + n] for i in range(0, len(data), n)]


def slice_unpack(data, n):
    """Helper function for slice then unpack."""
    if n in [1, 2, 4, 8]:
        length = len(data) // n
        fmt = "{:s}{:d}{:s}".format(Endian.endian_str(), length, {1: "B", 2: "H", 4: "I", 8: "Q"}[n])
        return struct.unpack(fmt, data)
    elif n == 16:
        return [u128(data[i:i + 16]) for i in range(0, len(data), 16)]
    else:
        raise


def byteswap(x, byte_size=None):
    """Helper function for byte swap."""
    byte_size = byte_size or current_arch.ptrsize
    bit_size = byte_size * 8
    s = 0
    for i in range(0, bit_size, 8):
        s += ((x >> i) & 0xff) << (bit_size - (i + 8))
    return s


def xor(a, b=None):
    """Helper function for xor.
    xor("AAA", "BBB") -> "\x03\x03\x03"
    xor(b"AAA", b"BBB") -> b"\x03\x03\x03"
    xor(["AAA", "BBB", "\x03\x03\x03"]) -> "\0\0\0"
    """
    def _xor(a, b):
        if len(a) < len(b):
            a, b = b, a
        if isinstance(a, str) and isinstance(b, str):
            return ''.join([chr(ord(c1) ^ ord(c2)) for (c1, c2) in zip(a, itertools.cycle(b))])
        elif isinstance(a, bytes) and isinstance(b, bytes):
            return bytes([c1 ^ c2 for (c1, c2) in zip(a, itertools.cycle(b))])
        elif isinstance(a, bytearray) and isinstance(b, bytearray):
            return bytearray([c1 ^ c2 for (c1, c2) in zip(a, itertools.cycle(b))])
        raise

    if b is None:
        if hasattr(a, "__iter__"):
            return functools.reduce(_xor, a)
        raise
    return _xor(a, b)


def ror(val, bits, arch_bits=64):
    """Helper function for rotate right."""
    new_val = (val >> bits) | (val << (arch_bits - bits))
    mask = (1 << arch_bits) - 1
    return new_val & mask


def rol(val, bits, arch_bits=64):
    """Helper function for rotate left."""
    new_val = (val << bits) | (val >> (arch_bits - bits))
    mask = (1 << arch_bits) - 1
    return new_val & mask


def hexdump(source, length=0x10, separator=".", color=True, show_symbol=True, base=0x00, unit=1):
    """Return the hexdump of `src` argument."""

    style = {
        "nonprintable": "yellow",
        "printable": "white",
        "00": "bright_black",
        "0a": "blue",
        "ff": "green",
    }

    def style_byte(b, color=True):
        sbyte = "{:02x}".format(b)
        if not color or Config.get_gef_setting("highlight.regex"):
            return sbyte
        if sbyte in style:
            st = style[sbyte]
        elif chr(b) in String.STRING_PRINTABLE:
            st = style["printable"]
        else:
            st = style["nonprintable"]
        return Color.colorify(sbyte, st)

    align = AddressUtil.get_format_address_width()

    tmp = []
    max_sym_width = 0
    for i in range(0, len(source), length):
        addr = base + i

        if show_symbol:
            sym = Symbol.get_symbol_string(addr)
        else:
            sym = ""
        if len(sym) > max_sym_width:
            max_sym_width = len(sym)

        chunk = bytearray(source[i : i + length])

        if unit == 1:
            padlen = (0x10 - len(chunk)) * 3
        else:
            padlen = (0x10 - len(chunk)) // unit * (unit * 2 + 3)
            if len(chunk) % unit:
                padlen += ((unit - len(chunk) % unit) * 2)

        hexa = [style_byte(b, color=color) for b in chunk]
        if unit > 1:
            hexa = ["0x" + "".join(x[::-1]) for x in slicer(hexa, unit)]
        if unit == 1:
            hexa[min(len(hexa), 8) - 1] += " " # double the blank at the 8th byte
        hexa = " ".join(hexa)
        padded_hexa = hexa + " " * padlen

        text = "".join([chr(b) if 0x20 <= b < 0x7f else separator for b in chunk])
        text_padlen = 0x10 - len(text)
        padded_text = text + " " * text_padlen

        tmp.append([addr, sym, hexa, padded_hexa, padded_text])

    result = []
    for addr, sym, _, data, text in tmp:
        result.append("{:#0{:d}x}:{:<{:d}}    {:s}    |  {:s}  |".format(
            addr, align, sym, max_sym_width, data, text,
        ))
    return "\n".join(result)


class Symbol:
    # `info symbol` called from gdb_get_location is heavy processing.
    # Moreover, AddressUtil.recursive_dereference causes each address to be resolved every time.
    # Cache.cache_until_next is not effective as-is, as it is cleared by Cache.reset_gef_caches() each time the `stepi` runs.
    # Fortunately, symbol information rarely changes.
    # I decided to keep the cache until it is explicitly cleared.
    @staticmethod
    @Cache.cache_this_session
    def gdb_get_location(address):
        """ex: 0xffffffff9f6bd2a0 -> ('commit_creds', 0)"""
        if address is None:
            return None

        # Do not use gdb.format_address available from gdb 13.x,
        # because symbols added with add-symbol-temporary may not be recognized.

        # slow path uses `info symbol` command
        name = None
        sym = gdb.execute("info symbol {:#x}".format(address), to_string=True)
        if sym.startswith("No symbol matches"):
            return None

        i = sym.find(" in section ")
        sym = sym[:i].split()
        if len(sym) >= 3 and sym[-1].isdigit():
            name = " ".join(sym[:-2])
            offset = int(sym[-1])
        else:
            name = " ".join(sym)
            offset = 0
        return name, offset

    @staticmethod
    @Cache.cache_this_session
    def get_symbol_string(addr, nosymbol_string=""):
        """ex: 0xffffffff9f6bd2a1 -> ' <commit_creds+0x1>'"""
        try:
            if isinstance(addr, str):
                addr = Color.remove_color(addr)
                addr = int(addr, 16)
            ret = Symbol.gdb_get_location(addr)
            if ret is None:
                return nosymbol_string
        except (ValueError, gdb.error):
            return nosymbol_string

        sym_name, sym_offset = ret[0], ret[1]
        if addr - sym_offset == 0:
            return nosymbol_string

        sym_name = Instruction.smartify_text(sym_name)
        if sym_offset == 0:
            return " <{}>".format(sym_name)
        else:
            return " <{}+{:#x}>".format(sym_name, sym_offset)

    @staticmethod
    def get_ksymaddr(sym):
        """ex: 'commit_creds' -> 0xffffffff9f6bd2a0"""
        try:
            res = gdb.execute("ksymaddr-remote --quiet --no-pager --exact {:s}".format(sym), to_string=True)
            return int(res.split()[0], 16)
        except (gdb.error, IndexError, ValueError):
            return None

    @staticmethod
    def get_ksymaddr_multiple(sym):
        """ex: 'set_is_seen' -> [0xffffffffba146db0,0xffffffffba6d84e0,0xffffffffba6dd170]"""
        out = []
        try:
            ret = gdb.execute("ksymaddr-remote --quiet --no-pager --exact {:s}".format(sym), to_string=True)
            for line in ret.splitlines():
                addr = int(line.split()[0], 16)
                out.append(addr)
            return out
        except (gdb.error, IndexError, ValueError):
            return None

    @staticmethod
    def get_ksymaddr_symbol(addr):
        """ex: 0xffffffff9f6bd2a0 -> 'commit_creds'"""
        try:
            res = gdb.execute("ksymaddr-remote --quiet --no-pager {:#x}".format(addr), to_string=True)
            res = res.splitlines()[-1]
            return res.split()[2]
        except (gdb.error, IndexError):
            return None


def load_capstone(f):
    """Decorator wrapper to load capstone."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        try:
            __import__("capstone")
            return f(*args, **kwargs)
        except ImportError as err:
            msg = "Missing `capstone` package for Python. Install with `pip install capstone`."
            raise ImportWarning(msg) from err

    return wrapper


def load_unicorn(f):
    """Decorator wrapper to load unicorn."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        try:
            __import__("unicorn")

            if is_ppc32(): # unicorn does not support ppc64
                try:
                    __import__("unicorn.ppc_const")
                except ImportError:
                    pass

            if is_riscv32() or is_riscv64():
                try:
                    __import__("unicorn.riscv_const")
                except ImportError:
                    pass

            if is_s390x():
                try:
                    __import__("unicorn.s390x_const")
                except ImportError:
                    pass

            return f(*args, **kwargs)
        except ImportError as err:
            msg = "Missing `unicorn` package for Python. Install with `pip install unicorn`."
            raise ImportWarning(msg) from err

    return wrapper


def load_keystone(f):
    """Decorator wrapper to load keystone."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        try:
            __import__("keystone")
            return f(*args, **kwargs)
        except ImportError as err:
            msg = "Missing `keystone-engine` package, install with: `pip install keystone-engine`."
            raise ImportWarning(msg) from err

    return wrapper


def load_ropper(f):
    """Decorator wrapper to load ropper."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        try:
            __import__("ropper")
            return f(*args, **kwargs)
        except ImportError as err:
            msg = "Missing `ropper` package, install with: `pip install ropper`."
            raise ImportWarning(msg) from err

    return wrapper


class Disasm:
    __gef_prev_arch__ = None # previous valid result of edb.selected_frame().architecture()

    @staticmethod
    def gdb_disassemble(start_pc, nb_insn=None, end_pc=None):
        """Disassemble instructions from `start_pc` (Integer). Return an iterator of Instruction objects.
        This is the backend used by Disasm.gef_disassemble by default."""
        if start_pc is None:
            return None

        try:
            arch = gdb.selected_frame().architecture()
            Disasm.__gef_prev_arch__ = arch
        except gdb.error:
            # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
            # At this time arch cannot be resolved, but if it was successful before, it will be used.
            if Disasm.__gef_prev_arch__ is None:
                raise
            arch = Disasm.__gef_prev_arch__

        kwargs = {}
        if nb_insn is not None:
            kwargs["count"] = nb_insn
        if end_pc is not None:
            kwargs["end_pc"] = end_pc

        for insn in arch.disassemble(start_pc, **kwargs):
            address = insn["addr"]
            asm = insn["asm"].rstrip().split(None, 1)
            if len(asm) > 1:
                mnemo, operands = asm
                if "\t" in operands:
                    first, second = operands.rsplit("\t", 1)
                    operands = [x.strip() for x in first.split(",")] + [second]
                else:
                    operands = [x.strip() for x in operands.split(",")]
            else:
                mnemo, operands = asm[0], []

            location = Symbol.get_symbol_string(address, nosymbol_string=" <NO_SYMBOL>")

            if is_arm32() and insn["addr"] & 1:
                opcodes = read_memory(insn["addr"] - 1, insn["length"])
            else:
                opcodes = read_memory(insn["addr"], insn["length"])

            yield Instruction(address, location, mnemo, operands, opcodes)
        return None

    @staticmethod
    def gdb_get_nth_previous_instruction_address(addr, n):
        """Return the address (Integer) of the `n`-th instruction before `addr`."""
        if addr is None:
            return None

        # fixed-length ABI
        if current_arch.instruction_length:
            return max(0, addr - n * current_arch.instruction_length)

        # variable-length ABI
        cur_insn_addr = get_insn(addr).address

        # we try to find a good set of previous instructions by "guessing" disassembling backwards
        # the 15 comes from the longest instruction valid size
        for i in range(15 * n, 0, -1):
            try:
                insns = list(Disasm.gdb_disassemble(addr - i, end_pc=cur_insn_addr))
            except gdb.MemoryError:
                # this is because we can hit an unmapped page trying to read backward
                break

            # 1. check that the disassembled instructions list size can satisfy
            if len(insns) < n + 1: # we expect the current instruction plus the n before it
                continue

            # If the list of instructions is longer than what we need, then we
            # could get lucky and already have more than what we need, so slice down
            insns = insns[-n - 1:]

            # 2. check that the sequence ends with the current address
            if insns[-1].address != cur_insn_addr:
                continue

            # 3. check all instructions are valid
            if all(insn.is_valid() for insn in insns):
                return insns[0].address
        return None

    @staticmethod
    @load_capstone
    def capstone_get_nth_previous_instruction_address(addr, n, cs=None):
        """Return the address (Integer) of the `n`-th instruction before `addr`."""
        if addr is None:
            return None

        if cs is None:
            cs = sys.modules["capstone"].Cs(*UnicornKeystoneCapstone.get_capstone_arch())

        # fixed-length ABI
        if current_arch.instruction_length:
            return max(0, addr - n * current_arch.instruction_length)

        # variable-length ABI

        # we try to find a good set of previous instructions by "guessing" disassembling backwards
        # the 15 comes from the longest instruction valid size
        for i in range(15 * n, 0, -1):
            try:
                code = read_memory(addr - i, i)
            except gdb.MemoryError:
                continue

            insns = list(cs.disasm(code, addr - i))

            # 1. check that the disassembled instructions list size can satisfy
            if len(insns) < n:
                continue
            insns = insns[-n:]

            # 2. check that the sequence ends with the current address
            if insns[-1].address + insns[-1].size != addr:
                continue

            return insns[0].address
        return None

    @staticmethod
    @load_capstone
    def capstone_disassemble(location, nb_insn, **kwargs):
        """Disassemble `nb_insn` instructions after `addr` and `nb_prev` before `addr` using the capstone disassembler.
        Return an iterator of Instruction objects.
        This is the backend used by Disasm.gef_disassemble if specified in the config.
        It is also called directly from some commands such as Disasm.capstone_disassemble."""
        def cs_insn_to_gef_insn(cs_insn):
            loc = Symbol.get_symbol_string(cs_insn.address, nosymbol_string=" <NO_SYMBOL>")
            ops = cs_insn.op_str.split(", ")
            return Instruction(cs_insn.address, loc, cs_insn.mnemonic, ops, cs_insn.bytes)

        capstone = sys.modules["capstone"]
        _arch = kwargs.get("arch", None)
        _mode = kwargs.get("mode", None)
        _endian = kwargs.get("endian", None)
        arch, mode = UnicornKeystoneCapstone.get_capstone_arch(arch=_arch, mode=_mode, endian=_endian)
        try:
            cs = capstone.Cs(arch, mode)
            cs.detail = True # noqa
        except capstone.CsError:
            err("CsError")
            return

        # fix location by nb_prev
        nb_prev = kwargs.get("nb_prev", 0)
        if nb_prev > 0:
            _location = Disasm.capstone_get_nth_previous_instruction_address(location, nb_prev, capstone.Cs(arch, mode))
            if _location is not None:
                location = _location
                nb_insn += nb_prev

        # split reading by page_size
        read_addr = location
        read_size = gef_getpagesize() - (location & gef_getpagesize_mask_low())

        # fix for arm thumb2 mode
        if is_arm32() and read_addr & 1:
            read_addr -= 1
            read_size += 1

        skip = kwargs.get("skip", 0)
        arch_inst_length = current_arch.instruction_length or 1
        used_bytes = 0
        code_remain = bytes.fromhex(kwargs.get("code", ""))
        dont_read = "code" in kwargs

        # A loop to read the required memory until the specified length is reached
        while True:
            if not dont_read and len(code_remain) < gef_getpagesize():
                # not enough code to disassemble, so read the memory to pool
                try:
                    read_data = read_memory(read_addr, read_size)
                except gdb.MemoryError:
                    err("Memory read error at {:#x}-{:#x}".format(read_addr, read_addr + read_size))
                    return
                code_remain += read_data

            # cs.disasm will terminate disassemble if an invalid instruction is detected.
            # This is a loop to display (bad) and increment and reinterpret code.
            while True:
                # disasm
                for insn in cs.disasm(code_remain, location):
                    used_bytes += len(insn.bytes)
                    if skip:
                        skip -= 1
                        continue
                    yield cs_insn_to_gef_insn(insn)
                    nb_insn -= 1
                    if nb_insn == 0:
                        return

                # success (disassembled something)
                if used_bytes > 0:
                    break

                # failure (maybe the code is invalid)
                yield Instruction(location, "", "(bad)", [], code_remain[:arch_inst_length])
                nb_insn -= 1
                if nb_insn == 0:
                    return
                location += arch_inst_length
                code_remain = code_remain[arch_inst_length:]

            # go away only the size used
            code_remain = code_remain[used_bytes:] # There may be instructions placed across page boundaries.
            location += used_bytes
            used_bytes = 0

            read_addr += read_size # 1st loop is the offset size. 2nd~ loops are the page size.
            read_size = gef_getpagesize()
        return

    @staticmethod
    def gef_disassemble(addr, nb_insn, nb_prev=0):
        """Disassemble `nb_insn` instructions after `addr` and `nb_prev` before `addr`.
        Return an iterator of Instruction objects.
        Use Disasm.gdb_disassemble or Disasm.capstone_disassemble according to the settings."""
        if Config.get_gef_setting("context.use_capstone"):
            get_nth_prev_address = Disasm.capstone_get_nth_previous_instruction_address
            get_insns = Disasm.capstone_disassemble
        else:
            get_nth_prev_address = Disasm.gdb_get_nth_previous_instruction_address
            get_insns = Disasm.gdb_disassemble

        if nb_prev:
            for i in range(nb_prev):
                nb_prev_addr = get_nth_prev_address(addr, nb_prev - i)
                if not nb_prev_addr:
                    continue
                for insn in get_insns(nb_prev_addr, nb_prev):
                    if insn.address == addr:
                        break
                    yield insn
                break

        nb_insn = max(1, nb_insn)
        for insn in get_insns(addr, nb_insn):
            yield insn
        return None

    @staticmethod
    def gef_instruction_n(addr, n):
        """Return the `n`-th instruction after `addr` as an Instruction object."""
        try:
            return list(Disasm.gef_disassemble(addr, n + 1))[n]
        except IndexError:
            return None


def get_insn(addr=None):
    """Return the current instruction as an Instruction object."""
    if addr is None:
        if not is_alive():
            return None
        addr = current_arch.pc
    return Disasm.gef_instruction_n(addr, 0)


def get_insn_next(addr=None):
    """Return the next instruction as an Instruction object."""
    if addr is None:
        if not is_alive():
            return None
        addr = current_arch.pc
    return Disasm.gef_instruction_n(addr, 1)


def get_insn_prev(addr=None):
    """Return the prev instruction as an Instruction object."""
    if addr is None:
        if not is_alive():
            return None
        addr = current_arch.pc
    try:
        gen = Disasm.gef_disassemble(addr, 0, nb_prev=2)
        gen.__next__()
        return gen.__next__()
    except (gdb.error, StopIteration):
        return None


class Checksec:
    @staticmethod
    @Cache.cache_until_next
    def get_cet_status_old_interface():
        # https://lore.kernel.org/lkml/1531342544.15351.37.camel@intel.com/
        sp = current_arch.sp
        mem = {}

        # backup
        for i in range(3):
            # *addr = SHSTK/IBT status
            # *(addr + 1) = SHSTK base address
            # *(addr + 2) = SHSTK size
            addr = sp + current_arch.ptrsize * i
            mem[addr] = read_memory(addr, current_arch.ptrsize)

        res = gdb.execute("call-syscall arch_prctl 0x3001 {:#x}".format(sp), to_string=True) # ARCH_CET_STATUS
        output_line = res.splitlines()[-1]
        ret = int(output_line.split()[2], 0)

        sp_value = read_int_from_memory(sp)

        # revert
        for addr, data in mem.items():
            write_memory(addr, data)

        # check ret
        if ret != 0:
            return None
        return sp_value

    @staticmethod
    @Cache.cache_until_next
    def get_cet_status_new_interface():
        # https://www.kernel.org/doc/html/next/arch/x86/shstk.html
        sp = current_arch.sp
        mem = {}

        # backup
        for i in range(1):
            # *addr = SHSTK status
            addr = sp + current_arch.ptrsize * i
            mem[addr] = read_memory(addr, current_arch.ptrsize)

        res = gdb.execute("call-syscall arch_prctl 0x5005 {:#x}".format(sp), to_string=True) # ARCH_SHSTK_STATUS
        output_line = res.splitlines()[-1]
        ret = int(output_line.split()[2], 0)

        sp_value = read_int_from_memory(sp)

        # revert
        for addr, data in mem.items():
            write_memory(addr, data)

        if ret != 0:
            return None
        return sp_value

    @staticmethod
    @Cache.cache_until_next
    def get_cet_status_via_procfs():
        # https://www.kernel.org/doc/html/next/arch/x86/shstk.html
        dic = {}
        if is_remote_debug():
            if Pid.get_pid(remote=True):
                remote_status = "/proc/{:d}/status".format(Pid.get_pid(remote=True))
            data = Path.read_remote_file(remote_status, as_byte=True) # qemu-user is failed here, it is ok
            if not data:
                return None
        else:
            if Pid.get_pid():
                local_status = "/proc/{:d}/status".format(Pid.get_pid())
            data = open(local_status, "rb").read()
            if not data:
                return None

        if b"x86_Thread_features:" not in data:
            return False # unsupported

        dic["shstk"] = b"x86_Thread_features: shstk" in data
        dic["shstk lock"] = b"x86_Thread_features_locked: shstk" in data
        return dic

    @staticmethod
    def get_mte_status():
        auxv = Auxv.get_auxiliary_values()
        HWCAP2_MTE = 1 << 18
        if auxv and "AT_HWCAP2" in auxv and (auxv["AT_HWCAP2"] & HWCAP2_MTE) == 0:
            return None # Unsupported
        res = gdb.execute("call-syscall prctl 0x38 0 0 0 0", to_string=True) # PR_GET_TAGGED_ADDR_CTRL
        output_line = res.splitlines()[-1]
        ret = int(output_line.split()[2], 0)

        pQ = lambda a: struct.pack("<Q", a & 0xffffffffffffffff)
        uq = lambda a: struct.unpack("<q", a)[0]
        u2i = lambda a: uq(pQ(a))
        return u2i(ret)

    @staticmethod
    def get_pac_status():
        auxv = Auxv.get_auxiliary_values()
        HWCAP_PACA = 1 << 30
        HWCAP_PACG = 1 << 31
        if auxv and "AT_HWCAP" in auxv and (auxv["AT_HWCAP"] & (HWCAP_PACA | HWCAP_PACG)) == 0:
            return None # Unsupported
        res = gdb.execute("call-syscall prctl 0x3d 0 0 0 0", to_string=True) # PR_PAC_GET_ENABLED_KEYS
        output_line = res.splitlines()[-1]
        ret = int(output_line.split()[2], 0)

        pQ = lambda a: struct.pack("<Q", a & 0xffffffffffffffff)
        uq = lambda a: struct.unpack("<q", a)[0]
        u2i = lambda a: uq(pQ(a))
        return u2i(ret)


class Endian:
    @staticmethod
    @Cache.cache_this_session
    def get_endian():
        """Return the binary endianness."""
        endian = gdb.execute("show endian", to_string=True).strip().lower()
        if "little endian" in endian:
            return Elf.LITTLE_ENDIAN
        if "big endian" in endian:
            return Elf.BIG_ENDIAN
        raise EnvironmentError("Invalid endianness")

    @staticmethod
    def is_big_endian():
        return Endian.get_endian() == Elf.BIG_ENDIAN

    @staticmethod
    def is_little_endian():
        return not Endian.is_big_endian()

    @staticmethod
    @Cache.cache_this_session
    def endian_str():
        return "<" if Endian.is_little_endian() else ">"


class Architecture:
    """Generic metaclass for the architecture supported by GEF."""
    __metaclass__ = abc.ABCMeta

    # base properties

    @abc.abstractproperty
    def arch(self):
        pass

    @abc.abstractproperty
    def mode(self):
        pass

    @abc.abstractproperty
    def load_condition(self):
        pass

    # register properties

    @abc.abstractproperty
    def all_registers(self):
        pass

    @abc.abstractproperty
    def alias_registers(self):
        pass

    @abc.abstractproperty
    def special_registers(self):
        pass

    @abc.abstractproperty
    def flag_register(self):
        pass

    @abc.abstractproperty
    def flags_table(self):
        pass

    @abc.abstractproperty
    def return_register(self):
        pass

    @abc.abstractproperty
    def function_parameters(self):
        pass

    @abc.abstractproperty
    def syscall_register(self):
        pass

    @abc.abstractproperty
    def syscall_parameters(self):
        pass

    # architecture properties

    @abc.abstractproperty
    def bit_length(self):
        pass

    @abc.abstractproperty
    def endianness(self):
        pass

    @abc.abstractproperty
    def instruction_length(self):
        pass

    @abc.abstractproperty
    def has_delay_slot(self):
        pass

    @abc.abstractproperty
    def has_syscall_delay_slot(self):
        pass

    @abc.abstractproperty
    def has_ret_delay_slot(self):
        pass

    @abc.abstractproperty
    def stack_grow_down(self):
        pass

    @abc.abstractproperty
    def tls_supported(self):
        pass

    # module properties

    @abc.abstractproperty
    def keystone_support(self):
        pass

    @abc.abstractproperty
    def capstone_support(self):
        pass

    @abc.abstractproperty
    def unicorn_support(self):
        pass

    # instruction properties

    @abc.abstractproperty
    def nop_insn(self):
        pass

    @abc.abstractproperty
    def infloop_insn(self):
        pass

    @abc.abstractproperty
    def trap_insn(self):
        pass

    @abc.abstractproperty
    def ret_insn(self):
        pass

    @abc.abstractproperty
    def syscall_insn(self):
        pass

    # instruction methods

    @abc.abstractmethod
    def is_syscall(self, insn):
        pass

    @abc.abstractmethod
    def is_call(self, insn):
        pass

    @abc.abstractmethod
    def is_jump(self, insn):
        pass

    @abc.abstractmethod
    def is_ret(self, insn):
        pass

    @abc.abstractmethod
    def is_conditional_branch(self, insn):
        pass

    @abc.abstractmethod
    def is_branch_taken(self, insn):
        pass

    # register methods

    @abc.abstractmethod
    def flag_register_to_human(self, val=None):
        pass

    @abc.abstractmethod
    def get_ra(self, insn, frame):
        pass

    @abc.abstractmethod
    def get_tls(self):
        pass

    @abc.abstractmethod
    def decode_cookie(self, value, cookie):
        pass

    @abc.abstractmethod
    def encode_cookie(self, value, cookie):
        pass

    @abc.abstractmethod
    def mprotect_asm(self, addr, size, perm):
        pass

    @property
    def pc(self):
        return get_register("$pc")

    @property
    def sp(self):
        return get_register("$sp")

    @property
    def ptrsize(self):
        return AddressUtil.get_memory_alignment()

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            i -= len(self.function_parameters)
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = sp + (i * sz)
            val = read_int_from_memory(loc)
            key = "[sp + {:#x}]".format(i * sz)
            return key, val

    __aliased_registers = None

    # {"$zero":"$zero/$x0", ...}
    def get_aliased_registers(self):
        if self.__aliased_registers is not None:
            return self.__aliased_registers
        self.__aliased_registers = {}
        for reg in self.all_registers:
            if self.alias_registers and reg in self.alias_registers:
                reg_str = "{:s}/{:s}".format(reg, self.alias_registers[reg])
            else:
                reg_str = reg
            self.__aliased_registers[reg] = reg_str
        return self.__aliased_registers

    __aliased_registers_max_len = None

    # max(len("$zero/$x0"), ...)
    def get_aliased_registers_name_max(self):
        if self.__aliased_registers_max_len is not None:
            return self.__aliased_registers_max_len
        maxlen = max([len(v) for v in self.get_aliased_registers().values()])
        self.__aliased_registers_max_len = maxlen
        return self.__aliased_registers_max_len

    __registers_max_len = None

    def get_registers_name_max(self):
        if self.__registers_max_len is not None:
            return self.__registers_max_len
        maxlen = max([len(v) for v in self.all_registers if v != self.flag_register])
        self.__registers_max_len = maxlen
        return self.__registers_max_len

    @staticmethod
    def flags_to_human(reg_value, value_table):
        """Return a human readable string showing the flag states."""
        flags = []
        for i in value_table:
            if reg_value & (1 << i):
                flag_str = Color.boldify(value_table[i].upper())
            else:
                flag_str = value_table[i].lower()
            flags.append(flag_str)
        return "{:#x} [{}]".format(reg_value, " ".join(flags))


class RISCV(Architecture):
    arch = "RISCV"
    mode = "32"

    load_condition = [
        # Elf.EM_RISCV cannot determine whether it is 32-bit or 64-bit, so it should not be used.
        "RISCV",
        "RISCV32",
        "RISCV:RV32",
    ]

    # https://msyksphinz-self.github.io/riscv-isadoc/html/index.html
    all_registers = [
        "$zero", "$ra", "$sp", "$gp", "$tp", "$t0", "$t1", "$t2",
        "$fp", "$s1", "$a0", "$a1", "$a2", "$a3", "$a4", "$a5",
        "$a6", "$a7", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
        "$s8", "$s9", "$s10", "$s11", "$t3", "$t4", "$t5", "$t6",
        "$pc",
    ]
    alias_registers = {
        "$zero": "$x0", "$ra": "$x1", "$sp": "$x2", "$gp": "$x3",
        "$tp": "$x4/$s0", "$t0": "$x5", "$t1": "$x6", "$t2": "$x7",
        "$fp": "$x8", "$s1": "$x9", "$a0": "$x10", "$a1": "$x11",
        "$a2": "$x12", "$a3": "$x13", "$a4": "$x14", "$a5": "$x15",
        "$a6": "$x16", "$a7": "$x17", "$s2": "$x18", "$s3": "$x19",
        "$s4": "$x20", "$s5": "$x21", "$s6": "$x22", "$s7": "$x23",
        "$s8": "$x24", "$s9": "$x25", "$s10": "$x26", "$s11": "$x27",
        "$t3": "$x28", "$t4": "$x29", "$t5": "$x30", "$t6": "$x31",
    }
    flag_register = None # RISC-V has no flags register
    return_register = "$a0"
    function_parameters = ["$a0", "$a1", "$a2", "$a3", "$a4", "$a5", "$a6", "$a7"]
    syscall_register = "$a7"
    syscall_parameters = ["$a0", "$a1", "$a2", "$a3", "$a4", "$a5"]

    bit_length = 32
    endianness = "little"
    instruction_length = None # variable length
    has_delay_slot = False
    has_syscall_delay_slot = False
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = True
    unicorn_support = True

    nop_insn = b"\x13\x00\x00\x00" # nop
    infloop_insn = b"\x6f\x00\x00\x00" # j self
    trap_insn = b"\x73\x00\x10\x00" # ebreak
    ret_insn = b"\x67\x80\x00\x00" # ret
    syscall_insn = b"\x73\x00\x00\x00" # ecall

    def is_syscall(self, insn):
        return insn.mnemonic in ["ecall"]

    def is_call(self, insn):
        if self.is_ret(insn):
            return False
        if insn.mnemonic in ["jal", "jalr", "c.jal", "c.jalr"]:
            return True
        return False

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        if insn.mnemonic in ["c.j", "c.jr"]:
            return True
        return False

    def is_ret(self, insn):
        mnemo = insn.mnemonic
        if mnemo == "ret":
            return True
        elif mnemo == "jalr":
            return insn.operands[:3] == ["zero", "ra", "0"]
        elif mnemo == "c.jalr":
            return insn.operands[0] == "ra"
        return False

    def is_conditional_branch(self, insn):
        branch_mnemos = [
            "beq", "bne", "blt", "bge", "bltu", "bgeu",
            "c.beqz", "c.bnez",
        ]
        return insn.mnemonic in branch_mnemos

    def is_branch_taken(self, insn):
        def long_to_twos_complement(v):
            """Convert a python long value to its two's complement."""
            if is_32bit():
                if v & 0x80000000:
                    return v - 0x100000000
            elif is_64bit():
                if v & 0x8000000000000000:
                    return v - 0x10000000000000000
            else:
                raise OSError("RISC-V: ELF file is not ELF32 or ELF64. This is not currently supported")
            return v

        mnemo = insn.mnemonic
        condition = mnemo[1:]

        if condition.endswith("z"):
            # r2 is the zero register if we are comparing to 0
            rs1 = get_register(insn.operands[0])
            rs2 = get_register("$zero")
            condition = condition[:-1]
        elif len(insn.operands) > 2:
            # r2 is populated with the second operand
            rs1 = get_register(insn.operands[0])
            rs2 = get_register(insn.operands[1])
        else:
            raise OSError("RISC-V: Failed to get rs1 and rs2 for instruction: `{}`".format(insn))

        # If the conditional operation is not unsigned, convert the python long into
        # its two's complement
        if not condition.endswith("u"):
            rs2 = long_to_twos_complement(rs2)
            rs1 = long_to_twos_complement(rs1)
        else:
            condition = condition[:-1]

        if condition == "eq":
            if rs1 == rs2:
                taken, reason = True, "{}={}".format(rs1, rs2)
            else:
                taken, reason = False, "{}!={}".format(rs1, rs2)
        elif condition == "ne":
            if rs1 != rs2:
                taken, reason = True, "{}!={}".format(rs1, rs2)
            else:
                taken, reason = False, "{}={}".format(rs1, rs2)
        elif condition == "lt":
            if rs1 < rs2:
                taken, reason = True, "{}<{}".format(rs1, rs2)
            else:
                taken, reason = False, "{}>={}".format(rs1, rs2)
        elif condition == "ge":
            if rs1 < rs2:
                taken, reason = True, "{}>={}".format(rs1, rs2)
            else:
                taken, reason = False, "{}<{}".format(rs1, rs2)
        else:
            raise OSError("RISC-V: Conditional instruction `{:s}` not supported yet".format(insn))

        return taken, reason

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$ra")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        return get_register("$tp")

    def decode_cookie(self, value, cookie):
        return value

    def encode_cookie(self, value, cookie):
        return value

    def mprotect_asm(self, addr, size, perm):

        def p(x):
            return p32(int(x, 2))

        def xor(reg1, reg2, reg3):
            fmt = "0b00000_00_{:05b}_{:05b}_100_{:05b}_01100_11"
            return p(fmt.format(reg3, reg2, reg1))

        def slli(reg1, reg2, imm):
            fmt = "0b00000_{:07b}_{:05b}_001_{:05b}_00100_11"
            return p(fmt.format(imm, reg2, reg1))

        def addi(reg1, reg2, imm):
            fmt = "0b{:012b}_{:05b}_000_{:05b}_00100_11"
            return p(fmt.format(imm, reg2, reg1))

        _NR_mprotect = 226
        insns = [
            xor(10, 10, 10), # xor a0, a0, a0
            addi(10, 10, (addr >> 20) & 0xfff), # addi a0, a0, addr[31:20]
            slli(10, 10, 12), # slli a0, a0, 12
            addi(10, 10, (addr >> 8) & 0xfff), # addi a0, a0, addr[19:8]
            slli(10, 10, 8), # slli a0, a0, 8
            addi(10, 10, (addr >> 0) & 0xff), # addi a0, a0, addr[7:0]

            xor(11, 11, 11), # xor a1, a1, a1
            addi(11, 11, (size >> 20) & 0xfff), # addi a1, a1, size[31:20]
            slli(11, 11, 12), # slli a1, a1, 12
            addi(11, 11, (size >> 8) & 0xfff), # addi a1, a1, size[19:8]
            slli(11, 11, 8), # slli a1, a1, 8
            addi(11, 11, (size >> 0) & 0xff), # addi a1, a1, size[7:0]

            xor(12, 12, 12), # xor a2, a2, a2
            addi(12, 12, (perm >> 20) & 0xfff), # addi a2, a2, perm[31:20]
            slli(12, 12, 12), # slli a2, a2, 12
            addi(12, 12, (perm >> 8) & 0xfff), # addi a2, a2, perm[19:8]
            slli(12, 12, 8), # slli a2, a2, 8
            addi(12, 12, (perm >> 0) & 0xff), # addi a2, a2, perm[7:0]

            addi(17, 0, _NR_mprotect), # addi a7, zero, _NR_mprotect
            p("0b00000_00_00000_00000_000_00000_11100_11"), # ecall
        ]
        return b"".join(insns)


class RISCV64(RISCV):
    arch = "RISCV"
    mode = "64"

    load_condition = [
        # Elf.EM_RISCV cannot determine whether it is 32-bit or 64-bit, so it should not be used.
        "RISCV64",
        "RISCV:RV64",
    ]

    bit_length = 64

    def mprotect_asm(self, addr, size, perm):

        def p(x):
            return p32(int(x, 2))

        def xor(reg1, reg2, reg3):
            fmt = "0b00000_00_{:05b}_{:05b}_100_{:05b}_01100_11"
            return p(fmt.format(reg3, reg2, reg1))

        def slli(reg1, reg2, imm):
            fmt = "0b00000_{:07b}_{:05b}_001_{:05b}_00100_11"
            return p(fmt.format(imm, reg2, reg1))

        def addi(reg1, reg2, imm):
            fmt = "0b{:012b}_{:05b}_000_{:05b}_00100_11"
            return p(fmt.format(imm, reg2, reg1))

        _NR_mprotect = 226
        insns = [
            xor(10, 10, 10), # xor a0, a0, a0
            addi(10, 10, (addr >> 52) & 0xfff), # addi a0, a0, addr[63:52]
            slli(10, 10, 12), # slli a0, a0, 12
            addi(10, 10, (addr >> 40) & 0xfff), # addi a0, a0, addr[51:40]
            slli(10, 10, 12), # slli a0, a0, 12
            addi(10, 10, (addr >> 28) & 0xfff), # addi a0, a0, addr[39:28]
            slli(10, 10, 12), # slli a0, a0, 12
            addi(10, 10, (addr >> 16) & 0xfff), # addi a0, a0, addr[27:16]
            slli(10, 10, 12), # slli a0, a0, 12
            addi(10, 10, (addr >> 4) & 0xfff), # addi a0, a0, addr[15:4]
            slli(10, 10, 4), # slli a0, a0, 4
            addi(10, 10, (addr >> 0) & 0xf), # addi a0, a0, addr[3:0]

            xor(11, 11, 11), # xor a1, a1, a1
            addi(11, 11, (size >> 52) & 0xfff), # addi a1, a1, size[63:52]
            slli(11, 11, 12), # slli a1, a1, 12
            addi(11, 11, (size >> 40) & 0xfff), # addi a1, a1, size[51:40]
            slli(11, 11, 12), # slli a1, a1, 12
            addi(11, 11, (size >> 28) & 0xfff), # addi a1, a1, size[39:28]
            slli(11, 11, 12), # slli a1, a1, 12
            addi(11, 11, (size >> 16) & 0xfff), # addi a1, a1, size[27:16]
            slli(11, 11, 12), # slli a1, a1, 12
            addi(11, 11, (size >> 4) & 0xfff), # addi a1, a1, size[15:4]
            slli(11, 11, 4), # slli a1, a1, 4
            addi(11, 11, (size >> 0) & 0xf), # addi a1, a1, size[3:0]

            xor(12, 12, 12), # xor a2, a2, a2
            addi(12, 12, (perm >> 52) & 0xfff), # addi a2, a2, perm[63:52]
            slli(12, 12, 12), # slli a2, a2, 12
            addi(12, 12, (perm >> 40) & 0xfff), # addi a2, a2, perm[51:40]
            slli(12, 12, 12), # slli a2, a2, 12
            addi(12, 12, (perm >> 28) & 0xfff), # addi a2, a2, perm[39:28]
            slli(12, 12, 12), # slli a2, a2, 12
            addi(12, 12, (perm >> 16) & 0xfff), # addi a2, a2, perm[27:16]
            slli(12, 12, 12), # slli a2, a2, 12
            addi(12, 12, (perm >> 4) & 0xfff), # addi a2, a2, perm[15:4]
            slli(12, 12, 4), # slli a2, a2, 4
            addi(12, 12, (perm >> 0) & 0xf), # addi a2, a2, perm[3:0]

            addi(17, 0, _NR_mprotect), # addi a7, zero, _NR_mprotect
            p("0b00000_00_00000_00000_000_00000_11100_11"), # ecall
        ]
        return b"".join(insns)


class ARM(Architecture):
    arch = "ARM"

    load_condition = [
        Elf.EM_ARM,
        "ARM",
        "ARM_ANY",
        "ARMV2",
        "ARMV2A",
        "ARMV3",
        "ARMV4",
        "ARMV4T",
        "ARMV5",
        "ARMV5T",
        "ARMV5TE",
        "ARMV5TEJ",
        "ARMV6",
        "ARMV6K",
        "ARMV6KZ",
        "ARMV6T2",
        "ARMV7",
    ]

    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$sp", "$lr", "$pc",
        "$cpsr",
    ]
    alias_registers = {
        "$r11": "$fp", "$r12": "$ip",
        "$sp": "$r13", "$lr": "$r14", "$pc": "$r15",
    }
    flag_register = "$cpsr"
    thumb_bit = 5

    flags_table = {
        31: "negative",
        30: "zero",
        29: "carry",
        28: "overflow",
        7: "interrupt",
        6: "fast",
        thumb_bit: "thumb",
    }
    return_register = "$r0"
    function_parameters = ["$r0", "$r1", "$r2", "$r3"]
    syscall_register = "$r7"
    syscall_parameters = ["$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6"]

    def is_thumb(self):
        """Determine if the machine is currently in THUMB mode."""
        if not is_alive():
            return False
        cpsr = get_register(self.flag_register)
        if cpsr is None:
            return False
        return cpsr & (1 << self.thumb_bit)

    @property
    def mode(self):
        if self.is_thumb():
            return "THUMB"
        else:
            return "ARM"

    bit_length = 32
    endianness = "little / big"

    @property
    def instruction_length(self):
        # Thumb instructions have variable-length (2 or 4-byte)
        if self.is_thumb():
            return None # variable length
        else:
            return 4

    has_delay_slot = False
    has_syscall_delay_slot = False
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = True
    capstone_support = True
    unicorn_support = True

    # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0041c/Caccegih.html
    @property
    def nop_insn(self):
        if self.is_thumb():
            return b"\x00\xbf" # nop
        else:
            return b"\x01\x10\xa0\xe1" # mov r1, r1

    @property
    def infloop_insn(self):
        if self.is_thumb():
            return b"\xfe\xe7" # b #0
        else:
            return b"\xfe\xff\xff\xea" # b #0

    @property
    def trap_insn(self):
        if self.is_thumb():
            return b"\x00\xbe" # bkpt #0
        else:
            return b"\x70\x00\x20\xe1" # bkpt #0

    @property
    def ret_insn(self):
        if self.is_thumb():
            return b"\xf7\x46" # mov pc, lr
        else:
            return b"\x0e\xf0\xa0\xe1" # mov pc, lr

    @property
    def syscall_insn(self):
        if self.is_thumb():
            return b"\x00\xdf" # svc 0x0
        else:
            return b"\x00\x00\x00\xef" # svc 0x0

    @property
    def pc(self):
        pc = get_register("$pc")
        if self.is_thumb():
            pc += 1
        return pc

    def is_syscall(self, insn):
        return insn.mnemonic in ["svc", "swi"]

    def is_call(self, insn):
        conditions = [
            "", "eq", "ne", "lt", "le", "gt", "ge", "vs", "vc",
            "mi", "pl", "hi", "ls", "cs", "cc", "hs", "lo", "al",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"bl{cc}", f"bl{cc}.n", f"bl{cc}.w", f"blx{cc}", f"blx{cc}.n", f"blx{cc}.w"]:
                return True
        return False

    def is_jump(self, insn):
        if self.is_ret(insn):
            return False
        if self.is_conditional_branch(insn):
            return True
        if insn.mnemonic in ["b", "b.n", "b.w", "bx", "bx.n", "bx.w"]:
            return True
        if insn.mnemonic in ["mov", "mov.n", "mov.w", "ldr", "ldr.n", "ldr.w", "add", "add.n", "add.w"]:
            return insn.operands[0] == "pc"
        return False

    def is_ret(self, insn):
        load_mnemos = [
            "pop", "ldm", "ldmea", "ldmed", "ldmfa",
            "ldmfd", "ldmia", "ldmib", "ldmda", "ldmdb",
            "ldm.n", "ldmea.n", "ldmed.n", "ldmfa.n",
            "ldmfd.n", "ldmia.n", "ldmib.n", "ldmda.n", "ldmdb.n",
            "ldm.w", "ldmea.w", "ldmed.w", "ldmfa.w",
            "ldmfd.w", "ldmia.w", "ldmib.w", "ldmda.w", "ldmdb.w",
        ]
        if insn.mnemonic in load_mnemos:
            return "pc}" in "".join(insn.operands)
        if insn.mnemonic in ["b", "b.n", "b.w", "bx", "bx.n", "bx.w"]:
            return insn.operands[0] == "lr"
        if insn.mnemonic in ["mov", "mov.n", "mov.w"]:
            return insn.operands[:2] == ["pc", "lr"]
        if insn.mnemonic == "rfe":
            return True
        return False

    def is_conditional_branch(self, insn):
        conditions = [
            "eq", "ne", "lt", "le", "gt", "ge", "vs", "vc",
            "mi", "pl", "hi", "ls", "cs", "cc", "hs", "lo", "al",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"b{cc}", f"b{cc}.n", f"b{cc}.w", f"bx{cc}", f"bx{cc}.n", f"bx{cc}.w"]:
                return True
        if insn.mnemonic in ["cbnz", "cbz", "tbnz", "tbz"]:
            return True
        return False

    def is_branch_taken(self, insn):
        mnemo, operands = insn.mnemonic, insn.operands
        # ref: http://www.davespace.co.uk/arm/introduction-to-arm/conditional.html
        flags = {self.flags_table[k]: k for k in self.flags_table}
        val = get_register(self.flag_register)
        taken, reason = False, ""

        if val is not None:
            zero = bool(val & (1 << flags["zero"]))
            negative = bool(val & (1 << flags["negative"]))
            overflow = bool(val & (1 << flags["overflow"]))
            carry = bool(val & (1 << flags["carry"]))
        else:
            zero = False
            negative = False
            overflow = False
            carry = False

        if mnemo in ["cbnz", "cbz", "tbnz", "tbz"]:
            reg = operands[0]
            op = get_register(reg)
            if mnemo == "cbnz":
                if op != 0:
                    taken, reason = True, "{}!=0".format(reg)
                else:
                    taken, reason = False, "{}==0".format(reg)
            elif mnemo == "cbz":
                if op == 0:
                    taken, reason = True, "{}==0".format(reg)
                else:
                    taken, reason = False, "{}!=0".format(reg)
            elif mnemo == "tbnz":
                # operands[1] has a #, then the number
                i = int(operands[1].lstrip("#"))
                if (op & (1 << i)) != 0:
                    taken, reason = True, "{}&1<<{}!=0".format(reg, i)
                else:
                    taken, reason = False, "{}&1<<{}==0".format(reg, i)
            elif mnemo == "tbz":
                # operands[1] has a #, then the number
                i = int(operands[1].lstrip("#"))
                if (op & (1 << i)) == 0:
                    taken, reason = True, "{}&1<<{}==0".format(reg, i)
                else:
                    taken, reason = False, "{}&1<<{}!=0".format(reg, i)
        elif mnemo.endswith("eq"):
            taken, reason = zero, "Z"
        elif mnemo.endswith("ne"):
            taken, reason = not zero, "!Z"
        elif mnemo.endswith("lt"):
            taken, reason = negative != overflow, "N!=V"
        elif mnemo.endswith("le"):
            taken, reason = zero or negative != overflow, "Z || N!=V"
        elif mnemo.endswith("gt"):
            taken, reason = not zero and negative == overflow, "!Z && N==V"
        elif mnemo.endswith("ge"):
            taken, reason = negative == overflow, "N==V"
        elif mnemo.endswith("vs"):
            taken, reason = overflow, "V"
        elif mnemo.endswith("vc"):
            taken, reason = not overflow, "!V"
        elif mnemo.endswith("mi"):
            taken, reason = negative, "N"
        elif mnemo.endswith("pl"):
            taken, reason = not negative, "N==0"
        elif mnemo.endswith("hi"):
            taken, reason = carry and not zero, "C && !Z"
        elif mnemo.endswith("ls"):
            taken, reason = not carry or zero, "!C || Z"
        elif mnemo.endswith("cs") or mnemo.endswith("hs"):
            taken, reason = carry, "C"
        elif mnemo.endswith("cc") or mnemo.endswith("lo"):
            taken, reason = not carry, "!C"
        return taken, reason

    __SCR_available = None
    __mode_dic = {
        # encoding: [mode, PL]
        0b10000: ["User", 0],
        0b10001: ["FIQ", 1],
        0b10010: ["IRQ", 1],
        0b10011: ["Supervisor", 1],
        0b10110: ["Monitor", 1],
        0b10111: ["Abort", 1],
        0b11010: ["Hypervisor", 2],
        0b11011: ["Undefined", 1],
        0b11111: ["System", 1],
    }

    def flag_register_to_human(self, val=None):
        # http://www.botskool.com/user-pages/tutorials/electronics/arm-7-tutorial-part-1
        if val is None:
            reg = self.flag_register
            val = get_register(reg) & 0xffffffff

        key = val & 0b11111
        CurrentMode, CurrentPL = self.__mode_dic[key]

        if self.__SCR_available is False: # for speed up
            mode = " [Mode={:s}({:#07b},PL{:d})]".format(CurrentMode, key, CurrentPL)
        else:
            scr = get_register("$SCR")
            if scr is not None:
                self.__SCR_available = True
                secure_state = ["Secure", "Non-Secure"][scr & 1]
                mode = " [Mode={:s}({:#07b},PL{:d}),{:s}]".format(CurrentMode, key, CurrentPL, secure_state)
            else:
                self.__SCR_available = False
                mode = " [Mode={:s}({:#07b},PL{:d})]".format(CurrentMode, key, CurrentPL)
        return Architecture.flags_to_human(val, self.flags_table) + mode

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                # If it's a pop, we have to peek into the stack, otherwise use lr
                if insn.mnemonic == "pop":
                    ra_addr = current_arch.sp + (len(insn.operands) - 1) * AddressUtil.get_memory_alignment()
                    ra = to_unsigned_long(AddressUtil.dereference(ra_addr))
                elif insn.mnemonic == "ldr":
                    return to_unsigned_long(AddressUtil.dereference(current_arch.sp))
                else: # 'bx lr' or 'add pc, lr, #0'
                    return get_register("$lr")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        if is_in_kernel() or is_rr():
            return None
        if self.is_thumb():
            codes = [b"\x1d\xee", b"\x70\x2f"] # mrc p15, #0, r2, c13, c0, #3
        else:
            codes = [b"\x70\x2f\x1d\xee"] # mrc p15, #0, r2, c13, c0, #3
        ret = ExecAsm(codes).exec_code()
        return ret["reg"]["$r2"]

    def decode_cookie(self, value, cookie):
        return value ^ cookie

    def encode_cookie(self, value, cookie):
        return value ^ cookie

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 125
        insns = [
            "mov r7, {:d}".format(_NR_mprotect),
            "movw r0, #{:#x}".format((addr >> 16) & 0xffff),
            "lsl r0, r0, 16",
            "orr r0, #{:#x}".format((addr >> 0) & 0xffff),
            "movw r1, #{:#x}".format((size >> 16) & 0xffff),
            "lsl r1, r1, 16",
            "orr r1, #{:#x}".format((size >> 0) & 0xffff),
            "mov r2, {:d}".format(perm),
            "svc 0",
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)


class AARCH64(ARM):
    arch = "ARM64"
    mode = "ARM"

    load_condition = [
        Elf.EM_AARCH64,
        "AARCH64",
        "ARM64",
        "ARMV8",
        "ARMV8-A",
        "ARMV9",
        "ARMV9-A",
    ]

    all_registers = [
        "$x0", "$x1", "$x2", "$x3", "$x4", "$x5", "$x6", "$x7",
        "$x8", "$x9", "$x10", "$x11", "$x12", "$x13", "$x14", "$x15",
        "$x16", "$x17", "$x18", "$x19", "$x20", "$x21", "$x22", "$x23",
        "$x24", "$x25", "$x26", "$x27", "$x28", "$x29", "$x30", "$sp",
        "$pc", "$cpsr", "$fpsr", "$fpcr",
    ]
    alias_registers = {
        "$x16": "$ip0", "$x17": "$ip1", "$x29": "$fp", "$x30": "$lr",
    }
    flag_register = "$cpsr"
    flags_table = {
        31: "negative",
        30: "zero",
        29: "carry",
        28: "overflow",
        7: "interrupt",
        6: "fast",
    }
    return_register = "$x0"
    function_parameters = ["$x0", "$x1", "$x2", "$x3", "$x4", "$x5", "$x6", "$x7"]
    syscall_register = "$x8"
    syscall_parameters = ["$x0", "$x1", "$x2", "$x3", "$x4", "$x5"]

    bit_length = 64
    endianness = "little"
    instruction_length = 4

    nop_insn = b"\x1f\x20\x03\xd5" # nop
    infloop_insn = b"\x00\x00\x00\x14" # b #0
    trap_insn = b"\x00\x00\x20\xd4" # brk #0
    ret_insn = b"\xc0\x03\x5f\xd6" # ret
    syscall_insn = b"\x01\x00\x00\xd4" # svc #0x0

    @property
    def pc(self):
        return get_register("$pc")

    def is_syscall(self, insn):
        return insn.mnemonic == "svc" and insn.operands[0] == "#0x0"

    def is_call(self, insn):
        return insn.mnemonic in ["bl", "blr"]

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        return insn.mnemonic in ["b", "br"]

    def is_ret(self, insn):
        if insn.mnemonic in ["ret", "eret"]:
            return True
        if insn.mnemonic == "ldp" and "pc" in insn.operands:
            return True
        return False

    def is_conditional_branch(self, insn):
        # https://www.element14.com/community/servlet/JiveServlet/previewBody/41836-102-1-229511/ARM.Reference_Manual.pdf
        # sect. 5.1.1
        if insn.mnemonic in ["cbnz", "cbz", "tbnz", "tbz"]:
            return True
        if insn.mnemonic.startswith("b."):
            return True
        return False

    # is_branch_taken is the same as ARM

    __SCR_EL3_available = None

    def flag_register_to_human(self, val=None):
        # http://events.linuxfoundation.org/sites/events/files/slides/KoreaLinuxForum-2014.pdf
        if val is None:
            reg = self.flag_register
            val = get_register(reg) & 0xffffffff

        if self.__SCR_EL3_available is False: # for speed up
            mode = " [EL={:d},SP={:d}]".format((val >> 2) & 0b11, val & 0b11)
        else:
            scr = get_register("$SCR_EL3")
            if scr is not None:
                self.__SCR_EL3_available = True
                secure_state = ["Secure", "Non-Secure"][scr & 1]
                mode = " [EL={:d},SP={:d},{:s}]".format((val >> 2) & 0b11, val & 0b11, secure_state)
            else:
                self.__SCR_EL3_available = False
                mode = " [EL={:d},SP={:d}]".format((val >> 2) & 0b11, val & 0b11)

        return Architecture.flags_to_human(val, self.flags_table) + mode

    def get_tls(self):
        if is_in_kernel():
            return None
        tls = get_register("$TPIDR_EL0")
        if tls is None:
            tls = get_register("$tpidr")
        return tls

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 226
        insns = [
            "mov x8, {:d}".format(_NR_mprotect),
            "movz x0, {:#x}".format(addr & 0xffff),
            "movk x0, {:#x}, lsl 16".format((addr >> 16) & 0xffff),
            "movk x0, {:#x}, lsl 32".format((addr >> 32) & 0xffff),
            "movk x0, {:#x}, lsl 48".format((addr >> 48) & 0xffff),
            "movz x1, {:#x}".format(size & 0xffff),
            "movk x1, {:#x}, lsl 16".format((size >> 16) & 0xffff),
            "movk x1, {:#x}, lsl 32".format((size >> 32) & 0xffff),
            "movk x1, {:#x}, lsl 48".format((size >> 48) & 0xffff),
            "mov x2, {:d}".format(perm),
            "svc 0",
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)


class X86(Architecture):
    arch = "X86"
    mode = "32"

    load_condition = [
        Elf.EM_386,
        "X86",
        "I386",
        "I386:INTEL",
    ]

    gpr_registers = ["$eax", "$ebx", "$ecx", "$edx", "$esp", "$ebp", "$esi", "$edi", "$eip", "$eflags"]
    special_registers = ["$cs", "$ss", "$ds", "$es", "$fs", "$gs"]
    flag_register = "$eflags"
    all_registers = gpr_registers + special_registers
    alias_registers = {}
    flags_table = {
        21: "ident",
        #20: "virtual_interrupt_pending",
        #19: "virtual_interrupt",
        18: "align",
        17: "vx86",
        16: "resume",
        #15: N/A
        14: "nested",
        #12-13: "iopl",
        11: "overflow",
        10: "direction",
        9: "interrupt",
        8: "trap",
        7: "sign",
        6: "zero",
        #5: N/A
        4: "adjust",
        #3: N/A
        2: "parity",
        #1: N/A
        0: "carry",
    }
    return_register = "$eax"
    function_parameters = ["$esp"] # but unused because x86 uses stack
    syscall_register = "$eax"
    syscall_parameters = ["$ebx", "$ecx", "$edx", "$esi", "$edi", "$ebp"]

    bit_length = 32
    endianness = "little"
    instruction_length = None # variable length
    has_delay_slot = False
    has_syscall_delay_slot = False
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = True
    capstone_support = True
    unicorn_support = True

    nop_insn = b"\x90" # nop
    infloop_insn = b"\xeb\xfe" # jmp 0
    trap_insn = b"\xcc" # int3
    ret_insn = b"\xc3" # ret
    syscall_insn = b"\xcd\x80" # int 0x80

    def flag_register_to_human(self, val=None):
        if val is None:
            reg = self.flag_register
            val = get_register(reg) & 0xffffffff
        mode = " [Ring={:d}]".format(get_register("$cs") & 0b11)
        return Architecture.flags_to_human(val, self.flags_table) + mode

    def is_syscall(self, insn):
        if insn.mnemonic in ["sysenter", "syscall"]:
            return True
        if insn.mnemonic == "int" and insn.operands[0] == "0x80":
            return True
        return False

    def is_call(self, insn):
        return insn.mnemonic == "call"

    def is_jump(self, insn):
        return insn.mnemonic == "jmp" or self.is_conditional_branch(insn)

    def is_ret(self, insn):
        if insn.mnemonic in ["ret", "retf"]:
            return True
        if insn.mnemonic in ["sysret"]:
            return True
        if insn.mnemonic in ["iret", "iretd", "iretw"]:
            return True
        return False

    def is_conditional_branch(self, insn):
        branch_mnemos = [
            "ja", "jnbe", "jae", "jnb", "jnc", "jb", "jc", "jnae", "jbe", "jna",
            "jcxz", "jecxz", "jrcxz", "je", "jz", "jg", "jnle", "jge", "jnl",
            "jl", "jnge", "jle", "jng", "jne", "jnz", "jno", "jnp", "jpo", "jns",
            "jo", "jp", "jpe", "js",
        ]
        return insn.mnemonic in branch_mnemos

    def is_branch_taken(self, insn):
        mnemo = insn.mnemonic
        # all kudos to fG! (https://github.com/gdbinit/Gdbinit/blob/master/gdbinit#L1654)
        flags = {self.flags_table[k]: k for k in self.flags_table}
        val = get_register(self.flag_register)
        taken, reason = False, ""

        zero = bool(val & (1 << flags["zero"]))
        sign = bool(val & (1 << flags["sign"]))
        overflow = bool(val & (1 << flags["overflow"]))
        carry = bool(val & (1 << flags["carry"]))
        parity = bool(val & (1 << flags["parity"]))

        if mnemo in ["ja", "jnbe"]:
            taken, reason = not carry and not zero, "!C && !Z"
        elif mnemo in ["jae", "jnb", "jnc"]:
            taken, reason = not carry, "!C"
        elif mnemo in ["jb", "jc", "jnae"]:
            taken, reason = carry, "C"
        elif mnemo in ["jbe", "jna"]:
            taken, reason = carry or zero, "C || Z"
        elif mnemo in ["jcxz", "jecxz", "jrcxz"]:
            cx = get_register("$rcx") if self.mode == "64" else get_register("$ecx")
            taken, reason = cx == 0, "!$CX"
        elif mnemo in ["je", "jz"]:
            taken, reason = zero, "Z"
        elif mnemo in ["jne", "jnz"]:
            taken, reason = not zero, "!Z"
        elif mnemo in ["jg", "jnle"]:
            taken, reason = not zero and sign == overflow, "!Z && S==O"
        elif mnemo in ["jge", "jnl"]:
            taken, reason = sign == overflow, "S==O"
        elif mnemo in ["jl", "jnge"]:
            taken, reason = sign != overflow, "S!=O"
        elif mnemo in ["jle", "jng"]:
            taken, reason = zero or sign != overflow, "Z || S!=O"
        elif mnemo in ["jo"]:
            taken, reason = overflow, "O"
        elif mnemo in ["jno"]:
            taken, reason = not overflow, "!O"
        elif mnemo in ["jpe", "jp"]:
            taken, reason = parity, "P"
        elif mnemo in ["jnp", "jpo"]:
            taken, reason = not parity, "!P"
        elif mnemo in ["js"]:
            taken, reason = sign, "S"
        elif mnemo in ["jns"]:
            taken, reason = not sign, "!S"
        return taken, reason

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                if insn.mnemonic == "ret":
                    ra = to_unsigned_long(AddressUtil.dereference(current_arch.sp))
                elif insn.mnemonic == "retf": # eip, cs
                    ra = to_unsigned_long(AddressUtil.dereference(current_arch.sp))
                elif insn.mnemonic == "sysret": # ecx
                    ra = get_register("$ecx")
                elif insn.mnemonic in ["iret", "iretd", "iretw"]: # eip, cs, eflags, esp, ss
                    reg = to_unsigned_long(AddressUtil.dereference(current_arch.sp))
                    seg = AddressUtil.dereference(current_arch.sp + current_arch.ptrsize) & 0xffff
                    if get_register("$cs") == 0x08:
                        return ((seg << 4) + reg) & (0x1fffff if X86_16.A20 else 0x0fffff)
                    return reg
            elif frame.older():
                ra = frame.older().pc()
        except (gdb.error, AttributeError):
            pass
        return ra

    def get_tls(self):
        if is_in_kernel():
            return None
        return self.get_gs()

    def decode_cookie(self, value, cookie):
        return ror(value, 9, 32) ^ cookie

    def encode_cookie(self, value, cookie):
        return rol(value ^ cookie, 9, 32)

    def get_fs(self):
        # fastest path
        fs = get_register("$fs_base")
        if fs is not None:
            return fs
        # fast path
        if not is_remote_debug() and not is_in_kernel() and not is_qiling() and not is_rr():
            PTRACE_ARCH_PRCTL = 30
            ARCH_GET_FS = 0x1003
            pid, lwpid, tid = gdb.selected_thread().ptid
            ppvoid = ctypes.POINTER(ctypes.c_void_p)
            value = ppvoid(ctypes.c_void_p())
            value.contents.value = 0
            libc = ctypes.CDLL("libc.so.6")
            ret = libc.ptrace(PTRACE_ARCH_PRCTL, lwpid, value, ARCH_GET_FS)
            if ret == 0: # success
                return value.contents.value or 0
        # slow path
        if not is_kvm_enabled() and not is_qiling() and not is_rr():
            codes = [b"\x64\xa1\x00\x00\x00\x00"] # mov eax, dword ptr fs:[0x0]
            ret = ExecAsm(codes).exec_code()
            return ret["reg"]["$eax"]
        return None

    def get_gs(self):
        # fastest path
        gs = get_register("$gs_base")
        if gs is not None:
            return gs
        # fast path
        if not is_remote_debug() and not is_in_kernel() and not is_qiling() and not is_rr():
            PTRACE_ARCH_PRCTL = 30
            ARCH_GET_GS = 0x1004
            pid, lwpid, tid = gdb.selected_thread().ptid
            ppvoid = ctypes.POINTER(ctypes.c_void_p)
            value = ppvoid(ctypes.c_void_p())
            value.contents.value = 0
            libc = ctypes.CDLL("libc.so.6")
            ret = libc.ptrace(PTRACE_ARCH_PRCTL, lwpid, value, ARCH_GET_GS)
            if ret == 0: # success
                return value.contents.value or 0
        # slow path
        if not is_kvm_enabled() and not is_qiling() and not is_rr():
            codes = [b"\x65\xa1\x00\x00\x00\x00"] # mov eax, dword ptr gs:[0x0]
            ret = ExecAsm(codes).exec_code()
            return ret["reg"]["$eax"]
        return None

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 125
        insns = [
            "mov eax, {:d}".format(_NR_mprotect),
            "mov ebx, {:d}".format(addr),
            "mov ecx, {:d}".format(size),
            "mov edx, {:d}".format(perm),
            "int 0x80",
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)

    def get_ith_parameter(self, i, in_func=True):
        if in_func:
            i += 1 # Account for RA being at the top of the stack
        sp = current_arch.sp
        sz = current_arch.ptrsize
        loc = sp + (i * sz)
        val = read_int_from_memory(loc)
        key = "[sp + {:#x}]".format(i * sz)
        return key, val

    def read28(self, addr):
        codes = [
            b"\x8b\x00", # mov eax, dword ptr [eax]
            b"\x8b\x09", # mov ecx, dword ptr [ecx]
            b"\x8b\x12", # mov edx, dword ptr [edx]
            b"\x8b\x1b", # mov ebx, dword ptr [ebx]
            b"\x8b\x24\x24", # mov esp, dword ptr [esp]
            # If I rewrite ebp, an error message will be displayed and it will be annoying, so I will skip it.
            #b"\x8b\x6d\x00", # mov ebp, dword ptr [ebp]
            b"\x8b\x36", # mov esi, dword ptr [esi]
            b"\x8b\x3f", # mov edi, dword ptr [edi]
        ]
        regs = [
            "$eax", "$ebx", "$ecx", "$edx", "$esp", "$esi", "$edi",
        ]
        regs = {reg: addr + i * current_arch.ptrsize for i, reg in enumerate(regs)}
        ret = ExecAsm(codes, regs=regs, step=len(codes)).exec_code()
        values = [ret["reg"][reg] for reg in regs]
        return b"".join([p32(v) for v in values])


class X86_64(X86):
    arch = "X86"
    mode = "64"

    load_condition = [
        Elf.EM_X86_64,
        "X64",
        "AMD64",
        "X86_64",
        "X86-64",
        "I386:X86-64",
        "I386:X86-64:INTEL",
    ]

    gpr_registers = [
        "$rax", "$rbx", "$rcx", "$rdx", "$rsp", "$rbp", "$rsi", "$rdi", "$rip",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$eflags",
    ]
    all_registers = gpr_registers + X86.special_registers
    alias_registers = {}

    return_register = "$rax"
    function_parameters = ["$rdi", "$rsi", "$rdx", "$rcx", "$r8", "$r9"]
    syscall_register = "$rax"
    syscall_parameters = ["$rdi", "$rsi", "$rdx", "$r10", "$r8", "$r9"]

    bit_length = 64

    syscall_insn = b"\x0f\x05" # syscall

    def is_syscall(self, insn):
        return insn.mnemonic in ["sysenter", "syscall"]

    def is_ret(self, insn):
        if insn.mnemonic in ["ret", "retf"]:
            return True
        if insn.mnemonic in ["sysret", "sysretd", "sysretq"]:
            return True
        if insn.mnemonic in ["iret", "iretd", "iretq", "iretw"]:
            return True
        return False

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                if insn.mnemonic == "ret":
                    ra = to_unsigned_long(AddressUtil.dereference(current_arch.sp))
                elif insn.mnemonic == "retf": # rip, cs
                    ra = to_unsigned_long(AddressUtil.dereference(current_arch.sp))
                elif insn.mnemonic in ["sysret", "sysretd", "sysretq"]: # rcx
                    ra = get_register("$rcx")
                elif insn.mnemonic in ["iret", "iretd", "iretq", "iretw"]: # rip, cs, rflags, rsp, ss
                    ra = to_unsigned_long(AddressUtil.dereference(current_arch.sp))
            elif frame.older():
                ra = frame.older().pc()
        except (gdb.error, AttributeError):
            pass
        return ra

    def get_tls(self):
        if is_in_kernel():
            return None
        return self.get_fs()

    def decode_cookie(self, value, cookie):
        return ror(value, 17, 64) ^ cookie

    def encode_cookie(self, value, cookie):
        return rol(value ^ cookie, 17, 64)

    def get_fs(self):
        # fastest path
        fs = get_register("$fs_base")
        if fs is not None:
            return fs
        # fast path
        if not is_remote_debug() and not is_in_kernel() and not is_qiling() and not is_rr():
            PTRACE_ARCH_PRCTL = 30
            ARCH_GET_FS = 0x1003
            pid, lwpid, tid = gdb.selected_thread().ptid
            ppvoid = ctypes.POINTER(ctypes.c_void_p)
            value = ppvoid(ctypes.c_void_p())
            value.contents.value = 0
            libc = ctypes.CDLL("libc.so.6")
            ret = libc.ptrace(PTRACE_ARCH_PRCTL, lwpid, value, ARCH_GET_FS)
            if ret == 0: # success
                return value.contents.value or 0
        # slow path
        if not is_kvm_enabled() and not is_qiling() and not is_rr():
            codes = [b"\x64\x48\xa1\x00\x00\x00\x00\x00\x00\x00\x00"] # movabs rax, qword ptr fs:[0x0]
            ret = ExecAsm(codes).exec_code()
            return ret["reg"]["$rax"]
        return None

    def get_gs(self):
        # fastest path
        gs = get_register("$gs_base")
        if gs is not None:
            return gs
        # fast path
        if not is_remote_debug() and not is_in_kernel() and not is_qiling() and not is_rr():
            PTRACE_ARCH_PRCTL = 30
            ARCH_GET_GS = 0x1004
            pid, lwpid, tid = gdb.selected_thread().ptid
            ppvoid = ctypes.POINTER(ctypes.c_void_p)
            value = ppvoid(ctypes.c_void_p())
            value.contents.value = 0
            libc = ctypes.CDLL("libc.so.6")
            ret = libc.ptrace(PTRACE_ARCH_PRCTL, lwpid, value, ARCH_GET_GS)
            if ret == 0: # success
                return value.contents.value or 0
        # slow path
        if not is_kvm_enabled() and not is_qiling() and not is_rr():
            codes = [b"\x65\x48\xa1\x00\x00\x00\x00\x00\x00\x00\x00"] # movabs rax, qword ptr gs:[0x0]
            ret = ExecAsm(codes).exec_code()
            return ret["reg"]["$rax"]
        return None

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            i -= len(self.function_parameters)
            if in_func:
                i += 1 # Account for RA being at the top of the stack
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = sp + (i * sz)
            val = read_int_from_memory(loc)
            key = "[sp + {:#x}]".format(i * sz)
            return key, val

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 10
        insns = [
            "mov rax, {:d}".format(_NR_mprotect),
            "mov rdi, {:d}".format(addr),
            "mov rsi, {:d}".format(size),
            "mov rdx, {:d}".format(perm),
            "syscall",
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)

    def read128(self, addr):
        codes = [
            b"\x48\x8b\x00", # mov rax, qword ptr [rax]
            b"\x48\x8b\x09", # mov rcx, qword ptr [rcx]
            b"\x48\x8b\x12", # mov rdx, qword ptr [rdx]
            b"\x48\x8b\x1b", # mov rbx, qword ptr [rbx]
            b"\x48\x8b\x24\x24", # mov rsp, qword ptr [rsp]
            b"\x48\x8b\x6d\x00", # mov rbp, qword ptr [rbp]
            b"\x48\x8b\x36", # mov rsi, qword ptr [rsi]
            b"\x48\x8b\x3f", # mov rdi, qword ptr [rdi]
            b"\x4d\x8b\x00", # mov r8, qword ptr [r8]
            b"\x4d\x8b\x09", # mov r9, qword ptr [r9]
            b"\x4d\x8b\x12", # mov r10, qword ptr [r10]
            b"\x4d\x8b\x1b", # mov r11, qword ptr [r11]
            b"\x4d\x8b\x24\x24", # mov r12, qword ptr [r12]
            b"\x4d\x8b\x6d\x00", # mov r13, qword ptr [r13]
            b"\x4d\x8b\x36", # mov r14, qword ptr [r14]
            b"\x4d\x8b\x3f", # mov r15, qword ptr [r15]
        ]
        regs = [
            "$rax", "$rcx", "$rdx", "$rbx", "$rsp", "$rbp", "$rsi", "$rdi",
            "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        ]
        regs = {reg: addr + i * current_arch.ptrsize for i, reg in enumerate(regs)}
        ret = ExecAsm(codes, regs=regs, step=len(codes)).exec_code()
        values = [ret["reg"][reg] for reg in regs]
        return b"".join([p64(v) for v in values])


class X86_16(X86):
    arch = "X86"
    mode = "16"

    load_condition = [
        "I8086",
    ]

    seg_extended_registers = {
        "$cs:$ip": ["$cs", "$pc"],
        "$ss:$sp": ["$ss", "$sp"],
        "$ss:$bp": ["$ss", "$bp"],
        "$ds:$si": ["$ds", "$si"],
        "$es:$di": ["$es", "$di"],
    }

    # https://stanislavs.org/helppc/int_21.html
    return_register = None
    function_parameters = ["$sp"] # but unused because x86 uses stack
    syscall_register = "$ah"
    syscall_parameters = None

    bit_length = 16

    def __init__(self):
        gdb.execute("gef config context.use_capstone True")
        return

    def is_syscall(self, insn):
        return insn.mnemonic == "int" and insn.operands[0] == "0x21"

    def is_jump(self, insn):
        return insn.mnemonic in ["jmp", "ljmp"] or self.is_conditional_branch(insn)

    def is_ret(self, insn):
        return insn.mnemonic in ["ret", "retf", "iret"]

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                if insn.mnemonic == "ret":
                    reg = AddressUtil.dereference(current_arch.sp) & 0xffff
                    ra = current_arch.real2phys("$cs", reg)
                elif insn.mnemonic == "retf": # ip, cs
                    reg = AddressUtil.dereference(current_arch.sp) & 0xffff
                    seg = AddressUtil.dereference(current_arch.sp + current_arch.ptrsize) & 0xffff
                    ra = current_arch.real2phys(seg, reg)
                elif insn.mnemonic == "iret": # ip, cs, flags, sp, ss
                    reg = AddressUtil.dereference(current_arch.sp) & 0xffff
                    seg = AddressUtil.dereference(current_arch.sp + current_arch.ptrsize) & 0xffff
                    ra = current_arch.real2phys(seg, reg)
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    A20 = True

    def real2phys(self, seg, reg):
        if isinstance(seg, str):
            segval = get_register(seg) & 0xffff
        else:
            segval = seg
        if isinstance(reg, str):
            regval = get_register(reg) & 0xffff
        else:
            regval = reg
        if self.A20:
            return ((segval << 4) + regval) & 0x1fffff
        else:
            return ((segval << 4) + regval) & 0x0fffff

    @property
    def pc(self):
        return self.real2phys("$cs", "$pc")

    @property
    def sp(self):
        return self.real2phys("$ss", "$sp")


class PPC(Architecture):
    arch = "PPC"
    mode = "32"

    load_condition = [
        Elf.EM_PPC,
        "POWERPC",
        "PPC",
        "PPC32",
        "POWERPC:COMMON",
    ]

    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23",
        "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31",
        "$pc", "$msr", "$cr", "$lr", "$ctr", "$xer", "$fpscr",
    ]
    alias_registers = {
        "$r1": "$sp", "$r2": "$tp",
    }
    flag_register = "$cr"
    flags_table = {
        3: "negative[0]",
        2: "positive[0]",
        1: "equal[0]",
        0: "overflow[0]",
        # cr7
        31: "less[7]",
        30: "greater[7]",
        29: "equal[7]",
        28: "overflow[7]",
    }
    return_register = "$r3"
    function_parameters = ["$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9", "$r10"]
    syscall_register = "$r0"
    syscall_parameters = ["$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9"]

    bit_length = 32
    endianness = "little / big"
    instruction_length = 4
    has_delay_slot = False
    has_syscall_delay_slot = False
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = True
    capstone_support = True
    unicorn_support = True

    nop_insn = b"\x00\x00\x00\x60" # nop
    infloop_insn = b"\x00\x00\x00\x48" # b #0
    trap_insn = b"\x08\x00\xe0\x7f" # trap
    ret_insn = b"\x20\x00\x80\x4e" # blr
    syscall_insn = b"\x02\x00\x00\x44" # sc

    def flag_register_to_human(self, val=None):
        # http://www.cebix.net/downloads/bebox/pem32b.pdf (% 2.1.3)
        if not val:
            reg = self.flag_register
            val = get_register(reg)
        return Architecture.flags_to_human(val, self.flags_table)

    def is_syscall(self, insn):
        return insn.mnemonic in ["sc"]

    def is_call(self, insn):
        conditions = [
            "", "lt", "le", "eq", "ge", "gt", "nl",
            "ne", "ng", "so", "ns", "un", "nu",
        ]
        for cc in conditions:
            if insn.mnemonic == f"b{cc}l":
                return True
            if insn.mnemonic == f"b{cc}la":
                return True
            if insn.mnemonic == f"b{cc}ctrl":
                return True
            if insn.mnemonic == f"b{cc}lrl":
                return True
        modes = ["dz", "dnzf", "dzt", "dzf", "dnzt", "dnz"]
        for m in modes:
            if insn.mnemonic == f"b{m}l":
                return True
            if insn.mnemonic == f"b{m}la":
                return True
            if insn.mnemonic == f"b{m}lrl":
                return True
        return False

    def is_jump(self, insn):
        conditions = [
            "", "lt", "le", "eq", "ge", "gt", "nl",
            "ne", "ng", "so", "ns", "un", "nu",
        ]
        for cc in conditions:
            if insn.mnemonic == f"b{cc}":
                return True
            if insn.mnemonic == f"b{cc}a":
                return True
            if insn.mnemonic == f"b{cc}ctr":
                return True
        modes = ["dz", "dnzf", "dzt", "dzf", "dnzt", "dnz"]
        for m in modes:
            if insn.mnemonic == f"b{m}":
                return True
            if insn.mnemonic == f"b{m}a":
                return True
        return False

    def is_ret(self, insn):
        conditions = [
            "", "lt", "le", "eq", "ge", "gt", "nl",
            "ne", "ng", "so", "ns", "un", "nu",
        ]
        for cc in conditions:
            if insn.mnemonic == f"b{cc}lr":
                return True
            if insn.mnemonic == b"b{cc}lrl":
                return True
        modes = ["dz", "dnzf", "dzt", "dzf", "dnzt", "dnz"]
        for m in modes:
            if insn.mnemonic == f"b{m}lr":
                return True
            if insn.mnemonic == f"b{m}lrl":
                return True
        return False

    def is_conditional_branch(self, insn):
        branch_mnemos = [
            "beq", "bne", "ble", "blt", "bgt", "bge",
            "bdz", "bdnz", "bdzt", "bdnzt", "bdzf", "bdnzf",
        ]
        return insn.mnemonic in branch_mnemos

    def is_branch_taken(self, insn):
        mnemo = insn.mnemonic
        flags = {self.flags_table[k]: k for k in self.flags_table}
        val = get_register(self.flag_register)
        taken, reason = False, ""

        equal = bool(val & (1 << flags["equal[7]"]))
        less = bool(val & (1 << flags["less[7]"]))
        greater = bool(val & (1 << flags["greater[7]"]))

        if mnemo == "beq":
            taken, reason = equal, "E"
        elif mnemo == "bne":
            taken, reason = not equal, "!E"
        elif mnemo == "ble":
            taken, reason = equal or less, "E || L"
        elif mnemo == "blt":
            taken, reason = less, "L"
        elif mnemo == "bge":
            taken, reason = equal or greater, "E || G"
        elif mnemo == "bgt":
            taken, reason = greater, "G"
        # todo: bdn?z[tf]? are unsupported
        return taken, reason

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            i -= len(self.function_parameters)
            i += 2 # ???
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = sp + (i * sz)
            val = read_int_from_memory(loc)
            key = "[sp + {:#x}]".format(i * sz)
            return key, val

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$lr")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        def adjust_offset(x):
            TLS_TCB_OFFSET = 0x7000
            if x == 0:
                return x
            return x - TLS_TCB_OFFSET

        tls = get_register("$r2")
        return adjust_offset(tls)

    def decode_cookie(self, value, cookie):
        return value ^ cookie

    def encode_cookie(self, value, cookie):
        return value ^ cookie

    def mprotect_asm(self, addr, size, perm):
        # Ref: http://www.ibm.com/developerworks/library/l-ppc/index.html
        _NR_mprotect = 125
        insns = [
            "li 3, 0",
            "ori 3, 3, {:d}".format((addr >> 16) & 0xffff),
            "slwi 3, 3, 16",
            "ori 3, 3, {:d}".format((addr >> 0) & 0xffff),
            "li 4, 0",
            "ori 4, 4, {:d}".format((size >> 16) & 0xffff),
            "slwi 4, 4, 16",
            "ori 4, 4, {:d}".format((size >> 0) & 0xffff),
            "li 5, {:d}".format(perm),
            "li 0, {:d}".format(_NR_mprotect),
            "sc",
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)


class PPC64(PPC):
    arch = "PPC"
    mode = "64"

    load_condition = [
        Elf.EM_PPC64,
        "POWERPC64",
        "PPC64",
        "POWERPC:COMMON64",
    ]

    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23",
        "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31",
        "$pc", "$msr", "$cr", "$lr", "$ctr", "$xer", "$fpscr", "$vscr", "$vrsave",
    ]
    alias_registers = {
        "$r1": "$sp", "$r13": "$tp",
    }
    syscall_parameters = ["$r3", "$r4", "$r5", "$r6", "$r7", "$r8"]

    bit_length = 64

    unicorn_support = False

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            i += 4 # ???
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = sp + (i * sz)
            val = read_int_from_memory(loc)
            key = "[sp + {:#x}]".format(i * sz)
            return key, val

    def get_tls(self):
        def adjust_offset(x):
            TLS_TCB_OFFSET = 0x7000
            if x == 0:
                return x
            return x - TLS_TCB_OFFSET

        tls = get_register("$r13")
        return adjust_offset(tls)

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 125
        insns = [
            "li 3, 0",
            "ori 3, 3, {:d}".format((addr >> 48) & 0xffff),
            "sldi 3, 3, 16",
            "ori 3, 3, {:d}".format((addr >> 32) & 0xffff),
            "sldi 3, 3, 16",
            "ori 3, 3, {:d}".format((addr >> 16) & 0xffff),
            "sldi 3, 3, 16",
            "ori 3, 3, {:d}".format((addr >> 0) & 0xffff),
            "li 4, 0",
            "ori 4, 4, {:d}".format((size >> 48) & 0xffff),
            "sldi 4, 4, 16",
            "ori 4, 4, {:d}".format((size >> 32) & 0xffff),
            "sldi 4, 4, 16",
            "ori 4, 4, {:d}".format((size >> 16) & 0xffff),
            "sldi 4, 4, 16",
            "ori 4, 4, {:d}".format((size >> 48) & 0xffff),
            "li 5, {:d}".format(perm),
            "li 0, {:d}".format(_NR_mprotect),
            "sc",
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)


class SPARC(Architecture):
    arch = "SPARC"
    mode = "32"

    load_condition = [
        Elf.EM_SPARC,
        "SPARC",
        "SPARC32",
        "SPARC:V8",
    ]

    # http://www.cse.scu.edu/~atkinson/teaching/sp05/259/sparc.pdf
    all_registers = [
        "$g0", "$g1", "$g2", "$g3", "$g4", "$g5", "$g6", "$g7",
        "$o0", "$o1", "$o2", "$o3", "$o4", "$o5", "$sp", "$o7",
        "$l0", "$l1", "$l2", "$l3", "$l4", "$l5", "$l6", "$l7",
        "$i0", "$i1", "$i2", "$i3", "$i4", "$i5", "$fp", "$i7",
        "$y", "$psr", "$wim", "$tbr", "$pc", "$npc", "$fsr", "$csr",
    ]
    alias_registers = {
        "$g0": "$zero", "$g7": "$tp", "$sp": "$o6", "$fp": "$i6",
    }
    flag_register = "$psr"
    flags_table = {
        23: "negative",
        22: "zero",
        21: "overflow",
        20: "carry",
        7: "supervisor",
        5: "trap",
    }
    return_register = "$o0"
    function_parameters = ["$o0", "$o1", "$o2", "$o3", "$o4", "$o5"]
    syscall_register = "$g1"
    syscall_parameters = ["$o0", "$o1", "$o2", "$o3", "$o4", "$o5"]

    bit_length = 32
    endianness = "big"
    instruction_length = 4
    has_delay_slot = True
    has_syscall_delay_slot = True
    has_ret_delay_slot = True
    stack_grow_down = False
    tls_supported = True

    keystone_support = True
    capstone_support = True
    unicorn_support = True

    nop_insn = b"\x00\x00\x00\x01" # nop
    infloop_insn = b"\x00\x00\x80\x10" # b self
    trap_insn = None
    ret_insn = b"\x08\xe0\xc7\x81" # ret
    syscall_insn = b"\x10\x20\xd0\x91" # trap 0x10

    def flag_register_to_human(self, val=None):
        # http://www.gaisler.com/doc/sparcv8.pdf
        reg = self.flag_register
        if not val:
            val = get_register(reg)
        return Architecture.flags_to_human(val, self.flags_table)

    def is_syscall(self, insn):
        return insn.mnemonic == "ta" and insn.operands[0] == "0x10"

    def is_call(self, insn):
        return insn.mnemonic in ["jmpl", "call"]

    def is_jump(self, insn):
        mnemo = insn.mnemonic
        return (mnemo.startswith("b") and mnemo != "btst") or mnemo.startswith("fb") or mnemo == "jmpl"

    def is_ret(self, insn):
        return insn.mnemonic in ["ret", "retl"]

    def is_conditional_branch(self, insn):
        branch_mnemos = [
            # http://moss.csc.ncsu.edu/~mueller/codeopt/codeopt00/notes/condbranch.html
            "be", "bne", "bg", "bge", "bgeu", "bgu", "bl", "ble", "blu", "bleu",
            "bneg", "bpos", "bvs", "bvc", "bcs", "bcc"
            # https://www.gaisler.com/doc/sparcv8.pdf
            "fbu", "fbg", "fbug", "fbl", "fbul", "fblg", "fbne", "fbe", "fbue", "fbge",
            "fbuge", "fble", "fbule", "fbo",
            # https://docs.oracle.com/cd/E18752_01/html/816-1681/sparcv9-30990.html
            "bpne", "bpe", "bpg", "bple", "bpge", "bpl", "bpgu", "bpleu", "bpcc", "bpcs",
            "bppos", "bpneg", "bpvc", "bpvs", "brz", "brlez", "brlz", "brnz", "brgz", "brgez",
            "fbpu", "fbpg", "fbpug", "fbpl", "fbpul", "fbplg", "fbpne", "fbpe", "fbpue", "fbpge",
            "fbpuge", "fbple", "fbpule", "fbpo",
        ]
        return insn.mnemonic in branch_mnemos

    def is_branch_taken(self, insn):
        mnemo = insn.mnemonic
        flags = {self.flags_table[k]: k for k in self.flags_table}
        val = get_register(self.flag_register)
        taken, reason = False, ""

        zero = bool(val & (1 << flags["zero"]))
        negative = bool(val & (1 << flags["negative"]))
        overflow = bool(val & (1 << flags["overflow"]))
        carry = bool(val & (1 << flags["carry"]))

        if mnemo in ["be", "bpe"]:
            taken, reason = zero, "Z"
        elif mnemo in ["bne", "bpne"]:
            taken, reason = not zero, "!Z"
        elif mnemo in ["bg", "bpg"]:
            taken, reason = not zero and (not negative or not overflow), "!Z && (!N || !O)"
        elif mnemo in ["bge", "bpge"]:
            taken, reason = not negative or not overflow, "!N || !O"
        elif mnemo in ["bgu", "bpgu"]:
            taken, reason = not carry and not zero, "!C && !Z"
        elif mnemo in ["bgeu"]:
            taken, reason = not carry, "!C"
        elif mnemo in ["bl", "bpl"]:
            taken, reason = negative and overflow, "N && O"
        elif mnemo in ["blu"]:
            taken, reason = carry, "C"
        elif mnemo in ["ble", "bple"]:
            taken, reason = zero or (negative or overflow), "Z || (N || O)"
        elif mnemo in ["bleu", "bpleu"]:
            taken, reason = carry or zero, "C || Z"
        elif mnemo in ["bneg", "bpneg"]:
            taken, reason = negative, "N"
        elif mnemo in ["bpos", "bppos"]:
            taken, reason = not negative, "!N"
        elif mnemo in ["bvs", "bpvs"]:
            taken, reason = overflow, "O"
        elif mnemo in ["bvc", "bpvc"]:
            taken, reason = not overflow, "!O"
        elif mnemo in ["bcs", "bpcs"]:
            taken, reason = carry, "C"
        elif mnemo in ["bcc", "bpcc"]:
            taken, reason = not carry, "!C"
        # todo: f* opcode, brn?z/br[lg]e?z are unsupported
        return taken, reason

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            i += 17 # ???
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = sp + (i * sz)
            val = read_int_from_memory(loc)
            key = "[sp + {:#x}]".format(i * sz)
            return key, val

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$o7") + self.instruction_length * 2 # call, delay-slot
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        return get_register("$g7")

    def decode_cookie(self, value, cookie):
        return value ^ cookie

    def encode_cookie(self, value, cookie):
        return value ^ cookie

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 74
        insns = [
            "sethi %hi({}), %o0".format(addr & 0xfffffc00),
            "or %o0, {}, %o0".format(addr & 0x000003ff),
            "sethi %hi({}), %o1".format(size & 0xfffffc00),
            "or %o1, {}, %o1".format(size & 0x000003ff),
            "mov {}, %o2".format(perm),
            "mov {}, %g1".format(_NR_mprotect),
            "ta 0x10",
            "nop", # keystone does not give nop for delay slot, needs this nop
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)


class SPARC32PLUS(SPARC):
    arch = "SPARC"
    mode = "32PLUS"

    load_condition = [
        Elf.EM_SPARC32PLUS,
        "SPARC32PLUS",
        "SPARC32+",
        "SPARCV8PLUS",
        "SPARCV8+",
        "SPARC:V8PLUS",
        "SPARC:V8PLUSA",
        "SPARC:V8PLUSB",
        "SPARC:V8PLUSC",
        "SPARC:V8PLUSD",
        "SPARC:V8PLUSE",
        "SPARC:V8PLUSM",
        "SPARC:V8PLUSV",
    ]


class SPARC64(SPARC):
    arch = "SPARC"
    mode = "64"

    load_condition = [
        Elf.EM_SPARCV9,
        "SPARC64",
        "SPARC:V9",
        "SPARC:V9A",
        "SPARC:V9B",
        "SPARC:V9C",
        "SPARC:V9D",
        "SPARC:V9E",
        "SPARC:V9M",
        "SPARC:V9V",
    ]

    # http://math-atlas.sourceforge.net/devel/assembly/abi_sysV_sparc.pdf
    # https://cr.yp.to/2005-590/sparcv9.pdf
    all_registers = [
        "$g0", "$g1", "$g2", "$g3", "$g4", "$g5", "$g6", "$g7",
        "$o0", "$o1", "$o2", "$o3", "$o4", "$o5", "$sp", "$o7",
        "$l0", "$l1", "$l2", "$l3", "$l4", "$l5", "$l6", "$l7",
        "$i0", "$i1", "$i2", "$i3", "$i4", "$i5", "$fp", "$i7",
        "$pc", "$npc", "$state", "$fsr", "$fprs", "$y", "$cwp",
        "$pstate", "$asi", "$ccr",
    ]
    flag_register = "$state" # sparcv9.pdf, 5.1.5.1 (ccr)
    flags_table = {
        35: "negative",
        34: "zero",
        33: "overflow",
        32: "carry",
    }

    bit_length = 64

    syscall_insn = b"\x6d\x20\xd0\x91" # trap 0x6d

    def is_syscall(self, insn):
        return insn.mnemonic == "ta" and insn.operands[0] == "0x6d"

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            i += 272 # ???
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = sp + (i * sz) - 1
            val = read_int_from_memory(loc)
            key = "[sp + {:#x}]".format(i * sz - 1)
            return key, val

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 74
        insns = [
            "sethi %hi({}), %o0".format(addr & 0xfffffc00),
            "or %o0, {}, %o0".format(addr & 0x000003ff),
            "sethi %hi({}), %o1".format((addr >> 32) & 0xfffffc00),
            "or %o1, {}, %o1".format((addr >> 32) & 0x000003ff),
            "sllx %o1, 32, %o1",
            "or %o0, %o1, %o0",
            "sethi %hi({}), %o1".format(size & 0xfffffc00),
            "or %o1, {}, %o1".format(size & 0x000003ff),
            "sethi %hi({}), %o2".format((size >> 32) & 0xfffffc00),
            "or %o2, {}, %o2".format((size >> 32) & 0x000003ff),
            "sllx %o2, 32, %o2",
            "or %o1, %o2, %o1",
            "mov {}, %o2".format(perm),
            "mov {}, %g1".format(_NR_mprotect),
            "ta 0x6d",
            "nop", # keystone does not give nop for delay slot, needs this nop
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)


class MIPS(Architecture):
    arch = "MIPS"
    mode = "32"

    load_condition = [
        # Elf.EM_MIPS cannot determine whether it is 32-bit or 64-bit, so it should not be used.
        "MIPS",
        "MIPS32",
        "MIPS:ISA32",
        "MIPS:ISA32R2",
        "MIPS:ISA32R3",
        "MIPS:ISA32R5",
        "MIPS:ISA32R6",
    ]

    # http://vhouten.home.xs4all.nl/mipsel/r3000-isa.html
    all_registers = [
        "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
        "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
        "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
        "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
        "$sr", "$lo", "$hi", "$bad", "$cause", "$fsr", "$fir", "$pc",
    ]
    alias_registers = {
        "$zero": "$r0", "$at": "$r1", "$v0": "$r2", "$v1": "$r3",
        "$a0": "$r4", "$a1": "$r5", "$a2": "$r6", "$a3": "$r7",
        "$t0": "$r8", "$t1": "$r9", "$t2": "$r10", "$t3": "$r11",
        "$t4": "$r12", "$t5": "$r13", "$t6": "$r14", "$t7": "$r15",
        "$s0": "$r16", "$s1": "$r17", "$s2": "$r18", "$s3": "$r19",
        "$s4": "$r20", "$s5": "$r21", "$s6": "$r22", "$s7": "$r23",
        "$t8": "$r24", "$t9": "$r25", "$k0": "$r26", "$k1": "$r27",
        "$gp": "$r28", "$sp": "$r29", "$fp": "$s8/$r30", "$ra": "$r31",
    }
    flag_register = None # MIPS has no flags register
    return_register = "$v0"
    function_parameters = ["$a0", "$a1", "$a2", "$a3"]
    syscall_register = "$v0"
    syscall_parameters = ["$a0", "$a1", "$a2", "$a3", "$sp+0x10", "$sp+0x14", "$sp+0x18", "$sp+0x1c"]

    bit_length = 32
    endianness = "little / big"
    instruction_length = 4
    has_delay_slot = True
    has_syscall_delay_slot = True
    has_ret_delay_slot = True
    stack_grow_down = False
    tls_supported = True

    keystone_support = True
    capstone_support = True
    unicorn_support = True

    nop_insn = b"\x00\x00\x00\x00" # nop
    infloop_insn = b"\xff\xff\x00\x10" # b self
    trap_insn = b"\x0d\x00\x00\x00" # break
    ret_insn = b"\x08\x00\xe0\x03" # jr $ra
    syscall_insn = b"\x0c\x00\x00\x00" # syscall

    def is_syscall(self, insn):
        return insn.mnemonic in ["syscall"]

    def is_call(self, insn):
        branch_mnemos = [
            "bal", "balc", "jal", "jalr", "jalrc", "jalrc.hb",
            "bgezal", "bgezall", "bltzal", "bltzall",
        ]
        return insn.mnemonic in branch_mnemos

    def is_jump(self, insn):
        if self.is_ret(insn):
            return False
        if insn.mnemonic in ["b", "bc", "j", "jr", "jrc", "balrsc", "brsc"]:
            return True
        if self.is_conditional_branch(insn):
            return True
        return False

    def is_ret(self, insn):
        if insn.mnemonic in ["jr", "jrc"] and insn.operands[0] == "ra":
            return True
        if insn.mnemonic in ["deret", "eret", "eretnc"]:
            return True
        if insn.mnemonic in ["restore", "restore.jrc"]:
            return True
        return False

    def is_conditional_branch(self, insn):
        branch_mnemos = [
            "beq", "bne", "bgtz", "bgez", "bltz", "blez", "beqz", "bnez",
            "beql", "bnel", "bgtzl", "bgezl", "bltzl", "blezl",
            "bgezal", "bgezall", "bltzal", "bltzall",
            "bc1f", "bc1fl", "bc1t", "bc1tl", "bc2f", "bc2fl", "bc2t", "bc2tl",
            "beqc", "beqic", "beqzc",
            "bnec", "bneic", "bnezc",
            "bgec", "bgeic", "bgeiuc", "bgeuc",
            "bltc", "bltic", "bltiuc", "bltuc",
            "bbeqzc", "bbnezc",
        ]
        return insn.mnemonic in branch_mnemos

    def is_branch_taken(self, insn):
        mnemo, ops = insn.mnemonic, insn.operands
        taken, reason = False, ""

        p = lambda a: struct.pack("<I", a & 0xffffffff)
        ui = lambda a: struct.unpack("<i", a)[0]
        u2i = lambda a: ui(p(a))

        if mnemo in ["beq", "beql", "beqc"]:
            taken, reason = get_register(ops[0]) == get_register(ops[1]), "{0[0]} == {0[1]}".format(ops)
        elif mnemo in ["beqic"]:
            taken, reason = get_register(ops[0]) == int(ops[1], 0), "{0[0]} == {0[1]}".format(ops)
        elif mnemo in ["bne", "bnel", "bnec"]:
            taken, reason = get_register(ops[0]) != get_register(ops[1]), "{0[0]} != {0[1]}".format(ops)
        elif mnemo in ["bneic"]:
            taken, reason = get_register(ops[0]) != int(ops[1], 0), "{0[0]} != {0[1]}".format(ops)
        elif mnemo in ["beqz", "beqzc"]:
            taken, reason = get_register(ops[0]) == 0, "{0[0]} == 0".format(ops)
        elif mnemo in ["bnez", "bnezc"]:
            taken, reason = get_register(ops[0]) != 0, "{0[0]} != 0".format(ops)
        elif mnemo in ["bgtz", "bgtzl"]:
            taken, reason = get_register(ops[0]) > 0, "{0[0]} > 0".format(ops)
        elif mnemo in ["bgez", "bgezl"]:
            taken, reason = get_register(ops[0]) >= 0, "{0[0]} >= 0".format(ops)
        elif mnemo in ["bltz", "bltzl"]:
            taken, reason = get_register(ops[0]) < 0, "{0[0]} < 0".format(ops)
        elif mnemo in ["blez", "blezl"]:
            taken, reason = get_register(ops[0]) <= 0, "{0[0]} <= 0".format(ops)
        elif mnemo in ["bbeqzc"]:
            taken, reason = (get_register(ops[0]) >> int(ops[1], 0) & 1) == 0, "(({0[0]} >> {0[1]}) & 1) == 0".format(ops)
        elif mnemo in ["bbnezc"]:
            taken, reason = (get_register(ops[0]) >> int(ops[1], 0) & 1) == 0, "(({0[0]} >> {0[1]}) & 1) != 0".format(ops)
        elif mnemo in ["bgec"]:
            taken, reason = get_register(ops[0]) >= u2i(get_register(ops[1])), "{0[0]} >= {0[1]}".format(ops)
        elif mnemo in ["bgeic"]:
            taken, reason = get_register(ops[0]) >= u2i(int(ops[1], 0)), "{0[0]} >= {0[1]}".format(ops)
        elif mnemo in ["bgeuc"]:
            taken, reason = get_register(ops[0]) >= get_register(ops[1]), "{0[0]} >= {0[1]}".format(ops)
        elif mnemo in ["bgeiuc"]:
            taken, reason = get_register(ops[0]) >= int(ops[1], 0), "{0[0]} >= {0[1]}".format(ops)
        elif mnemo in ["bltc"]:
            taken, reason = get_register(ops[0]) < u2i(get_register(ops[1])), "{0[0]} < {0[1]}".format(ops)
        elif mnemo in ["bltic"]:
            taken, reason = get_register(ops[0]) < u2i(int(ops[1], 0)), "{0[0]} < {0[1]}".format(ops)
        elif mnemo in ["bltuc"]:
            taken, reason = get_register(ops[0]) < get_register(ops[1]), "{0[0]} < {0[1]}".format(ops)
        elif mnemo in ["bltiuc"]:
            taken, reason = get_register(ops[0]) < int(ops[1], 0), "{0[0]} < {0[1]}".format(ops)
        return taken, reason

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = sp + (i * sz)
            val = read_int_from_memory(loc)
            key = "[sp + {:#x}]".format(i * sz)
            return key, val

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$ra")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        def adjust_offset(x):
            TLS_TCB_OFFSET = 0x7000
            if x == 0:
                return x
            return x - TLS_TCB_OFFSET

        codes = [b"\x3b\xe8\x03\x7c"] # rdhwr v1, $29
        ret = ExecAsm(codes).exec_code()
        tls = ret["reg"]["$v1"]
        return adjust_offset(tls)

    def decode_cookie(self, value, cookie):
        return value

    def encode_cookie(self, value, cookie):
        return value

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 4125
        insns = [
            "li $v0, {:d}".format(_NR_mprotect),
            "li $a0, {:d}".format(addr),
            "li $a1, {:d}".format(size),
            "li $a2, {:d}".format(perm),
            "syscall", # keystone gives nop for delay slot, need not nop
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)


class MIPS64(MIPS):
    arch = "MIPS"
    mode = "64"

    load_condition = [
        # Elf.EM_MIPS cannot determine whether it is 32-bit or 64-bit, so it should not be used.
        "MIPS64",
        "MIPS:ISA64",
        "MIPS:ISA64R2",
        "MIPS:ISA64R3",
        "MIPS:ISA64R5",
        "MIPS:ISA64R6",
    ]

    all_registers = [
        "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
        "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3",
        "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
        "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
        "$sr", "$lo", "$hi", "$bad", "$cause", "$fsr", "$fir", "$pc",
    ]
    alias_registers = {
        "$zero": "$r0", "$at": "$r1", "$v0": "$r2", "$v1": "$r3",
        "$a0": "$r4", "$a1": "$r5", "$a2": "$r6", "$a3": "$r7",
        "$a4": "$r8", "$a5": "$r9", "$a6": "$r10", "$a7": "$r11",
        "$t0": "$r12", "$t1": "$r13", "$t2": "$r14", "$t3": "$r15",
        "$s0": "$r16", "$s1": "$r17", "$s2": "$r18", "$s3": "$r19",
        "$s4": "$r20", "$s5": "$r21", "$s6": "$r22", "$s7": "$r23",
        "$t8": "$r24", "$t9": "$r25", "$k0": "$r26", "$k1": "$r27",
        "$gp": "$r28", "$sp": "$r29", "$fp": "$s8/$r30", "$ra": "$r31",
    }
    function_parameters = ["$a0", "$a1", "$a2", "$a3", "$a4", "$a5", "$a6", "$a7"]
    syscall_parameters = ["$a0", "$a1", "$a2", "$a3", "$a4", "$a5"]

    bit_length = 64

    unicorn_support = False

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            i -= len(self.function_parameters)
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = sp + (i * sz)
            val = read_int_from_memory(loc)
            key = "[sp + {:#x}]".format(i * sz)
            return key, val

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 5010
        insns = [
            "ori $a0, $zero, {:#x}".format((addr >> 48) & 0xffff),
            "dsll $a0, $a0, 16",
            "ori $a0, $a0, {:#x}".format((addr >> 32) & 0xffff),
            "dsll $a0, $a0, 16",
            "ori $a0, $a0, {:#x}".format((addr >> 16) & 0xffff),
            "dsll $a0, $a0, 16",
            "ori $a0, $a0, {:#x}".format((addr >> 0) & 0xffff),
            "ori $a1, $zero, {:#x}".format((size >> 48) & 0xffff),
            "dsll $a1, $a1, 16",
            "ori $a1, $a1, {:#x}".format((size >> 32) & 0xffff),
            "dsll $a1, $a1, 16",
            "ori $a1, $a1, {:#x}".format((size >> 16) & 0xffff),
            "dsll $a1, $a1, 16",
            "ori $a1, $a1, {:#x}".format((size >> 0) & 0xffff),
            "li $a2, {:d}".format(perm),
            "li $v0, {:d}".format(_NR_mprotect),
            "syscall", # keystone gives nop for delay slot, need not nop
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)


class MIPSN32(MIPS64):
    arch = "MIPS"
    mode = "n32"

    load_condition = [
        "MIPSN32"
    ]

    bit_length = 32


class S390X(Architecture):
    arch = "S390X"
    mode = "64"

    load_condition = [
        # Elf.EM_S390 cannot determine whether it is 32 bit or 64 bit,
        # but since GEF only supports 64 bit (s390x), so we will use it.
        Elf.EM_S390,
        "S390X",
        "S390:64-BIT",
    ]

    # https://www.ibm.com/docs/en/SSQ2R2_15.0.0/com.ibm.tpf.toolkit.hlasm.doc/dz9zr006.pdf
    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$pswm", "$pswa", "$fpc", "$gsd", "$gssm", "$gsepla",
        "$gs_reserved", "$pc", "$cc",
    ]
    alias_registers = {
        "$r14": "$lr", "$r15": "$sp",
    }
    flag_register = "$cc"
    flags_table = {
        1: "cc1",
        0: "cc0",
    }
    return_register = "$r2"
    function_parameters = ["$r2", "$r3", "$r4", "$r5", "$r6"]
    syscall_register = [r"svc\s+(\d+)", "$r1"] # $r1 is used when NR > 127
    syscall_parameters = ["$r2", "$r3", "$r4", "$r5", "$r6", "$r7"]

    bit_length = 64
    endianness = "big"
    instruction_length = None # variable length
    has_delay_slot = False
    has_syscall_delay_slot = True
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = True
    capstone_support = True
    unicorn_support = False # for some reason it doesn't work

    nop_insn = b"\x07\x07" # bcr 0, %r7
    infloop_insn = b"\x00\x00\xf4\xa7" # j 0
    trap_insn = None
    ret_insn = b"\xfe\x07" # br %r14
    syscall_insn = b"\x00\x0a" # svc 0x0

    def is_syscall(self, insn):
        return insn.mnemonic == "svc"

    # https://www.ibm.com/docs/en/zos/2.1.0?topic=statements-branching-extended-mnemonic-codes
    def is_call(self, insn):
        return insn.mnemonic in ["bal", "balr", "bas", "basr", "bassm", "bsm", "bras", "brasl"]

    def is_jump(self, insn):
        if self.is_ret(insn):
            return False
        if insn.mnemonic in ["b", "br", "j", "bru", "brul", "jlu"]:
            return True
        return self.is_conditional_branch(insn)

    def is_ret(self, insn):
        return insn.mnemonic == "br" and insn.operands[-1] == "%r14"

    def is_conditional_branch(self, insn):
        if insn.mnemonic in ["bc", "bcr", "brc", "brcl"]:
            return True
        conditions = ["h", "l", "e", "nh", "nl", "ne", "p", "m", "z", "o", "np", "nm", "nz", "no"]
        for cc in conditions:
            if insn.mnemonic == f"b{cc}": # alias for `bc N, ...`
                return True
            if insn.mnemonic == f"b{cc}r": # alias for `bcr N, ...`
                return True
            if insn.mnemonic in [f"br{cc}", f"j{cc}"]: # alias for `brc N, ...`
                return True
            if insn.mnemonic in [f"br{cc}l", f"jl{cc}"]: # alias for `brcl N, ...`
                return True

        if insn.mnemonic in ["bct", "bctr", "bctg", "bctgr", "brct", "brctg"]:
            return True
        if insn.mnemonic in ["bxh", "bxhg", "brxh", "brxhg"]:
            return True
        if insn.mnemonic in ["bxle", "bxleg", "brxle", "brxlg"]:
            return True

        if insn.mnemonic in ["crb", "cgrb", "crj", "cgrj"]:
            return True
        if insn.mnemonic in ["cib", "cgib", "cij", "cgij"]:
            return True
        if insn.mnemonic in ["clrb", "clgrb", "clrj", "clgrj"]:
            return True
        if insn.mnemonic in ["clib", "clgib", "clij", "clgij"]:
            return True
        conditions = ["h", "l", "ne"]
        for cc in conditions:
            if insn.mnemonic == f"crb{cc}": # alias for `crb r,r,N`
                return True
            if insn.mnemonic == f"cgrb{cc}": # alias for `cgrb r,r,N`
                return True
            if insn.mnemonic == f"crj{cc}": # alias for `crj r,r,N, ...`
                return True
            if insn.mnemonic == f"cgrj{cc}": # alias for `cgrj r,r,N, ...`
                return True
            if insn.mnemonic == f"cib{cc}": # alias for `cib r,i,N, ...`
                return True
            if insn.mnemonic == f"cgib{cc}": # alias for `cgib r,i,N, ...`
                return True
            if insn.mnemonic == f"cij{cc}": # alias for `cij r,i,N, ...`
                return True
            if insn.mnemonic == f"cgij{cc}": # alias for `cgij r,i,N, ...`
                return True
            if insn.mnemonic == f"clrb{cc}": # alias for `clrb r,r,N, ...`
                return True
            if insn.mnemonic == f"clgrb{cc}": # alias for `clgrb r,r,N, ...`
                return True
            if insn.mnemonic == f"clrj{cc}": # alias for `clrj r,r,N, ...`
                return True
            if insn.mnemonic == f"clgrj{cc}": # alias for `clgrj r,r,N, ...`
                return True
            if insn.mnemonic == f"clib{cc}": # alias for `clib r,i,N, ...`
                return True
            if insn.mnemonic == f"clgib{cc}": # alias for `clgib r,i,N, ...`
                return True
            if insn.mnemonic == f"clij{cc}": # alias for `clij r,i,N, ...`
                return True
            if insn.mnemonic == f"clgij{cc}": # alias for `clgij r,i,N, ...`
                return True
        return False

    def is_branch_taken(self, insn):
        taken, reason = False, ""

        def is_insn_condition_type1(insn):
            if insn.mnemonic in ["bc", "bcr", "brc", "brcl"]:
                return True
            conditions = [
                "h", "l", "e", "nh", "nl", "ne", "p", "m",
                "z", "o", "np", "nm", "nz", "no",
            ]
            for cc in conditions:
                if insn.mnemonic == f"b{cc}": # alias for `bc N, ...`
                    return True
                if insn.mnemonic == f"b{cc}r": # alias for `bcr N, ...`
                    return True
                if insn.mnemonic in [f"br{cc}", f"j{cc}"]: # alias for `brc N, ...`
                    return True
                if insn.mnemonic in [f"br{cc}l", f"jl{cc}"]: # alias for `brcl N, ...`
                    return True
            return False

        def is_insn_condition_type2_signed32(insn):
            if insn.mnemonic in ["crb", "crj"]:
                return True
            if insn.mnemonic in ["cib", "cij"]:
                return True
            conditions = ["h", "l", "ne"]
            for cc in conditions:
                if insn.mnemonic == f"crb{cc}": # alias for `crb r,r,N`
                    return True
                if insn.mnemonic == f"crj{cc}": # alias for `crj r,r,N, ...`
                    return True
                if insn.mnemonic == f"cib{cc}": # alias for `cib r,i,N, ...`
                    return True
                if insn.mnemonic == f"cij{cc}": # alias for `cij r,i,N, ...`
                    return True
            return False

        def is_insn_condition_type2_signed64(insn):
            if insn.mnemonic in ["cgrb", "cgrj"]:
                return True
            if insn.mnemonic in ["cgib", "cgij"]:
                return True
            conditions = ["h", "l", "ne"]
            for cc in conditions:
                if insn.mnemonic == f"cgrb{cc}": # alias for `cgrb r,r,N`
                    return True
                if insn.mnemonic == f"cgrj{cc}": # alias for `cgrj r,r,N, ...`
                    return True
                if insn.mnemonic == f"cgib{cc}": # alias for `cgib r,i,N, ...`
                    return True
                if insn.mnemonic == f"cgij{cc}": # alias for `cgij r,i,N, ...`
                    return True
            return False

        def is_insn_condition_type2_unsigned32(insn):
            if insn.mnemonic in ["clrb", "clrj"]:
                return True
            if insn.mnemonic in ["clib", "clij"]:
                return True
            conditions = ["h", "l", "ne"]
            for cc in conditions:
                if insn.mnemonic == f"clrb{cc}": # alias for `clrb r,r,N, ...`
                    return True
                if insn.mnemonic == f"clrj{cc}": # alias for `clrj r,r,N, ...`
                    return True
                if insn.mnemonic == f"clib{cc}": # alias for `clib r,i,N, ...`
                    return True
                if insn.mnemonic == f"clij{cc}": # alias for `clij r,i,N, ...`
                    return True
            return False

        def is_insn_condition_type2_unsigned64(insn):
            if insn.mnemonic in ["clgrb", "clgrj"]:
                return True
            if insn.mnemonic in ["clgib", "clgij"]:
                return True
            conditions = ["h", "l", "ne"]
            for cc in conditions:
                if insn.mnemonic == f"clgrb{cc}": # alias for `clgrb r,r,N, ...`
                    return True
                if insn.mnemonic == f"clgrj{cc}": # alias for `clgrj r,r,N, ...`
                    return True
                if insn.mnemonic == f"clgib{cc}": # alias for `clgib r,i,N, ...`
                    return True
                if insn.mnemonic == f"clgij{cc}": # alias for `clgij r,i,N, ...`
                    return True
            return False

        if is_insn_condition_type1(insn):
            mask = insn.opcodes[1] >> 4

            val = get_register(self.flag_register)
            flags = {self.flags_table[k]: k for k in self.flags_table}
            cc1 = (val >> flags["cc1"]) & 1
            cc0 = (val >> flags["cc0"]) & 1
            cc = (cc1 << 1) + cc0

            if (mask & 0b1) and cc == 3:
                return True, "cc==3"
            if (mask & 0b10) and cc == 2:
                return True, "cc==2"
            if (mask & 0b100) and cc == 1:
                return True, "cc==1"
            if (mask & 0b1000) and cc == 0:
                return True, "cc==0"
            return False, ""

        if insn.mnemonic in ["bct", "bctr", "bctg", "bctgr", "brct", "brctg"]:
            reg = insn.operands[0]
            return get_register(reg) != 1, "{:s}!=1".format(reg)

        if insn.mnemonic in ["bxh", "bxhg", "brxh", "brxhg"]:
            reg1, reg3 = insn.operands[0], insn.operands[1]
            taken = get_register(reg1) + get_register(reg3) > get_register(reg3) + 1
            reason = "({:s}+{:s})>{:#x}".format(reg1, reg3, get_register(reg3) + 1)
            return taken, reason

        if insn.mnemonic in ["bxle", "bxleg", "brxle", "brxlg"]:
            reg1, reg3 = insn.operands[0], insn.operands[1]
            taken = get_register(reg1) + get_register(reg3) <= get_register(reg3) + 1
            reason = "({:s}+{:s})<={:#x}".format(reg1, reg3, get_register(reg3) + 1)
            return taken, reason

        def for_compare(insn, signed, bit):
            if signed and bit == 32:
                trans = lambda a: struct.unpack("<i", struct.pack("<I", a & 0xffffffff))[0]
            elif signed and bit == 64:
                trans = lambda a: struct.unpack("<q", struct.pack("<Q", a & 0xffffffffffffffff))[0]
            elif not signed and bit == 32:
                trans = lambda a: a & 0xffffffff
            elif not signed and bit == 64:
                trans = lambda a: a & 0xffffffffffffffff
            else:
                raise

            mask = insn.opcodes[4] >> 4
            reg1 = insn.operands[0]
            reg2_or_imm = insn.operands[1]

            val1 = trans(get_register(reg1))
            if reg2_or_imm.startswith("%"):
                val2 = trans(get_register(reg2_or_imm))
            else:
                val2 = int(reg2_or_imm, 0)
            if (mask & 0b1) and val1 == val2:
                return True, "{:s}=={:s}".format(reg1, reg2_or_imm)
            if (mask & 0b10) and val1 < val2:
                return True, "{:s}<{:s}".format(reg1, reg2_or_imm)
            if (mask & 0b100) and val1 > val2:
                return True, "{:s}>{:s}".format(reg1, reg2_or_imm)
            return False, ""

        if is_insn_condition_type2_signed32(insn):
            return for_compare(insn, signed=True, bit=32)
        if is_insn_condition_type2_signed64(insn):
            return for_compare(insn, signed=True, bit=64)
        if is_insn_condition_type2_unsigned32(insn):
            return for_compare(insn, signed=False, bit=32)
        if is_insn_condition_type2_unsigned64(insn):
            return for_compare(insn, signed=False, bit=64)

        return taken, reason

    def flag_register_to_human(self, val=None):
        if not val:
            reg = self.flag_register
            val = get_register(reg)
        flags = {self.flags_table[k]: k for k in self.flags_table}

        extra_msg = " ["
        if get_register("$pswm"):
            addressing0 = (get_register("$pswm") >> 31) & 1
            addressing1 = (get_register("$pswm") >> 32) & 1
            addressing_mode = {
                (0, 0): "24-bit",
                (0, 1): "31-bit",
                (1, 1): "64-bit",
            }[addressing0, addressing1]
            extra_msg += "AddressingMode={:s}, ".format(addressing_mode)

        cc1 = (val >> flags["cc1"]) & 1
        cc0 = (val >> flags["cc0"]) & 1
        condition_code = (cc1 << 1) + cc0
        extra_msg += "ConditionCode={:d}]".format(condition_code)

        return Architecture.flags_to_human(val, self.flags_table) + extra_msg

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            i += 15 # ???
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = sp + (i * sz)
            val = read_int_from_memory(loc)
            key = "[sp + {:#x}]".format(i * sz)
            return key, val

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$r14")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        hi = get_register("$acr0")
        lo = get_register("$acr1")
        return (hi << 32) | lo

    def decode_cookie(self, value, cookie):
        return value ^ cookie

    def encode_cookie(self, value, cookie):
        return value ^ cookie

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 125
        insns = [
            "llilf %r2, {:#x}".format(addr >> 32),
            "sllg %r2, %r2, 32",
            "oilf %r2, {:#x}".format(addr & 0xffffffff),
            "llilf %r3, {:#x}".format(size >> 32),
            "sllg %r3, %r3, 32",
            "oilf %r3, {:#x}".format(size & 0xffffffff),
            "llilf %r4, {:#x}".format(perm >> 32),
            "sllg %r4, %r4, 32",
            "oilf %r4, {:#x}".format(perm & 0xffffffff),
            ".byte 0x0a, {:#x}".format(_NR_mprotect), # svc 0x7d
            "bcr 0, %r7", # nop
        ]
        code = "; ".join(insns)
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        return UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)


class SH4(Architecture):
    arch = "SH4"
    mode = "SH4"

    load_condition = [
        Elf.EM_SH,
        "SH4",
        "SH4-NOFPU",
        "SH4A",
        "SH4A-NOFPU",
        "SH2A-OR-SH4",
    ]

    # https://www.renesas.com/us/en/document/man/705261
    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$pc", "$pr", "$gbr", "$mach", "$macl", "$sr",
    ]
    alias_registers = {
        "$r15": "$sp",
    }
    flag_register = "$sr"
    flags_table = {
        0: "t",
    }
    return_register = "$r0"
    function_parameters = ["$r4", "$r5", "$r6", "$r7"]
    syscall_register = "$r3"
    syscall_parameters = ["$r4", "$r5", "$r6", "$r7", "$r0", "$r1", "$r2"]

    bit_length = 32
    endianness = "little"
    instruction_length = 2
    has_delay_slot = True
    has_syscall_delay_slot = True
    has_ret_delay_slot = True
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\x09\x00" # nop
    infloop_insn = b"\xfe\xaf" # bra self
    trap_insn = None
    ret_insn = b"\x0b\x00" # rts
    syscall_insn = b"\x13\xc3" # trapa #19

    def is_syscall(self, insn):
        return insn.mnemonic == "trapa" and insn.operands[0] == "#19"

    def is_call(self, insn):
        return insn.mnemonic in ["bsr", "bsrf", "jsr"]

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        return insn.mnemonic in ["bra", "braf", "jmp"]

    def is_ret(self, insn):
        return insn.mnemonic == "rts"

    def is_conditional_branch(self, insn):
        return insn.mnemonic in ["bf", "bf.s", "bt", "bt.s"]

    def is_branch_taken(self, insn):
        mnemo = insn.mnemonic
        val = get_register(self.flag_register)
        flags = {self.flags_table[k]: k for k in self.flags_table}
        taken, reason = False, ""

        t = bool(val & (1 << flags["t"]))

        if mnemo in ["bf", "bf.s"]:
            taken, reason = not t, "!T"
        elif mnemo in ["bt", "bt.s"]:
            taken, reason = t, "T"
        return taken, reason

    def flag_register_to_human(self, val=None):
        if not val:
            reg = self.flag_register
            val = get_register(reg)
        return Architecture.flags_to_human(val, self.flags_table)

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$pr")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        return get_register("$gbr")

    def decode_cookie(self, value, cookie):
        return value ^ cookie

    def encode_cookie(self, value, cookie):
        return value ^ cookie

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 125
        insns = [
            # In sh4, r0-r7 cannot be set from gdb.
            # Since it can be set to r8-r15, save it there.
            b"\x03\x68", # mov r0, r8
            b"\x33\x69", # mov r3, r9
            b"\x43\x6a", # mov r4, r10
            b"\x53\x6b", # mov r5, r11
            b"\x63\x6c", # mov r6, r12

            b"\x4a\x24", # xor r4, r4
            p8((addr >> 24) & 0xff) + b"\xe0", # mov addr[31:24], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x18\x40", # shll8 r0
            b"\x18\x40", # shll8 r0
            b"\x18\x40", # shll8 r0
            b"\x0b\x24", # or r0, r4
            p8((addr >> 16) & 0xff) + b"\xe0", # mov addr[23:16], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x18\x40", # shll8 r0
            b"\x18\x40", # shll8 r0
            b"\x0b\x24", # or r0, r4
            p8((addr >> 8) & 0xff) + b"\xe0", # mov addr[15:8], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x18\x40", # shll8 r0
            b"\x0b\x24", # or r0, r4
            p8((addr >> 0) & 0xff) + b"\xe0", # mov addr[7:0], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x0b\x24", # or r0, r4

            b"\x5a\x25", # xor r5, r5
            p8((size >> 24) & 0xff) + b"\xe0", # mov size[31:24], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x18\x40", # shll8 r0
            b"\x18\x40", # shll8 r0
            b"\x18\x40", # shll8 r0
            b"\x0b\x25", # or r0, r5
            p8((size >> 16) & 0xff) + b"\xe0", # mov size[23:16], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x18\x40", # shll8 r0
            b"\x18\x40", # shll8 r0
            b"\x0b\x25", # or r0, r5
            p8((size >> 8) & 0xff) + b"\xe0", # mov size[15:8], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x18\x40", # shll8 r0
            b"\x0b\x25", # or r0, r5
            p8((size >> 0) & 0xff) + b"\xe0", # mov size[7:0], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x0b\x25", # or r0, r5

            b"\x6a\x26", # xor r6, r6
            p8((perm >> 24) & 0xff) + b"\xe0", # mov perm[31:24], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x18\x40", # shll8 r0
            b"\x18\x40", # shll8 r0
            b"\x18\x40", # shll8 r0
            b"\x0b\x26", # or r0, r6
            p8((perm >> 16) & 0xff) + b"\xe0", # mov perm[23:16], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x18\x40", # shll8 r0
            b"\x18\x40", # shll8 r0
            b"\x0b\x26", # or r0, r6
            p8((perm >> 8) & 0xff) + b"\xe0", # mov perm[15:8], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x18\x40", # shll8 r0
            b"\x0b\x26", # or r0, r6
            p8((perm >> 0) & 0xff) + b"\xe0", # mov perm[7:0], r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x0b\x26", # or r0, r6

            b"\x3a\x23", # xor r3, r3
            p8(_NR_mprotect & 0xff) + b"\xe0", # mov _NR_mprotect, r0
            b"\x0c\x60", # extu.b r0, r0
            b"\x0b\x23", # or r0, r3

            b"\x13\xc3", # trapa #19

            b"\x83\x60", # mov r8, r0
            b"\x93\x63", # mov r9,  r3
            b"\xa3\x64", # mov r10, r4
            b"\xb3\x65", # mov r11, r5
            b"\xc3\x66", # mov r12, r6
        ]
        return b"".join(insns)


class M68K(Architecture):
    arch = "M68K"
    mode = "32"

    load_condition = [
        Elf.EM_68K,
        "M68K",
        "M68000",
        "M68K:68000",
        "M68K:68008",
        "M68K:68010",
        "M68K:68020",
        "M68K:68030",
        "M68K:68040",
        "M68K:68060",
    ]

    # https://www.nxp.com/files-static/archives/doc/ref_manual/M68000PRM.pdf
    all_registers = [
        "$d0", "$d1", "$d2", "$d3", "$d4", "$d5", "$d6", "$d7",
        "$a0", "$a1", "$a2", "$a3", "$a4", "$a5", "$fp", "$sp",
        "$ps", "$pc",
    ]
    alias_registers = {
        "$fp": "$a6", "$sp": "$a7", "$ps": "$sr",
    }
    flag_register = "$ps"
    flags_table = {
        0: "carry",
        1: "overflow",
        2: "zero",
        3: "negative",
        4: "extend",
    }
    return_register = "$d0"
    function_parameters = ["$sp"] # but unused because m68k uses stack
    syscall_register = "$d0"
    syscall_parameters = ["$d1", "$d2", "$d3", "$d4", "$d5", "$a0"]

    bit_length = 32
    endianness = "big"
    instruction_length = None # variable length
    has_delay_slot = False
    has_syscall_delay_slot = True
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = True
    unicorn_support = True

    nop_insn = b"\x71\x4e" # nop
    infloop_insn = b"\xfe\x60" # bras self
    trap_insn = b"\x48\x48" # bkpt 0
    ret_insn = b"\x75\x4e" # rts
    syscall_insn = b"\x40\x4e" # trap #0

    def is_syscall(self, insn):
        return insn.mnemonic == "trap" and insn.operands[0] == "#0"

    def is_call(self, insn):
        return insn.mnemonic in ["bsrs", "bsrw", "bsrl", "jsr"]

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        return insn.mnemonic in ["bras", "braw", "bral", "jmp"]

    def is_ret(self, insn):
        return insn.mnemonic == "rts"

    # https://sourceware.org/binutils/docs/as/M68K_002dBranch.html
    def is_conditional_branch(self, insn):
        conditions = [
            "hi", "ls", "cc", "cs", "ne", "eq", "vc",
            "vs", "pl", "mi", "ge", "lt", "gt", "le",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"b{cc}s", f"b{cc}w", f"b{cc}l"]:
                return True
        conditions = [
            "hi", "ls", "cc", "cs", "ne", "eq", "vc",
            "vs", "pl", "mi", "ge", "lt", "gt", "le",
            "t", "f",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"db{cc}w", f"db{cc}"]:
                return True
        conditions = [
            "ne", "eq", "ge", "lt", "gt", "le", "f", "t",
            "gl", "gle", "nge", "ngl", "ngle", "ngt", "nle", "nlt",
            "oge", "ogl", "ogt", "ole", "olt", "or",
            "seq", "sf", "sne", "st", "ueq", "uge", "ugt", "ule", "ult", "un",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"fb{cc}w", f"fb{cc}l"]:
                return True
        return False

    def is_branch_taken(self, insn):
        mnemo = insn.mnemonic
        flags = {self.flags_table[k]: k for k in self.flags_table}
        val = get_register(self.flag_register)
        taken, reason = False, ""

        carry = bool(val & (1 << flags["carry"]))
        overflow = bool(val & (1 << flags["overflow"]))
        zero = bool(val & (1 << flags["zero"]))
        negative = bool(val & (1 << flags["negative"]))

        if mnemo in ["bhis", "bhiw", "bhil"]:
            taken, reason = not carry and not zero, "!C && !Z"
        elif mnemo in ["blss", "blsw", "blsl"]:
            taken, reason = carry or zero, "C || Z"
        elif mnemo in ["bccs", "bccw", "bccl"]:
            taken, reason = not carry, "!C"
        elif mnemo in ["bcss", "bcsw", "bcsl"]:
            taken, reason = carry, "C"
        elif mnemo in ["bnes", "bnew", "bnel"]:
            taken, reason = not zero, "!Z"
        elif mnemo in ["beqs", "beqw", "beql"]:
            taken, reason = zero, "Z"
        elif mnemo in ["bvcs", "bvcw", "bvcl"]:
            taken, reason = not overflow, "!V"
        elif mnemo in ["bvss", "bvsw", "bvsl"]:
            taken, reason = overflow, "V"
        elif mnemo in ["bpls", "bplw", "bpll"]:
            taken, reason = not negative, "!N"
        elif mnemo in ["bmis", "bmiw", "bmil"]:
            taken, reason = negative, "N"
        elif mnemo in ["bges", "bgew", "bgel"]:
            taken, reason = (negative and overflow) or (not negative and not overflow), "(N && V) || (!N && !V)"
        elif mnemo in ["blts", "bltw", "bltl"]:
            taken, reason = (negative and not overflow) or (not negative and overflow), "(N && !V) || (!N && V)"
        elif mnemo in ["bgts", "bgtw", "bgtl"]:
            taken = (negative and overflow and not zero) or (not negative and not overflow and not zero)
            reason = "(N && V && !Z) || (!N && !V && !Z)"
        elif mnemo in ["bles", "blew", "blel"]:
            taken, reason = zero or (negative and not overflow) or (not negative and overflow), "Z || (N && !V) || (!N && V)"
        elif mnemo in ["dbhiw", "dbhi"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = (carry or zero) and val != 0, "(C || Z) && {:s}==0".format(regname)
        elif mnemo in ["dblsw", "dbls"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = not carry and not zero and val != 0, "!C && !Z && {:s}==0".format(regname)
        elif mnemo in ["dbccw", "dbcc"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = carry and val != 0, "C && {:s}==0".format(regname)
        elif mnemo in ["dbcsw", "dbcs"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = not carry and val != 0, "!C && {:s}==0".format(regname)
        elif mnemo in ["dbnew", "dbne"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = zero and val != 0, "Z && {:s}==0".format(regname)
        elif mnemo in ["dbeqw", "dbeq"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = not zero and val != 0, "!Z && {:s}==0".format(regname)
        elif mnemo in ["dbvcw", "dbvc"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = overflow and val != 0, "V && {:s}==0".format(regname)
        elif mnemo in ["dbvsw", "dbvs"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = not overflow and val != 0, "!V && {:s}==0".format(regname)
        elif mnemo in ["dbplw", "dbpl"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = negative and val != 0, "N && {:s}==0".format(regname)
        elif mnemo in ["dbmiw", "dbmi"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = not negative and val != 0, "!N && {:s}==0".format(regname)
        elif mnemo in ["dbgew", "dbge"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken = ((negative and not overflow) or (not negative and overflow)) and val != 0
            reason = "((N && !V) || (!N && V)) && {:s}==0".format(regname)
        elif mnemo in ["dbltw", "dblt"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken = ((negative and overflow) or (not negative and not overflow)) and val != 0
            reason = "((N && V) || (!N && !V)) && {:s}==0".format(regname)
        elif mnemo in ["dbgtw", "dbgt"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken = (zero or (negative and not overflow) or (not negative and overflow)) and val != 0
            reason = "(Z || (N && !V) || (!N && V)) && {:s}==0".format(regname)
        elif mnemo in ["dblew", "dble"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken = ((negative and overflow and not zero) or (not negative and not overflow and not zero)) and val != 0
            reason = "((N && V && !Z) || (!N && !V && !Z)) && {:s}==0".format(regname)
        elif mnemo in ["dbtw", "dbt"]: # branch never taken
            taken, reason = False, ""
        elif mnemo in ["dbfw", "dbf"]:
            regname = insn.operands[0].replace("%", "$")
            val = get_register(regname)
            taken, reason = val != 0, "{:s}==0".format(regname)
        # TODO: fbXXw, fbXXl
        return taken, reason

    def flag_register_to_human(self, val=None):
        if not val:
            reg = self.flag_register
            val = get_register(reg)
        return Architecture.flags_to_human(val, self.flags_table)

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = to_unsigned_long(AddressUtil.dereference(current_arch.sp))
            if frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_ith_parameter(self, i, in_func=True):
        if in_func:
            i += 1 # Account for RA being at the top of the stack
        sp = current_arch.sp
        sz = current_arch.ptrsize
        loc = sp + (i * sz)
        val = read_int_from_memory(loc)
        key = "[sp + {:#x}]".format(i * sz)
        return key, val

    def get_tls(self):
        def adjust_offset(x):
            TLS_TCB_OFFSET = 0x7000
            if x == 0:
                return x
            return x - TLS_TCB_OFFSET

        ret = ExecSyscall(0x14d, []).exec_code() # get_thread_area
        tls = ret["reg"]["$d0"]
        return adjust_offset(tls)

    def decode_cookie(self, value, cookie):
        return value

    def encode_cookie(self, value, cookie):
        return value

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 125
        insns = [
            b"\x26\x3c" + p32(perm), # movel perm, %d3
            b"\x24\x3c" + p32(size), # movel size, %d2
            b"\x22\x3c" + p32(addr), # movel addr, %d1
            b"\x20\x3c" + p32(_NR_mprotect), # movel _NR_mprotect, %d0
            b"\x4e\x40", # trap #0
        ]
        return b"".join(insns)


class ALPHA(Architecture):
    arch = "ALPHA"
    mode = "ALPHA"

    load_condition = [
        Elf.EM_ALPHA,
        Elf.EM_ALPHA_UNOFFICIAL,
        "ALPHA",
        "ALPHA:EV4",
        "ALPHA:EV5",
        "ALPHA:EV6",
    ]

    # https://download.majix.org/dec/alpha_arch_ref.pdf
    all_registers = [
        "$v0", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6",
        "$t7", "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$fp",
        "$a0", "$a1", "$a2", "$a3", "$a4", "$a5", "$t8", "$t9",
        "$t10", "$t11", "$ra", "$t12", "$at", "$gp", "$sp", "$pc",
    ]
    alias_registers = {
        "$v0": "$r0", "$t0": "$r1", "$t1": "$r2", "$t2": "$r3",
        "$t3": "$r4", "$t4": "$r5", "$t5": "$r6", "$t6": "$r7",
        "$t7": "$r8", "$s0": "$r9", "$s1": "$r10", "$s2": "$r11",
        "$s3": "$r12", "$s4": "$r13", "$s5": "$r14", "$fp": "$r15/$s6",
        "$a0": "$r16", "$a1": "$r17", "$a2": "$r18", "$a3": "$r19",
        "$a4": "$r20", "$a5": "$r21", "$t8": "$r22", "$t9": "$r23",
        "$t10": "$r24", "$t11": "$r25", "$ra": "$r26", "$t12": "$r27/$pv",
        "$at": "$r28", "$gp": "$r29", "$sp": "$r30", "$pc": "$r31/$zero",
    }
    flag_register = None # alpha has no flags register
    return_register = "$v0"
    function_parameters = ["$a0", "$a1", "$a2", "$a3", "$a4", "$a5"]
    syscall_register = "$v0"
    syscall_parameters = ["$a0", "$a1", "$a2", "$a3", "$a4", "$a5"]

    bit_length = 64
    endianness = "little"
    instruction_length = 4
    has_delay_slot = False
    has_syscall_delay_slot = False
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\x1f\x04\xff\x47" # nop
    infloop_insn = b"\xff\xff\xff\xc3" # br self
    trap_insn = b"\x80\x00\x00\x00" # bpt
    ret_insn = b"\x01\x80\xfa\x6b" # ret
    syscall_insn = b"\x83\x00\x00\x00" # callsys

    def is_syscall(self, insn):
        return insn.mnemonic in ["callsys"]

    def is_call(self, insn):
        return insn.mnemonic in ["br", "bsr", "jsr"]

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        return insn.mnemonic in ["jmp"]

    def is_ret(self, insn):
        return insn.mnemonic in ["ret", "jsr_coroutine"]

    def is_conditional_branch(self, insn):
        branch_mnemos = [
            "beq", "bge", "bgt", "blbc", "blbs", "ble", "blt", "bne",
        ]
        return insn.mnemonic in branch_mnemos

    def is_branch_taken(self, insn):
        mnemo, ops = insn.mnemonic, insn.operands
        taken, reason = False, ""

        if len(ops) == 0:
            return taken, reason

        regname = ops[0]
        regval = get_register(regname)
        if regval is None:
            return taken, reason

        if mnemo == "beq":
            taken, reason = regval == 0, "{:s} == 0".format(regname)
        elif mnemo == "bne":
            taken, reason = regval != 0, "{:s} != 0".format(regname)
        elif mnemo == "bge":
            taken, reason = regval >= 0, "{:s} >= 0".format(regname)
        elif mnemo == "bgt":
            taken, reason = regval > 0, "{:s} > 0".format(regname)
        elif mnemo == "ble":
            taken, reason = regval <= 0, "{:s} <= 0".format(regname)
        elif mnemo == "blt":
            taken, reason = regval < 0, "{:s} < 0".format(regname)
        elif mnemo == "blbc":
            taken, reason = (regval & 1) == 0, "({:s}&1) == 0".format(regname)
        elif mnemo == "blbs":
            taken, reason = (regval & 1) == 1, "({:s}&1) == 1".format(regname)

        return taken, reason

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$ra")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        codes = [b"\x9e\x00\x00\x00"] # rduniq
        ret = ExecAsm(codes).exec_code()
        return ret["reg"]["$v0"]

    def decode_cookie(self, value, cookie):
        return value ^ cookie

    def encode_cookie(self, value, cookie):
        return value ^ cookie

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 74

        def lda_v0(x):
            return p32(0x201f0000 | x)

        def op_ii(op, reg1, imm, reg2):
            fmt = "0b{:06b}_{:05b}_{:08b}_1_0111001_{:05b}"
            val = fmt.format(op, reg1, imm, reg2)
            return p32(int(val, 2))

        def op_ir(op, reg1, reg2, reg3):
            fmt = "0b{:06b}_{:05b}_{:05b}_000_0_0100000_{:05b}"
            val = fmt.format(op, reg1, reg2, reg3)
            return p32(int(val, 2))

        insns = [
            lda_v0((addr >> 49) & 0x7fff), # lda v0, addr[63:49]
            op_ir(0x11, 16, 0, 16), # or a0, v0, a0
            op_ii(0x12, 16, 0xf, 16), # sll a0, 0xf, a0
            lda_v0((addr >> 34) & 0x7fff), # lda v0, addr[48:34]
            op_ir(0x11, 16, 0, 16), # or a0, v0, a0
            op_ii(0x12, 16, 0xf, 16), # sll a0, 0xf, a0
            lda_v0((addr >> 19) & 0x7fff), # lda v0, addr[33:19]
            op_ir(0x11, 16, 0, 16), # or a0, v0, a0
            op_ii(0x12, 16, 0xf, 16), # sll a0, 0xf, a0
            lda_v0((addr >> 4) & 0x7fff), # lda v0, addr[18:4]
            op_ir(0x11, 16, 0, 16), # or a0, v0, a0
            op_ii(0x12, 16, 0x4, 16), # sll a0, 0x4, a0
            lda_v0((addr >> 0) & 0xf), # lda v0, addr[3:0]
            op_ir(0x11, 16, 0, 16), # or a0, v0, a0

            lda_v0((size >> 49) & 0x7fff), # lda v0, size[63:49]
            op_ir(0x11, 17, 0, 17), # or a1, v0, a1
            op_ii(0x12, 17, 0xf, 17), # sll a1, 0xf, a1
            lda_v0((size >> 34) & 0x7fff), # lda v0, size[48:34]
            op_ir(0x11, 17, 0, 17), # or a1, v0, a1
            op_ii(0x12, 17, 0xf, 17), # sll a1, 0xf, a1
            lda_v0((size >> 19) & 0x7fff), # lda v0, size[33:19]
            op_ir(0x11, 17, 0, 17), # or a1, v0, a1
            op_ii(0x12, 17, 0xf, 17), # sll a1, 0xf, a1
            lda_v0((size >> 4) & 0x7fff), # lda v0, size[18:4]
            op_ir(0x11, 17, 0, 17), # or a1, v0, a1
            op_ii(0x12, 17, 0x4, 17), # sll a1, 0x4, a1
            lda_v0((size >> 0) & 0xf), # lda v0, size[3:0]
            op_ir(0x11, 17, 0, 17), # or a1, v0, a1

            lda_v0((perm >> 49) & 0x7fff), # lda v0, perm[63:49]
            op_ir(0x11, 18, 0, 18), # or a2, v0, a2
            op_ii(0x12, 18, 0xf, 18), # sll a2, 0xf, a2
            lda_v0((perm >> 34) & 0x7fff), # lda v0, perm[48:34]
            op_ir(0x11, 18, 0, 18), # or a2, v0, a2
            op_ii(0x12, 18, 0xf, 18), # sll a2, 0xf, a2
            lda_v0((perm >> 19) & 0x7fff), # lda v0, perm[33:19]
            op_ir(0x11, 18, 0, 18), # or a2, v0, a2
            op_ii(0x12, 18, 0xf, 18), # sll a2, 0xf, a2
            lda_v0((perm >> 4) & 0x7fff), # lda v0, perm[18:4]
            op_ir(0x11, 18, 0, 18), # or a2, v0, a2
            op_ii(0x12, 18, 0xf, 18), # sll a2, 0xf, a2
            lda_v0((perm >> 0) & 0xf), # lda v0, perm[3:0]
            op_ir(0x11, 18, 0, 18), # or a2, v0, a2

            lda_v0(_NR_mprotect), # lda v0, _NR_mprotect
            p32(0x00000083), # callsys
        ]
        return b"".join(insns)


class HPPA(Architecture):
    arch = "HPPA"
    mode = "32"

    load_condition = [
        # Elf.EM_PARISC cannot determine whether it is 32-bit or 64-bit, so it should not be used
        "PARISC",
        "PARISC32",
        "PA-RISC",
        "PA-RISC32",
        "HPPA",
        "HPPA32",
        "HPPA1.0",
        "HPPA1.1",
    ]

    # https://parisc.wiki.kernel.org/images-parisc/6/68/Pa11_acd.pdf
    all_registers = [
        "$r1", "$rp", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8",
        "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$r16",
        "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23", "$r24",
        "$r25", "$r26", "$dp", "$ret0", "$ret1", "$sp", "$r31", "$pc",
        "$flags", "$pcoqh", "$pcsqh", "$pcoqt", "$pcsqt",
    ]
    alias_registers = {
        "$rp": "$r2", "$dp": "$r27", "$ret0": "$r28", "$ret1": "$r29",
        "$sp": "$r30",
    }
    flag_register = None # HPPA has no flags register
    return_register = "$ret0"
    function_parameters = ["$r26", "$r25", "$r24", "$r23"]
    syscall_register = "$r20"
    syscall_parameters = ["$r26", "$r25", "$r24", "$r23", "$r22", "$r21"]

    bit_length = 32
    endianness = "big"
    instruction_length = 4
    has_delay_slot = True
    has_syscall_delay_slot = True
    has_ret_delay_slot = True
    stack_grow_down = True
    tls_supported = True

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\x40\x02\x00\x08" # nop
    infloop_insn = b"\xf7\x1f\x1f\xe8" # b,l,n self, r0
    trap_insn = None
    ret_insn = b"\x02\xc0\x40\xe8" # bv.n r0(rp)
    syscall_insn = b"\x00\x82\x00\xe4" # be,l 100(sr2, r0), sr0, r31

    def is_syscall(self, insn):
        return insn.mnemonic == "be,l" and insn.operands[:4] == ["100(sr2", "r0)", "sr0", "r31"]

    def is_call(self, insn):
        if self.is_syscall(insn):
            return False
        if insn.mnemonic in ["b,l", "b,l,n"]: # alias for BL,n
            return True
        if insn.mnemonic in ["blr", "blr,n"]: # alias for BLR,n
            return True
        if insn.mnemonic in ["be,l", "be,l,n"]: # alias for BLE,n
            return True
        return False

    def is_jump(self, insn):
        if self.is_ret(insn):
            return False
        if self.is_conditional_branch(insn):
            return True
        if insn.mnemonic in ["b,gate", "b,gate,n"]: # alias for GATE,n
            return True
        if insn.mnemonic in ["bv", "bv,n"]: # alias for BV,n
            return True
        if insn.mnemonic in ["be", "be,n"]: # alias for BE,n
            return True
        return False

    def is_ret(self, insn):
        return insn.mnemonic == "bv,n" and insn.operands[-1] == "r0(rp)"

    def is_conditional_branch(self, insn):
        if insn.mnemonic.startswith(("movb", "movib")): # alias for MOVB,cond,n / MOVIB,cond,n
            return True
        if insn.mnemonic.startswith(("cmpb", "cmpib")): # alias for COMB[TF},cond,n / COMIB[TF],cond,n
            return True
        if insn.mnemonic.startswith(("addb", "addib")): # alias for ADDB[TF],cond,n / ADDIB[TF],cond,n
            return True
        if insn.mnemonic.startswith("bb,"): # alias for BVB,cond,n / BB,cond,n
            return True
        return False

    def is_branch_taken(self, insn):

        def check_cond_mov(c, name, val):
            if c == 0: # never
                taken, reason = False, ""
            elif c == 1: # =
                taken, reason = val == 0, "{:s}==0".format(name)
            elif c == 2: # <
                taken, reason = (val >> [31, 63][is_64bit()]) == 1, "MSB({:s})==1".format(name)
            elif c == 3: # OD
                taken, reason = (val & 1) == 1, "LSB({:s})==1".format(name)
            elif c == 4: # TR
                taken, reason = True, "Always True"
            elif c == 5: # <>
                taken, reason = val != 0, "{:s}!=0".format(name)
            elif c == 6: # EV
                taken, reason = (val & 1) == 0, "LSB({:s})==0".format(name)
            return taken, reason

        def check_cond_cmp(c, f, name1, val1, name2, val2):
            if c == 0: # never
                if not f:
                    taken, reason = False, ""
                else:
                    taken, reason = True, "Always True"
            elif c == 1: # =
                if not f:
                    taken, reason = val1 == val2, "{:s}=={:s}".format(name1, name2)
                else:
                    taken, reason = val1 != val2, "{:s}!={:s}".format(name1, name2)
            elif c == 2: # < (signed)
                if not f:
                    taken, reason = val1 < val2, "{:s}<{:s}".format(name1, name2)
                else:
                    taken, reason = val1 >= val2, "{:s}>={:s}".format(name1, name2)
            elif c == 3: # <= (signed)
                if not f:
                    taken, reason = val1 <= val2, "{:s}<={:s}".format(name1, name2)
                else:
                    taken, reason = val1 > val2, "{:s}>{:s}".format(name1, name2)
            elif c == 4: # < (unsigned)
                if is_64bit():
                    shift = 64
                else:
                    shift = 32
                val1 &= (1 << shift) - 1
                val2 &= (1 << shift) - 1
                if not f:
                    taken, reason = val1 < val2, "{:s}<{:s} (unsigned)".format(name1, name2)
                else:
                    taken, reason = val1 >= val2, "{:s}>={:s} (unsigned)".format(name1, name2)
            elif c == 5: # <= (unsigned)
                if is_64bit():
                    shift = 64
                else:
                    shift = 32
                val1 &= (1 << shift) - 1
                val2 &= (1 << shift) - 1
                if not f:
                    taken, reason = val1 <= val2, "{:s}<={:s} (unsigned)".format(name1, name2)
                else:
                    taken, reason = val1 > val2, "{:s}>{:s} (unsigned)".format(name1, name2)
            elif c == 6: # SV
                if is_64bit():
                    shift = 63
                else:
                    shift = 31
                val1_sign = (val1 >> shift) & 1
                val2_sign = (val2 >> shift) & 1
                ans_sign = ((val1 - val2) >> shift) & 1
                overflow = (val1_sign != val2_sign) and (val1_sign != ans_sign) # subtract overflow
                if not f:
                    taken, reason = overflow, "{:s}-{:s} overflows".format(name1, name2)
                else:
                    taken, reason = overflow, "{:s}-{:s} does not overflow".format(name1, name2)
            elif c == 7: # OD
                if not f:
                    taken, reason = ((val1 - val2) & 1) == 1, "LSB({:s}-{:s})==1".format(name1, name2)
                else:
                    taken, reason = ((val1 - val2) & 1) == 0, "LSB({:s}-{:s})==0".format(name1, name2)
            return taken, reason

        def check_cond_add(c, f, name1, val1, name2, val2):
            if c == 0: # never
                if not f:
                    taken, reason = False, ""
                else:
                    taken, reason = True, "Always True"
            elif c == 1: # =
                if not f:
                    taken, reason = val1 == -val2, "{:s}==-{:s}".format(name1, name2)
                else:
                    taken, reason = val1 != -val2, "{:s}!=-{:s}".format(name1, name2)
            elif c == 2: # < (signed)
                if not f:
                    taken, reason = val1 < -val2, "{:s}<-{:s} (signed)".format(name1, name2)
                else:
                    taken, reason = val1 >= -val2, "{:s}>=-{:s} (signed)".format(name1, name2)
            elif c == 3: # <= (signed)
                if not f:
                    taken, reason = val1 <= -val2, "{:s}<=-{:s} (signed)".format(name1, name2)
                else:
                    taken, reason = val1 > -val2, "{:s}>-{:s} (signed)".format(name1, name2)
            elif c == 4: # NUV (unsigned)
                if is_64bit():
                    shift = 63
                else:
                    shift = 31
                val1 &= (1 << (shift + 1)) - 1
                val2 &= (1 << (shift + 1)) - 1
                val1_sign = (val1 >> shift) & 1
                val2_sign = (val2 >> shift) & 1
                ans_sign = ((val1 + val2) >> shift) & 1
                overflow = (val1_sign == val2_sign) and (val1_sign != ans_sign) # addition overflow
                if not f:
                    taken, reason = not overflow, "{:s}+{:s} does not overflow (unsigned)".format(name1, name2)
                else:
                    taken, reason = overflow, "{:s}+{:s} overflows (unsigned)".format(name1, name2)
            elif c == 5: # ZNV (unsigned)
                if is_64bit():
                    shift = 63
                else:
                    shift = 31
                val1 &= (1 << (shift + 1)) - 1
                val2 &= (1 << (shift + 1)) - 1
                val1_sign = (val1 >> shift) & 1
                val2_sign = (val2 >> shift) & 1
                ans_sign = ((val1 + val2) >> shift) & 1
                overflow = (val1_sign == val2_sign) and (val1_sign != ans_sign) # addition overflow
                zero = (val1 + val2) == 0
                if not f:
                    taken, reason = zero or not overflow, "{:s}+{:s} is zero or no overflow (unsigned)".format(name1, name2)
                else:
                    taken, reason = not zero and overflow, "{:s}+{:s} is nonzero and overflows (unsigned)".format(name1, name2)
            elif c == 6: # SV (signed)
                if is_64bit():
                    shift = 63
                else:
                    shift = 31
                val1_sign = (val1 >> shift) & 1
                val2_sign = (val2 >> shift) & 1
                ans_sign = ((val1 + val2) >> shift) & 1
                overflow = (val1_sign == val2_sign) and (val1_sign != ans_sign) # addition overflow
                if not f:
                    taken, reason = overflow, "{:s}+{:s} overflows (signed)".format(name1, name2)
                else:
                    taken, reason = not overflow, "{:s}+{:s} does not overflow (signed)".format(name1, name2)
            elif c == 7: # OD
                if not f:
                    taken, reason = ((val1 + val2) & 1) == 1, "LSB({:s}-{:s})==1".format(name1, name2)
                else:
                    taken, reason = ((val1 + val2) & 1) == 0, "LSB({:s}-{:s})==0".format(name1, name2)
            return taken, reason

        def check_cond_bit(c, name1, val1, name2, val2):
            if is_64bit():
                shift = 63
            else:
                shift = 31
            bit_on = ((val1 >> (shift - val2)) & 1) == 1
            if c == 2: # <
                taken, reason = bit_on, "{:s}.bit({:s})==1".format(name1, name2)
            elif c == 6: # >=
                taken, reason = not bit_on, "{:s}.bit({:s})==0".format(name1, name2)
            else:
                taken, reason = False, ""
            return taken, reason

        taken, reason = False, ""
        if insn.mnemonic.startswith("movb"):
            c = (insn.opcodes[2] >> 5) & 0b111
            v1 = insn.operands[0] # source
            taken, reason = check_cond_mov(c, v1, get_register(v1))
        elif insn.mnemonic.startswith("movib"):
            c = (insn.opcodes[2] >> 5) & 0b111
            v1 = insn.operands[0] # source
            taken, reason = check_cond_mov(c, v1, int(v1, 16))
        elif insn.mnemonic.startswith("cmpb"):
            c = (insn.opcodes[2] >> 5) & 0b111
            f = (insn.opcodes[0] >> 3) & 1
            v1 = insn.operands[0] # source1
            v2 = insn.operands[1] # source2
            taken, reason = check_cond_cmp(c, f, v1, get_register(v1), v2, get_register(v2))
        elif insn.mnemonic.startswith("cmpib"):
            c = (insn.opcodes[2] >> 5) & 0b111
            f = (insn.opcodes[0] >> 3) & 1
            v1 = insn.operands[0] # source1
            v2 = insn.operands[1] # source2
            taken, reason = check_cond_cmp(c, f, v1, int(v1, 16), v2, get_register(v2))
        elif insn.mnemonic.startswith("addb"):
            c = (insn.opcodes[2] >> 5) & 0b111
            f = (insn.opcodes[0] >> 3) & 1
            v1 = insn.operands[0] # source1
            v2 = insn.operands[1] # source2
            taken, reason = check_cond_add(c, f, v1, get_register(v1), v2, get_register(v2))
        elif insn.mnemonic.startswith("addib"):
            c = (insn.opcodes[2] >> 5) & 0b111
            f = (insn.opcodes[0] >> 3) & 1
            v1 = insn.operands[0] # source1
            v2 = insn.operands[1] # source2
            taken, reason = check_cond_add(c, f, v1, int(v1, 16), v2, get_register(v2))
        elif insn.mnemonic.startswith("bb,"): # bb and bvb
            c = (insn.opcodes[2] >> 5) & 0b111
            v1 = insn.operands[0] # source1
            v2 = insn.operands[1] # source2
            vbit = (insn.opcodes[0] >> 2) & 1
            if vbit:
                taken, reason = check_cond_bit(c, v1, get_register(v1), v2, int(v2, 16)) # bb,cond,n
            else:
                taken, reason = check_cond_bit(c, v1, get_register(v1), v2, get_register(v2)) # bvb,cond,n

        if not taken:
            reason = ""
        return taken, reason

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            i -= len(self.function_parameters)
            ret0 = get_register("$ret0")
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = ret0 - (i * sz)
            val = read_int_from_memory(loc)
            key = "[sp - {:#x}]".format(sp - loc)
            return key, val

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$rp") & ~0b11
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        codes = [b"\xbc\x08\x60\x03"] # mfctl tr3, ret0
        ret = ExecAsm(codes).exec_code()
        return ret["reg"]["$ret0"]

    def decode_cookie(self, value, cookie):
        return value

    def encode_cookie(self, value, cookie):
        return value

    def mprotect_asm(self, addr, size, perm):

        def asm21(x):
            temp = (x & 0x100000) >> 20
            temp |= (x & 0x0ffe00) >> 8
            temp |= (x & 0x000180) << 7
            temp |= (x & 0x00007c) << 14
            temp |= (x & 0x000003) << 12
            return "{:021b}".format(temp)

        def imm14(x, len=14):
            i = len_ones = 0
            while i < len:
                len_ones = (len_ones << 1) | 1
                i += 1
            one_bit_at_len = 1 << (len - 1)
            sign = x & len_ones & one_bit_at_len
            sign >>= (len - 1)
            rest = x & len_ones & (len_ones ^ one_bit_at_len)
            rest <<= 1
            return "{:014b}".format(rest | sign)

        def ldil(reg, imm):
            fmt = "0b001000_{:05b}_{:s}"
            val = fmt.format(reg, asm21(imm))
            return p32(int(val, 2))

        def ldo(reg1, reg2, imm):
            fmt = "0b001101_{:05b}_{:05b}_00_{:s}"
            val = fmt.format(reg1, reg2, imm14(imm))
            return p32(int(val, 2))

        _NR_mprotect = 125
        insns = [
            ldil(26, addr >> 11), # ldil L%addr[31:11], r26
            ldo(26, 26, addr & 0x7ff), # ldo addr[10:0](r26), r26
            ldil(25, size >> 11), # ldil L%size[31:11], r25
            ldo(25, 25, size & 0x7ff), # ldo size[10:0](r25), r25
            ldil(24, perm >> 11), # ldil L%perm[31:11], r24
            ldo(24, 24, perm & 0x7ff), # ldo perm[10:0](r24), r24
            ldil(20, _NR_mprotect >> 11), # ldil L%_NR_mprotect[31:11], r20
            ldo(20, 20, _NR_mprotect & 0x7ff), # ldo _NR_mprotect[10:0](r20), r20
            p32(0xe4008200), # be,l 100(sr2, r0), sr0, r31
        ]
        return b"".join(insns)


class HPPA64(HPPA):
    arch = "HPPA"
    mode = "64"

    load_condition = [
    ]

    bit_length = 64

    # qemu does not support hppa64, so I could not test


class OR1K(Architecture):
    arch = "OR1K"
    mode = "OR1K"

    load_condition = [
        Elf.EM_OPENRISC,
        "OPENRISC",
        "OPENRISC1000",
        "OR1K",
    ]

    # https://openrisc.io/or1k.html
    # https://sourceware.org/cgen/gen-doc/openrisc-insn.html
    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23",
        "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31",
        "$ppc", "$npc", "$sr",
    ]
    alias_registers = {
        "$r1": "$sp", "$r9": "$lr",
    }
    flag_register = "$sr"
    flags_table = {
        11: "overflow",
        10: "carry",
        9: "flag",
    }
    return_register = "$r11"
    function_parameters = ["$r3", "$r4", "$r5", "$r6", "$r7", "$r8"]
    syscall_register = "$r11"
    syscall_parameters = ["$r3", "$r4", "$r5", "$r6", "$r7", "$r8"]

    bit_length = 32
    endianness = "big"
    instruction_length = 4
    has_delay_slot = True
    has_syscall_delay_slot = True
    has_ret_delay_slot = True
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\x00\x00\x00\x15" # l.nop 0x0
    infloop_insn = b"\x00\x00\x00\x00" # l.j self
    trap_insn = None
    ret_insn = b"\x00\x48\x00\x44" # l.jr r9
    syscall_insn = b"\x01\x00\x00\x20" # l.sys 0x1

    def is_syscall(self, insn):
        return insn.mnemonic == "l.sys" and insn.operands[0] == "0x1"

    def is_call(self, insn):
        return insn.mnemonic in ["l.bal", "l.jal", "ljalr"]

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        return insn.mnemonic in ["l.j", "l.jr"]

    def is_ret(self, insn):
        if insn.mnemonic == "l.jr" and insn.operands[0] == "r9":
            return True
        if insn.mnemonic in ["l.rfe"]:
            return True
        return False

    def is_conditional_branch(self, insn):
        return insn.mnemonic in ["l.bf", "l.bnf"]

    def is_branch_taken(self, insn):
        mnemo = insn.mnemonic
        val = get_register(self.flag_register)
        flags = {self.flags_table[k]: k for k in self.flags_table}
        taken, reason = False, ""

        flag = bool(val & (1 << flags["flag"]))

        if mnemo == "l.bf":
            taken, reason = flag, "F"
        if mnemo == "l.bnf":
            taken, reason = not flag, "!F"
        return taken, reason

    def flag_register_to_human(self, val=None):
        if not val:
            reg = self.flag_register
            val = get_register(reg)
        return Architecture.flags_to_human(val, self.flags_table)

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$r9")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        return get_register("$r10")

    def decode_cookie(self, value, cookie):
        return value

    def encode_cookie(self, value, cookie):
        return value

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 226
        insns = [
            p32(0xa8600000 | (addr >> 16)), # l.ori r3, r0, addr[31:16]
            p32(0xb8630010), # l.slli r3, r3, 16
            p32(0xa8630000 | (addr & 0xffff)), # l.ori r3, r6, addr[15:0]

            p32(0xa8800000 | (size >> 16)), # l.ori r4, r0, size[31:16]
            p32(0xb8840010), # l.slli r4, r4, 16
            p32(0xa8840000 | (size & 0xffff)), # l.ori r4, r6, size[15:0]

            p32(0xa8a00000 | (perm >> 16)), # l.ori r5, r0, perm[31:16]
            p32(0xb8a50010), # l.slli r5, r5, 16
            p32(0xa8a50000 | (perm & 0xffff)), # l.ori r5, r6, perm[15:0]

            p32(0xa9600000 | _NR_mprotect), # l.ori r11, r0, _NR_mprotect

            p32(0x20000001), # l.sys 0x1
            p32(0x15000000), # l.nop 0x0 (delay slot)
        ]
        return b"".join(insns)


class NIOS2(Architecture):
    arch = "NIOS2"
    mode = "NIOS2"

    load_condition = [
        Elf.EM_ALTERA_NIOS2,
        "NIOS2",
        "NIOS2:R1",
        "NIOS2:R2",
    ]

    # https://www.intel.com/content/www/us/en/docs/programmable/683836/current/introduction.html
    # https://www.intel.co.jp/content/dam/altera-www/global/ja_JP/pdfs/literature/hb/nios2/n2cpu-nii5v1gen2-j.pdf
    all_registers = [
        "$zero", "$at", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23",
        "$et", "$bt", "$gp", "$sp", "$fp", "$ea", "$sstatus", "$ra",
        "$pc",
    ]
    alias_registers = {
        "$zero": "$r0", "$at": "$r1", "$et": "$r24", "$bt": "$r25",
        "$gp": "$r26", "$sp": "$r27", "$fp": "$r28", "$ea": "$r29",
        "$sstatus": "$r30", "$ra": "$r31",
    }
    flag_register = None # NIOS2 has no flags register
    return_register = "$r2"
    function_parameters = ["$r4", "$r5", "$r6", "$r7"]
    syscall_register = "$r2"
    syscall_parameters = ["$r4", "$r5", "$r6", "$r7", "$r8", "$r9"]

    bit_length = 32
    endianness = "little"
    instruction_length = 4
    has_delay_slot = False
    has_syscall_delay_slot = False
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\x3a\x88\x01\x00" # nop
    infloop_insn = b"\x06\xff\x3f\x00" # br self
    trap_insn = None
    ret_insn = b"\x3a\x28\x00\xf8" # ret
    syscall_insn = b"\x3a\x68\x3b\x00" # trap 0

    def is_syscall(self, insn):
        return insn.mnemonic == "trap" and insn.operands[0] == "0"

    def is_call(self, insn):
        return insn.mnemonic in ["call", "callr"]

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        return insn.mnemonic in ["br", "jmp", "jmpi"]

    def is_ret(self, insn):
        return insn.mnemonic in ["ret", "bret", "eret"]

    def is_conditional_branch(self, insn):
        branch_mnemos = [
            "beq", "bne",
            "bge", "bgeu", "bgt", "bgtu",
            "ble", "bleu", "blt", "bltu",
        ]
        return insn.mnemonic in branch_mnemos

    def is_branch_taken(self, insn):
        mnemo, ops = insn.mnemonic, insn.operands
        v0 = get_register(ops[0])
        v1 = get_register(ops[1])

        pI = lambda a: struct.pack("<I", a & 0xffffffff)
        ui = lambda a: struct.unpack("<i", a)[0]
        u2i = lambda a: ui(pI(a))
        v0s = u2i(v0)
        v1s = u2i(v1)

        taken, reason = False, ""
        if mnemo == "beq":
            taken, reason = v0 == v1, "{:s}=={:s}".format(ops[0], ops[1])
        elif mnemo == "bne":
            taken, reason = v0 != v1, "{:s}!={:s}".format(ops[0], ops[1])
        elif mnemo == "bge":
            taken, reason = v0s >= v1s, "{:s}>={:s} (signed)".format(ops[0], ops[1])
        elif mnemo == "bgeu":
            taken, reason = v0 >= v1, "{:s}>={:s} (unsigned)".format(ops[0], ops[1])
        elif mnemo == "bgt":
            taken, reason = v0s > v1s, "{:s}>{:s} (signed)".format(ops[0], ops[1])
        elif mnemo == "bgtu":
            taken, reason = v0 > v1, "{:s}>{:s} (unsigned)".format(ops[0], ops[1])
        elif mnemo == "ble":
            taken, reason = v0s <= v1s, "{:s}<={:s} (signed)".format(ops[0], ops[1])
        elif mnemo == "bleu":
            taken, reason = v0 <= v1, "{:s}<={:s} (unsigned)".format(ops[0], ops[1])
        elif mnemo == "blt":
            taken, reason = v0s < v1s, "{:s}<{:s} (signed)".format(ops[0], ops[1])
        elif mnemo == "bltu":
            taken, reason = v0 < v1, "{:s}<{:s} (unsigned)".format(ops[0], ops[1])
        return taken, reason

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$ra")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        def adjust_offset(x):
            TLS_TCB_OFFSET = 0x7000
            if x == 0:
                return x
            return x - TLS_TCB_OFFSET

        tls = get_register("$r23")
        return adjust_offset(tls)

    def decode_cookie(self, value, cookie):
        return value ^ cookie

    def encode_cookie(self, value, cookie):
        return value ^ cookie

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 226

        def op_i(op, reg1, reg2, imm):
            fmt = "0b{:05b}_{:05b}_{:016b}_{:06b}"
            val = fmt.format(reg1, reg2, imm, op)
            return p32(int(val, 2))

        insns = [
            op_i(0x34, 0, 4, (addr >> 16) & 0xffff), # orhi r0, r4, addr[31:16]
            op_i(0x14, 4, 4, (addr >> 0) & 0xffff), # ori r4, r4, addr[15:0]

            op_i(0x34, 0, 5, (size >> 16) & 0xffff), # orhi r0, r5, size[31:16]
            op_i(0x14, 5, 5, (size >> 0) & 0xffff), # ori r5, r5, size[15:0]

            op_i(0x34, 0, 6, (perm >> 16) & 0xffff), # orhi r0, r6, perm[31:16]
            op_i(0x14, 6, 6, (perm >> 0) & 0xffff), # ori r6, r6, perm[15:0]

            op_i(0x14, 0, 2, _NR_mprotect), # ori r0, r2, _NR_mprotect
            p32(0x003b683a), # trap 0
        ]
        return b"".join(insns)


class MICROBLAZE(Architecture):
    arch = "MICROBLAZE"
    mode = "MICROBLAZE"

    load_condition = [
        Elf.EM_MICROBLAZE,
        "MICROBLAZE",
    ]

    # https://www.xilinx.com/content/dam/xilinx/support/documents/sw_manuals/xilinx2021_2/ug984-vivado-microblaze-ref.pdf
    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23",
        "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31",
        "$rpc", "$rmsr",
    ]
    alias_registers = {
        "$r0": "$zero", "$r1": "$sp", "$r15": "$ra",
    }
    flag_register = None
    return_register = "$r3"
    function_parameters = ["$r5", "$r6", "$r7", "$r8", "$r9", "$r10"]
    syscall_register = "$r12"
    syscall_parameters = ["$r5", "$r6", "$r7", "$r8", "$r9", "$r10"]

    bit_length = 32
    endianness = "little / big"
    instruction_length = 4
    has_delay_slot = True
    has_syscall_delay_slot = True
    has_ret_delay_slot = True
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\x00\x00\x00\x80" # or r0, r0, r0
    infloop_insn = b"\x00\x00\x00\xb8" # bri self
    trap_insn = None
    ret_insn = b"\x08\x00\x0f\xb6" # rtsd r15, 8
    syscall_insn = b"\x08\x00\xcc\xb9" # brki r14,8

    def is_syscall(self, insn):
        return insn.mnemonic == "brki" and insn.operands[:2] == ["r14", "8"]

    def is_call(self, insn):
        return insn.mnemonic in ["brld", "brald", "brlid", "bralid"]

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        branch_mnemos = [
            "br", "bra", "brd", "brad",
            "bri", "brai", "brid", "braid",
        ]
        return insn.mnemonic in branch_mnemos

    def is_ret(self, insn):
        return insn.mnemonic in ["rtsd"]

    def is_conditional_branch(self, insn):
        branch_mnemos = [
            "beq", "beqd", "beqi", "beqid",
            "bne", "bned", "bnei", "bneid",
            "bge", "bged", "bgei", "bgeid",
            "bgt", "bgtd", "bgti", "bgtid",
            "ble", "bled", "blei", "bleid",
            "blt", "bltd", "blti", "bltid",
        ]
        return insn.mnemonic in branch_mnemos

    def is_branch_taken(self, insn):
        mnemo, ops = insn.mnemonic, [x.split()[0] for x in insn.operands]
        taken, reason = False, ""

        pI = lambda a: struct.pack("<I", a & 0xffffffff)
        ui = lambda a: struct.unpack("<i", a)[0]
        u2i = lambda a: ui(pI(a))

        v0 = u2i(get_register(ops[0])) # signed

        if mnemo in ["beq", "beqd", "beqi", "beqid"]:
            taken, reason = v0 == 0, "{:s}==0".format(ops[0])
        elif mnemo in ["bne", "bned", "bnei", "bneid"]:
            taken, reason = v0 != 0, "{:s}!=0".format(ops[0])
        elif mnemo in ["bge", "bged", "bgei", "bgeid"]:
            taken, reason = v0 >= 0, "{:s}>=0".format(ops[0])
        elif mnemo in ["bgt", "bgtd", "bgti", "bgtid"]:
            taken, reason = v0 > 0, "{:s}>0".format(ops[0])
        elif mnemo in ["ble", "bled", "blei", "bleid"]:
            taken, reason = v0 <= 0, "{:s}<=0".format(ops[0])
        elif mnemo in ["blt", "bltd", "blti", "bltid"]:
            taken, reason = v0 < 0, "{:s}<0".format(ops[0])
        return taken, reason

    def get_ith_parameter(self, i, in_func=True):
        if i < len(self.function_parameters):
            reg = self.function_parameters[i]
            val = get_register(reg)
            key = reg
            return key, val
        else:
            sp = current_arch.sp
            sz = current_arch.ptrsize
            loc = sp + (i * sz)
            val = read_int_from_memory(loc)
            key = "[sp + {:#x}]".format(i * sz)
            return key, val

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$r15")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        return get_register("$r21")

    def decode_cookie(self, value, cookie):
        return value

    def encode_cookie(self, value, cookie):
        return value

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 125

        def op_i(op, reg1, reg2, imm):
            fmt = "0b{:06b}_{:05b}_{:05b}_{:016b}"
            val = fmt.format(op, reg1, reg2, imm)
            return p32(int(val, 2))

        insns = [
            op_i(0xc, 5, 0, (addr >> 16) & 0xffff), # addik r5, r0, addr[31:16]
            op_i(0x24, 5, 5, 0x1e2), # swaph r5, r5
            op_i(0xc, 5, 5, addr & 0xffff), # addik r5, r5, addr[15:0]

            op_i(0xc, 6, 0, (size >> 16) & 0xffff), # addik r6, r0, size[31:16]
            op_i(0x24, 6, 6, 0x1e2), # swaph r6, r6
            op_i(0xc, 6, 6, size & 0xffff), # addik r6, r6, size[15:0]

            op_i(0xc, 7, 0, (perm >> 16) & 0xffff), # addik r7, r0, perm[31:16]
            op_i(0x24, 7, 7, 0x1e2), # swaph r7, r7
            op_i(0xc, 7, 7, perm & 0xffff), # addik r7, r7, perm[15:0]

            op_i(0xc, 12, 0, _NR_mprotect), # addik r12, r0, _NR_mprotect

            p32(0xb9cc0008), # brki r14,8
            p32(0x80000000), # or r0, r0, r0 # delay slot
        ]
        return b"".join(insns)


class XTENSA(Architecture):
    arch = "XTENSA"
    mode = "XTENSA"

    load_condition = [
        Elf.EM_XTENSA,
        "XTENSA",
    ]

    # https://www.cadence.com/content/dam/cadence-www/global/en_US/documents/tools/ip/tensilica-ip/isa-summary.pdf
    # https://dl.espressif.com/github_assets/espressif/xtensa-isa-doc/releases/download/latest/Xtensa.pdf
    # https://usermanual.wiki/Document/Xtensa2020ASSEMBLER20GUIDE.1231659642/html
    all_registers = [
        "$a0", "$a1", "$a2", "$a3", "$a4", "$a5", "$a6", "$a7",
        "$a8", "$a9", "$a10", "$a11", "$a12", "$a13", "$a14", "$a15",
        "$pc", "$lbeg", "$lend", "$lcount", "$sar", "$litbase", "$ps", "$threadptr",
        "$scompare1", "$acclo", "$acchi", "$expstate",
    ]
    alias_registers = {
        "$a0": "$lr", "$a1": "$sp",
    }
    flag_register = None
    return_register = "$a2"
    function_parameters = ["$a10", "$a11", "$a12", "$a13", "$a14", "$a15"]
    syscall_register = "$a2"
    syscall_parameters = ["$a6", "$a3", "$a4", "$a5", "$a8", "$a9"]

    bit_length = 32
    endianness = "little / big"
    instruction_length = None # variable length
    has_delay_slot = False
    has_syscall_delay_slot = False
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\x3d\xf0" # nop.n
    infloop_insn = b"\x06\xff\xff" # j self
    trap_insn = None
    ret_insn = b"\x1d\xf0" # retw.n
    syscall_insn = b"\x00\x50\x00" # syscall

    def is_syscall(self, insn):
        return insn.mnemonic in ["syscall"]

    def is_call(self, insn):
        call_mnemo = [
            "call0", "call4", "call8", "call12",
            "callx0", "callx4", "callx8", "callx12",
        ]
        return insn.mnemonic in call_mnemo

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        return insn.mnemonic in ["j", "jx"]

    def is_ret(self, insn):
        return insn.mnemonic in ["ret", "retw", "ret.n", "retw.n"]

    def is_conditional_branch(self, insn):
        branch_mnemos = [
            "beq", "beqz", "beqz.n", "beqi",
            "bne", "bnez", "bnez.n", "bnei",
            "bge", "bgez", "bgei", "bgeu", "bgeui",
            "blt", "bltz", "blti", "bltu", "bltui",
            "bbc", "bbs", "bbci", "bbsi",
            "bnone", "bany", "ball", "bnall",
            "bt", "bf",
        ]
        return insn.mnemonic in branch_mnemos

    def is_branch_taken(self, insn):
        mnemo, ops = insn.mnemonic, insn.operands
        taken, reason = False, ""

        pI = lambda a: struct.pack("<I", a & 0xffffffff)
        ui = lambda a: struct.unpack("<i", a)[0]
        u2i = lambda a: ui(pI(a))

        if mnemo == "beq":
            v0 = get_register(ops[0])
            v1 = get_register(ops[1])
            taken, reason = v0 == v1, "{:s}=={:s}".format(ops[0], ops[1])
        if mnemo == "beqi":
            v0 = get_register(ops[0])
            v1 = int(ops[1])
            taken, reason = v0 == v1, "{:s}=={:s}".format(ops[0], ops[1])
        elif mnemo == "bne":
            v0 = get_register(ops[0])
            v1 = get_register(ops[1])
            taken, reason = v0 != v1, "{:s}!={:s}".format(ops[0], ops[1])
        elif mnemo == "bnei":
            v0 = get_register(ops[0])
            v1 = int(ops[1])
            taken, reason = v0 != v1, "{:s}!={:s}".format(ops[0], ops[1])
        elif mnemo in ["beqz", "beqz.n"]:
            v0 = get_register(ops[0])
            taken, reason = v0 == 0, "{:s}==0".format(ops[0])
        elif mnemo in ["bnez", "bnez.n"]:
            v0 = get_register(ops[0])
            taken, reason = v0 != 0, "{:s}!=0".format(ops[0])
        elif mnemo == "bge":
            v0 = u2i(get_register(ops[0]))
            v1 = u2i(get_register(ops[1]))
            taken, reason = v0 >= v1, "{:s}>={:s} (signed)".format(ops[0], ops[1])
        elif mnemo == "bgei":
            v0 = u2i(get_register(ops[0]))
            v1 = int(ops[1])
            taken, reason = v0 >= v1, "{:s}>={:s} (signed)".format(ops[0], ops[1])
        elif mnemo == "bgeu":
            v0 = get_register(ops[0])
            v1 = get_register(ops[1])
            taken, reason = v0 >= v1, "{:s}>={:s} (unsigned)".format(ops[0], ops[1])
        elif mnemo == "bgeui":
            v0 = get_register(ops[0])
            v1 = int(ops[1])
            taken, reason = v0 >= v1, "{:s}>={:s} (unsigned)".format(ops[0], ops[1])
        elif mnemo == "bgez":
            v0 = get_register(ops[0])
            taken, reason = (v0 >> 31) == 0, "({:s}>>31)==0".format(ops[0])
        elif mnemo == "blt":
            v0 = u2i(get_register(ops[0]))
            v1 = u2i(get_register(ops[1]))
            taken, reason = v0 < v1, "{:s}<{:s} (signed)".format(ops[0], ops[1])
        elif mnemo == "blti":
            v0 = u2i(get_register(ops[0]))
            v1 = int(ops[1])
            taken, reason = v0 < v1, "{:s}<{:s} (signed)".format(ops[0], ops[1])
        elif mnemo == "bltu":
            v0 = get_register(ops[0])
            v1 = get_register(ops[1])
            taken, reason = v0 < v1, "{:s}<{:s} (unsigned)".format(ops[0], ops[1])
        elif mnemo == "bltui":
            v0 = get_register(ops[0])
            v1 = int(ops[1])
            taken, reason = v0 < v1, "{:s}<{:s} (unsigned)".format(ops[0], ops[1])
        elif mnemo == "bltz":
            v0 = get_register(ops[0])
            taken, reason = (v0 >> 31) == 1, "({:s}>>31)==1".format(ops[0])
        elif mnemo == "bany":
            v0 = get_register(ops[0])
            v1 = get_register(ops[1])
            taken, reason = (v0 & v1) != 0, "({:s}&{:s})!=0".format(ops[0], ops[1])
        elif mnemo == "bnone":
            v0 = get_register(ops[0])
            v1 = get_register(ops[1])
            taken, reason = (v0 & v1) == 0, "({:s}&{:s})==0".format(ops[0], ops[1])
        elif mnemo == "ball":
            v0 = get_register(ops[0])
            v1 = get_register(ops[1])
            taken, reason = (~v0 & v1) == 0, "(~{:s}&{:s})==0".format(ops[0], ops[1])
        elif mnemo == "bnall":
            v0 = get_register(ops[0])
            v1 = get_register(ops[1])
            taken, reason = (~v0 & v1) != 0, "(~{:s}&{:s})!=0".format(ops[0], ops[1])
        elif mnemo == "bt":
            v0 = get_register(ops[0])
            taken, reason = v0 != 0, "{:s}!=0".format(ops[0])
        elif mnemo == "bf":
            v0 = get_register(ops[0])
            taken, reason = v0 == 0, "{:s}==0".format(ops[0])
        elif mnemo == "bbs":
            v0 = get_register(ops[0])
            v1 = get_register(ops[1])
            taken, reason = ((v0 >> (v1 & 0b11111)) & 1) == 1, "Bit ({:s}&0b11111) of {:s} is 1".format(ops[1], ops[0])
        elif mnemo == "bbsi":
            v0 = get_register(ops[0])
            v1 = int(ops[1])
            taken, reason = ((v0 >> v1) & 1) == 1, "Bit {:s} of {:s} is 1".format(ops[1], ops[0])
        elif mnemo == "bbc":
            v0 = get_register(ops[0])
            v1 = get_register(ops[1])
            taken, reason = ((v0 >> (v1 & 0b11111)) & 1) == 0, "Bit ({:s}&0b11111) of {:s} is 0".format(ops[1], ops[0])
        elif mnemo == "bbci":
            v0 = get_register(ops[0])
            v1 = int(ops[1])
            taken, reason = ((v0 >> v1) & 1) == 0, "Bit {:s} of {:s} is 0".format(ops[1], ops[0])
        return taken, reason

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$a0")
                if insn.mnemonic in ["retw", "retw.n"]:
                    ra &= ~(0b11 << 30)
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        return get_register("$threadptr")

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 82

        def movi(reg, imm):
            fmt = "0b{:04b}_0010_1010_{:04b}_{:08b}"
            val = fmt.format(reg, (imm >> 8) & 0xf, imm & 0xff)
            val = int(val, 2)
            return bytes([(val >> 16) & 0xff, (val >> 8) & 0xff,  val & 0xff])

        def slli(reg1, reg2, imm):
            fmt = "0b{:04b}_0000_{:04b}_{:04b}_000{:01b}_0001"
            val = fmt.format((32 - imm) & 0xf, reg1, reg2, ((32 - imm) >> 4) & 1)
            val = int(val, 2)
            return bytes([(val >> 16) & 0xff, (val >> 8) & 0xff,  val & 0xff])

        def orr(reg1, reg2, reg3):
            fmt = "0b{:04b}_0000_{:04b}_{:04b}_0010_0000"
            val = fmt.format(reg3, reg1, reg2)
            val = int(val, 2)
            return bytes([(val >> 16) & 0xff, (val >> 8) & 0xff,  val & 0xff])

        insns = [
            movi(2, (addr >> 21) & 0x7ff), # mov a2, addr[31:21]
            slli(6, 2, 21), # slli a6, a2, 21
            movi(2, (addr >> 10) & 0x7ff), # mov a2, addr[20:10]
            slli(2, 2, 10), # slli a2, a2, 10
            orr(6, 6, 2), # or a6, a6, a2
            movi(2, (addr >> 0) & 0x3ff), # mov a2, addr[9:0]
            orr(6, 6, 2), # or a6, a6, a2

            movi(2, (size >> 21) & 0x7ff), # mov a2, size[31:21]
            slli(3, 2, 21), # slli a3, a2, 21
            movi(2, (size >> 10) & 0x7ff), # mov a2, size[20:10]
            slli(2, 2, 10), # slli a2, a2, 10
            orr(3, 3, 2), # or a3, a3, a2
            movi(2, (size >> 0) & 0x3ff), # mov a2, size[9:0]
            orr(3, 3, 2), # or a3, a3, a2

            movi(2, (perm >> 21) & 0x7ff), # mov a2, perm[31:21]
            slli(4, 2, 21), # slli a4, a2, 21
            movi(2, (perm >> 10) & 0x7ff), # mov a2, perm[20:10]
            slli(2, 2, 10), # slli a2, a2, 10
            orr(4, 4, 2), # or a4, a4, a2
            movi(2, (perm >> 0) & 0x3ff), # mov a2, perm[9:0]
            orr(4, 4, 2), # or a4, a4, a2

            movi(2, _NR_mprotect), # mov a2, _NR_mprotect

            b"\x00\x50\x00", # syscall
        ]
        return b"".join(insns)


class CRIS(Architecture):
    arch = "CRIS"
    mode = "CRIS"

    load_condition = [
        Elf.EM_CRIS,
        "CRIS",
    ]

    # https://www.axis.com/dam/public/25/67/ab/etrax-100lx-programmer%E2%80%99s-manual-en-US-33419.pdf
    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$sp", "$pc",
        "$srp", "$ccr",
    ]
    alias_registers = {
        "$sp": "$r14", "$pc": "$r15",
    }
    flag_register = "$ccr"
    flags_table = {
        9: "write-fail",
        3: "negative",
        2: "zero",
        1: "overflow",
        0: "carry",
    }
    return_register = "$r10"
    function_parameters = ["$r10", "$r11", "$r12", "$r13"]
    # As of linux 4.17, cris is no longer supported.
    syscall_register = "$r9"
    syscall_parameters = ["$r10", "$r11", "$r12", "$r13", "$dcr1/mof", "$sp+0x4"]

    bit_length = 32
    endianness = "little"
    instruction_length = None # variable length
    has_delay_slot = True
    has_syscall_delay_slot = True
    has_ret_delay_slot = True
    stack_grow_down = False
    tls_supported = False

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\x0f\x05" # nop
    infloop_insn = b"\xff\xe0" # ba self
    trap_insn = None
    ret_insn = b"\x7f\xb6" # ret
    syscall_insn = b"\x3d\xe9" # break 13

    def is_syscall(self, insn):
        return insn.mnemonic == "break" and insn.operands[0] == "13"

    def is_call(self, insn):
        return insn.mnemonic in ["jsr", "jsrc"]

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        return insn.mnemonic in ["ba", "jmpu", "jump"]

    def is_ret(self, insn):
        return insn.mnemonic == "ret"

    def is_conditional_branch(self, insn):
        conditions = [
            "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi",
            "ls", "hi", "ge", "lt", "gt", "le", "wf"
        ]
        for cc in conditions:
            if insn.mnemonic in [f"b{cc}"]:
                return True
        return False

    def is_branch_taken(self, insn):
        mnemo = insn.mnemonic
        val = get_register(self.flag_register)
        flags = {self.flags_table[k]: k for k in self.flags_table}
        taken, reason = False, ""

        zero = bool(val & (1 << flags["zero"]))
        negative = bool(val & (1 << flags["negative"]))
        overflow = bool(val & (1 << flags["overflow"]))
        carry = bool(val & (1 << flags["carry"]))
        write_fail = bool(val & (1 << flags["write-fail"]))

        if mnemo == "bcc":
            taken, reason = not carry, "!C"
        elif mnemo == "bcs":
            taken, reason = carry, "C"
        elif mnemo == "bne":
            taken, reason = not zero, "!Z"
        elif mnemo == "beq":
            taken, reason = zero, "Z"
        elif mnemo == "bvc":
            taken, reason = not overflow, "!V"
        elif mnemo == "bvs":
            taken, reason = overflow, "V"
        elif mnemo == "bpl":
            taken, reason = not negative, "!N"
        elif mnemo == "bmi":
            taken, reason = negative, "N"
        elif mnemo == "bls":
            taken, reason = carry or zero, "C || Z"
        elif mnemo == "bhi":
            taken, reason = not carry and not zero, "!C && !Z"
        elif mnemo == "bge":
            taken, reason = (negative and overflow) or (not negative and not overflow), "(N && V) || (!N && !V)"
        elif mnemo == "blt":
            taken, reason = (negative and not overflow) or (not negative and overflow), "(N && !V) || (!N && V)"
        elif mnemo == "bgt":
            taken = (negative and overflow and not zero) or (not negative and not overflow and not zero)
            reason = "(N && V && !Z) || (!N && !V && !Z)"
        elif mnemo == "ble":
            taken, reason = zero or (negative and not overflow) or (not negative and overflow), "Z || (N && !V) || (!N && V)"
        elif mnemo == "bwf":
            taken, reason = write_fail, "WF"
        return taken, reason

    def flag_register_to_human(self, val=None):
        if not val:
            reg = self.flag_register
            val = get_register(reg)
        return Architecture.flags_to_human(val, self.flags_table)

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$srp")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def mprotect_asm(self, addr, size, perm):
        _NR_mprotect = 125
        insns = [
            b"\x6f\xae" + p32(addr), # move.d addr, $r10
            b"\x6f\xbe" + p32(size), # move.d size, $r11
            b"\x6f\xce" + p32(perm), # move.d perm, $r12
            b"\x6f\x9e" + p32(_NR_mprotect), # move.d _NR_mprotect, $r9
            b"\x3d\xe9", # syscall
            b"\x0f\x05", # nop
        ]
        return b"".join(insns)


class LOONGARCH64(Architecture):
    arch = "LOONGARCH"
    mode = "64"

    load_condition = [
        # Elf.EM_LOONGARCH cannot determine whether it is 32 bit or 64 bit,
        # but since GEF only supports 64 bit (LA64), so we will use it.
        Elf.EM_LOONGARCH,
        "LOONGARCH",
        "LOONGARCH64",
    ]

    # https://docs.kernel.org/loongarch/introduction.html
    # https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html
    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23",
        "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31",
        "$orig_a0", "$pc", "$badv",
    ]
    alias_registers = {
        "$r0": "$zero", "$r1": "$ra", "$r2": "$tp", "$r3": "$sp",
        "$r4": "$a0/$v0", "$r5": "$a1/$v1", "$r6": "$a2", "$r7": "$a3",
        "$r8": "$a4", "$r9": "$a5", "$r10": "$a6", "$r11": "$a7",
        "$r12": "$t0", "$r13": "$t1", "$r14": "$t2", "$r15": "$t3",
        "$r16": "$t4", "$r17": "$t5", "$r18": "$t6", "$r19": "$t7", "$r20": "$t8",
        "$r21": "$u0", "$r22": "$fp",
        "$r23": "$s0", "$r24": "$s1", "$r25": "$s2", "$r26": "$s3",
        "$r27": "$s4", "$r28": "$s5", "$r29": "$s6", "$r30": "$s7", "$r31": "$s8",
    }
    flag_register = None # LOONGARCH has no flags register
    return_register = "$r4"
    function_parameters = ["$r4", "$r5", "$r6", "$r7", "$r8", "$r9", "$r10", "$r11"]
    syscall_register = "$r11"
    syscall_parameters = ["$r4", "$r5", "$r6", "$r7", "$r8", "$r9"]

    bit_length = 64
    endianness = "little"
    instruction_length = 4
    has_delay_slot = False
    has_syscall_delay_slot = False
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\x00\x00\x40\x03" # andi $zero, $zero, 0x0
    infloop_insn = b"\x00\x00\x00\x50" # b self
    trap_insn = None
    ret_insn = b"\x20\x00\x00\x4c" # jirl
    syscall_insn = b"\x00\x00\x2b\x00" # syscall

    def is_syscall(self, insn):
        return insn.mnemonic in ["syscall"]

    def is_call(self, insn):
        return insn.mnemonic in ["bl"]

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        return insn.mnemonic in ["b"]

    def is_ret(self, insn):
        return insn.mnemonic in ["jirl"]

    def is_conditional_branch(self, insn):
        return insn.mnemonic in ["beq", "bne", "bge", "bgeu", "blt", "bltu", "beqz", "bnez"]

    def is_branch_taken(self, insn):
        mnemo, ops = insn.mnemonic, insn.operands
        alias_inverse = {}
        for k, v in self.alias_registers.items():
            for alias_reg in v.split("/"):
                alias_inverse[alias_reg] = k

        pQ = lambda a: struct.pack("<Q", a & 0xffffffffffffffff)
        uq = lambda a: struct.unpack("<q", a)[0]
        u2i = lambda a: uq(pQ(a))

        v0 = get_register(alias_inverse.get(ops[0], ops[0]))
        v0s = u2i(v0)

        if mnemo not in ["beqz", "bnez"]:
            v1 = get_register(alias_inverse.get(ops[1], ops[1]))
            v1s = u2i(v1)

        taken, reason = False, ""
        if mnemo == "beq":
            taken, reason = v0 == v1, "{:s}=={:s}".format(ops[0], ops[1])
        elif mnemo == "bne":
            taken, reason = v0 != v1, "{:s}!={:s}".format(ops[0], ops[1])
        elif mnemo == "bge":
            taken, reason = v0s >= v1s, "{:s}>={:s} (signed)".format(ops[0], ops[1])
        elif mnemo == "bgeu":
            taken, reason = v0 >= v1, "{:s}>={:s} (unsigned)".format(ops[0], ops[1])
        elif mnemo == "blt":
            taken, reason = v0s < v1s, "{:s}<{:s} (signed)".format(ops[0], ops[1])
        elif mnemo == "bltu":
            taken, reason = v0 < v1, "{:s}<{:s} (unsigned)".format(ops[0], ops[1])
        elif mnemo == "beqz":
            taken, reason = v0 == 0, "{:s}==0".format(ops[0])
        elif mnemo == "bnez":
            taken, reason = v0 != 0, "{:s}!=0".format(ops[0])
        return taken, reason

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$r1")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        return get_register("$r2")

    def decode_cookie(self, value, cookie):
        return value ^ cookie

    def encode_cookie(self, value, cookie):
        return value ^ cookie

    def mprotect_asm(self, addr, size, perm):
        def lu12iw(reg, si20):
            b = "0b_0001010_{:020b}_{:05b}".format(si20, reg)
            return p32(int(b, 2))

        def ori(dstreg, srcreg, ui12):
            b = "0b_0000001110_{:012b}_{:05b}_{:05b}".format(ui12, srcreg, dstreg)
            return p32(int(b, 2))

        def lu32id(reg, si20):
            b = "0b_0001011_{:020b}_{:05b}".format(si20, reg)
            return p32(int(b, 2))

        def lu52id(dstreg, srcreg, ui12):
            b = "0b_0000001100_{:012b}_{:05b}_{:05b}".format(ui12, srcreg, dstreg)
            return p32(int(b, 2))

        def move(dstreg, srcreg):
            b = "0b_0000000000010101000000_{:05b}_{:05b}".format(srcreg, dstreg)
            return p32(int(b, 2))

        _NR_mprotect = 226
        insns = [
            lu12iw(12, (addr >> 12) & 0xfffff), # lu12i.w $t0, addr[12:32]
            ori(12, 12, addr & 0xfff), # ori $a0, $t0, addr[0:12]
            lu32id(12, (addr >> 32) & 0xfffff), # lu32i.d $t0, addr[32:52]
            lu52id(12, 12, (addr >> 52) & 0xfff), # lu52i.d $t0, addr[52:64]
            move(4, 12), # move $r4, $t0

            lu12iw(12, (size >> 12) & 0xfffff), # lu12i.w $t0, size[12:32]
            ori(12, 12, size & 0xfff), # ori $a0, $t0, size[0:12]
            lu32id(12, (size >> 32) & 0xfffff), # lu32i.d $t0, size[32:52]
            lu52id(12, 12, (size >> 52) & 0xfff), # lu52i.d $t0, size[52:64]
            move(5, 12), # move $r5, $t0

            lu12iw(12, (perm >> 12) & 0xfffff), # lu12i.w $t0, perm[12:32]
            ori(12, 12, perm & 0xfff), # ori $a0, $t0, perm[0:12]
            lu32id(12, (perm >> 32) & 0xfffff), # lu32i.d $t0, perm[32:52]
            lu52id(12, 12, (perm >> 52) & 0xfff), # lu52i.d $t0, perm[52:64]
            move(6, 12), # move $r6, $t0

            lu12iw(12, (_NR_mprotect >> 12) & 0xfffff), # lu12i.w $t0, _NR_mprotect[12:32]
            ori(12, 12, _NR_mprotect & 0xfff), # ori $a0, $t0, _NR_mprotect[0:12]
            lu32id(12, (_NR_mprotect >> 32) & 0xfffff), # lu32i.d $t0, _NR_mprotect[32:52]
            lu52id(12, 12, (_NR_mprotect >> 52) & 0xfff), # lu52i.d $t0, _NR_mprotect[52:64]
            move(11, 12), # move $r11, $t0

            b"\x00\x00\x2b\x00", # syscall
        ]
        return b"".join(insns)


class ARC(Architecture):
    arch = "ARC"
    mode = "32v2"

    load_condition = [
        Elf.EM_ARC,
        Elf.EM_ARC_COMPACT,
        Elf.EM_ARCV2,
        "ARC600",
        "ARC601",
        "ARC700",
        "ARCV2",
    ]

    # http://me.bios.io/images/d/dd/ARCompactISA_ProgrammersReference.pdf
    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23",
        "$r24", "$r25", "$gp", "$fp", "$sp", "$ilink", "$r30", "$blink",
        "$pc", "$status32", "$bta", "$lp_count",
    ]
    alias_registers = {
        "$r25": "$tp", "$gp": "$r26", "$fp": "$r27", "$sp": "$r28", "$ilink": "$r29", "$blink": "$r31",
        "$lp_count": "$r60", "$pc": "$pcl/$r63",
    }

    flag_register = "$status32"
    flags_table = {
        0: "halt",
        1: "e1",
        2: "e2",
        3: "a1",
        4: "a2",
        5: "ae",
        6: "de",
        7: "user",
        8: "overflow",
        9: "carry",
        10: "negative",
        11: "zero",
        12: "loop",
    }
    return_register = "$r0"
    function_parameters = ["$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7"]
    syscall_register = "$r8"
    syscall_parameters = ["$r0", "$r1", "$r2", "$r3", "$r4", "$r5"]

    bit_length = 32
    endianness = "little"
    instruction_length = None # variable length
    has_delay_slot = True # if op includes `.d`
    has_syscall_delay_slot = False
    has_ret_delay_slot = True # if op includes `.d`
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\xe0\x78" # nop_s
    infloop_insn = b"\x00\xf0" # b_s 0
    infloop_insn2 = b"\x01\xf0" # b_s 2 (if $pc % 4 == 2)
    trap_insn = None
    ret_insn = b"\xe0\x7e" # j_s [blink]
    syscall_insn = b"\x1e\x78" # trap_s 0

    def is_syscall(self, insn):
        if insn.mnemonic == "trap_s" and insn.operands == ["0"]:
            return True
        if insn.mnemonic == "trap0":
            return True
        return False

    def is_call(self, insn):
        if insn.mnemonic in ["bl", "bl.d", "bl_s", "jl", "jl.d", "jl_s", "jl_s.d"]:
            return True

        # BLcc<.d>
        conditions = [
            "al", "ra", "eq", "z", "ne", "nz", "pl", "p",
            "mi", "n", "cs", "c", "lo", "cc", "nc", "hs",
            "vs", "v", "vc", "nv", "gt", "ge", "lt", "le",
            "hi", "ls", "pnz",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"bl{cc}", f"bl{cc}.d"]:
                return True

        # JLcc<.d>
        conditions = [
            "eq", "ne", "lt", "ge", "lo", "hs",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"jl{cc}", f"jl{cc}.d"]:
                return True

        return False

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        if insn.mnemonic in ["b", "b.d", "b_s"]:
            return True
        if insn.mnemonic in ["j", "j.d"]:
            if insn.operands != ["[blink]"]:
                return True
        return False

    def is_ret(self, insn):
        if insn.mnemonic in ["j", "j_s", "j_s.d"] and insn.operands == ["[blink]"]:
            return True
        return False

    def is_conditional_branch(self, insn):
        # Bcc<.d>
        conditions = [
            "al", "ra", "eq", "z", "ne", "nz", "pl", "p",
            "mi", "n", "cs", "c", "lo", "cc", "nc", "hs",
            "vs", "v", "vc", "nv", "gt", "ge", "lt", "le",
            "hi", "ls", "pnz",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"b{cc}", f"b{cc}.d"]:
                return True

        # BRcc<.d>
        conditions = [
            "eq", "ne", "lt", "ge", "lo", "hs",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"br{cc}", f"br{cc}.d", f"br{cc}.nt", f"br{cc}.d.nt"]:
                return True
        if insn.mnemonic in ["bbit0", "bbit1", "bbit0.d", "bbit1.d"]:
            return True

        # BRcc_s
        conditions = [
            "eq", "ne", "gt", "ge", "lt", "le", "hi", "hs", "lo", "ls",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"br{cc}_s"]:
                return True

        # Jcc<.d>, Jcc.F
        conditions = [
            "eq", "ne", "lt", "ge", "lo", "hs",
        ]
        for cc in conditions:
            if insn.mnemonic in [f"j{cc}", f"j{cc}.d", f"j{cc}.f"]:
                return True

        # Jcc_s
        if insn.mnemonic in ["jeq_s", "jne_s"]:
            return True

        return False

    def is_branch_taken(self, insn):
        mnemo = insn.mnemonic
        ops = []
        for op in insn.operands:
            if op.startswith(";"):
                break
            ops.append(op)

        val = get_register(self.flag_register)
        flags = {self.flags_table[k]: k for k in self.flags_table}

        zero = bool(val & (1 << flags["zero"]))
        negative = bool(val & (1 << flags["negative"]))
        overflow = bool(val & (1 << flags["overflow"]))
        carry = bool(val & (1 << flags["carry"]))

        if len(ops) >= 2:
            pI = lambda a: struct.pack("<I", a & 0xffffffff)
            ui = lambda a: struct.unpack("<i", a)[0]
            u2i = lambda a: ui(pI(a))
            v0u = get_register(ops[0])
            if v0u is None:
                v0u = int(ops[0], 0)
            v1u = get_register(ops[1])
            if v1u is None:
                v1u = int(ops[1], 0)
            v0s = u2i(v0u)
            v1s = u2i(v1u)

        taken, reason = False, ""
        if mnemo.startswith(("beq", "breq", "jeq")):
            if len(ops) >= 2:
                taken, reason = v0u == v1u, "{:s}=={:s}".format(ops[0], ops[1])
            else:
                taken, reason = zero, "Z"

        elif mnemo.startswith(("bne", "brne", "jne")):
            if len(ops) >= 2:
                taken, reason = v0u != v1u, "{:s}!={:s}".format(ops[0], ops[1])
            else:
                taken, reason = not zero, "!Z"

        elif mnemo.startswith(("bgt", "brgt")):
            if len(ops) >= 2:
                taken, reason = v0s > v1s, "{:s}>{:s}".format(ops[0], ops[1])
            else:
                taken = (negative and overflow and not zero) or (not negative and not overflow and not zero)
                reason = "(N && V && !Z) || (!N && !V && !Z)"

        elif mnemo.startswith(("bge", "brge", "jge")):
            if len(ops) >= 2:
                taken, reason = v0s >= v1s, "{:s}>={:s}".format(ops[0], ops[1])
            else:
                taken, reason = (negative and overflow) or (not negative and not overflow), "(N && V) || (!N && !V)"

        elif mnemo.startswith(("blt", "brlt", "jlt")):
            if len(ops) >= 2:
                taken, reason = v0s < v1s, "{:s}<{:s}".format(ops[0], ops[1])
            else:
                taken, reason = (negative and not overflow) or (not negative and overflow), "(N && !V) || (!N && V)"

        elif mnemo.startswith(("ble", "brle")):
            if len(ops) >= 2:
                taken, reason = v0s <= v1s, "{:s}<={:s}".format(ops[0], ops[1])
            else:
                taken, reason = zero or (negative and not overflow) or (not negative and overflow), "Z || (N && !V) || (!N && V)"

        elif mnemo.startswith(("bhi", "brhi")):
            if len(ops) >= 2:
                taken, reason = v0u > v1u, "{:s}>{:s}".format(ops[0], ops[1])
            else:
                taken, reason = not carry and not zero, "!C || !Z"

        elif mnemo.startswith(("bhs", "brhs", "jhs")):
            if len(ops) >= 2:
                taken, reason = v0u >= v1u, "{:s}>={:s}".format(ops[0], ops[1])
            else:
                taken, reason = not carry, "!C"

        elif mnemo.startswith(("blo", "brlo", "jlo")):
            if len(ops) >= 2:
                taken, reason = v0u < v1u, "{:s}<{:s}".format(ops[0], ops[1])
            else:
                taken, reason = carry, "C"

        elif mnemo.startswith(("bls", "brls")):
            if len(ops) >= 2:
                taken, reason = v0u <= v1u, "{:s}<={:s}".format(ops[0], ops[1])
            else:
                taken, reason = carry or zero, "C || Z"

        return taken, reason

    def flag_register_to_human(self, val=None):
        if not val:
            reg = self.flag_register
            val = get_register(reg)
        return Architecture.flags_to_human(val, self.flags_table)

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$blink")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        return get_register("$r25")

    def decode_cookie(self, value, cookie):
        return value

    def encode_cookie(self, value, cookie):
        return value

    def mprotect_asm(self, addr, size, perm):
        insns = [
            b"\x0a\x20\x80\x0f" + p16(addr >> 16) + p16(addr & 0xffff), # mov r0, addr
            b"\x0a\x21\x80\x0f" + p16(size >> 16) + p16(size & 0xffff), # mov r1, size
            b"\x0a\x22\x80\x0f" + p16(perm >> 16) + p16(perm & 0xffff), # mov r2, perm
            b"\x8a\x20\x83\x18" # mov r8, _NR_mprotect (=226)
            b"\x1e\x78" # trap_s 0
        ]
        return b"".join(insns)


class ARCv3(ARC):
    arch = "ARC"
    mode = "32v3"

    load_condition = [
        Elf.EM_ARC_COMPACT3,
        "ARC64:32",
    ]

    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23",
        "$r24", "$r25", "$r26", "$fp", "$sp", "$ilink", "$gp", "$blink",
        "$pc", "$status32", "$bta", "$eret",
    ]
    alias_registers = {
        "$fp": "$r27", "$sp": "$r28", "$ilink": "$r29", "$gp": "$r30", "$blink": "$r31",
        "$pc": "$pcl/$r63",
    }

    def get_tls(self):
        return get_register("$gp")


class ARC64(ARCv3):
    arch = "ARC"
    mode = "64v3"

    load_condition = [
        Elf.EM_ARC_COMPACT3_64,
        "ARC64:64",
    ]

    bit_length = 64

    def mprotect_asm(self, addr, size, perm):
        insns = [
            b"\x08\x70" + p16((addr >> 48) & 0xffff) + p16((addr >> 32) & 0xffff), # movhl_s r0, addr[63:32]
            b"\x00\x58\x80\x0f" + p16((addr >> 16) & 0xffff) + p16(addr & 0xffff), # addl r0, r0, addr[31:0]
            b"\x28\x70" + p16((size >> 48) & 0xffff) + p16((size >> 32) & 0xffff), # movhl_s r1, size[63:32]
            b"\x00\x59\x81\x0f" + p16((size >> 16) & 0xffff) + p16(size & 0xffff), # addl r1, r1, size[31:0]
            b"\x48\x70" + p16((perm >> 48) >> 16) + p16((perm >> 32) & 0xffff), # movhl_s r2, perm[63:32]
            b"\x00\x5a\x82\x0f" + p16((perm >> 16) & 0xffff) + p16(perm & 0xffff), # addl r2, r2, perm[31:0]
            b"\x8a\x20\x83\x18" # mov r8, _NR_mprotect (=226)
            b"\x1e\x78" # trap_s 0
        ]
        return b"".join(insns)


class CSKY(Architecture):
    arch = "CSKY"
    mode = "CSKY"

    load_condition = [
        Elf.EM_CSKY,
        "CSKY",
        "CSKY:CK510",
        "CSKY:CK610",
        "CSKY:CK801",
        "CSKY:CK802",
        "CSKY:CK803",
        "CSKY:CK807",
        "CSKY:CK810",
        "CSKY:CK860",
        "CSKY:ANY",
    ]

    # https://github.com/c-sky/csky-doc/blob/master/CSKY%20Architecture%20user_guide.pdf
    all_registers = [
        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
        "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23",
        "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31",
        "$pc", "$psr", "$hi", "$lo",
    ]
    alias_registers = {
        "$r14": "$sp", "$r15": "$lr", "$r28": "$ds", "$r30": "$vec",
        "$r31": "$tp",
    }
    flag_register = "$psr"
    flags_table = {
        0: "carry",
    }
    return_register = "$r0"
    function_parameters = ["$r0", "$r1", "$r2", "$r3"]
    syscall_register = "$r7"
    syscall_parameters = ["$r0", "$r1", "$r2", "$r3", "$r4", "$r5"]

    bit_length = 32
    endianness = "little"
    instruction_length = None # variable length
    has_delay_slot = False
    has_syscall_delay_slot = False
    has_ret_delay_slot = False
    stack_grow_down = False
    tls_supported = True

    keystone_support = False
    capstone_support = False
    unicorn_support = False

    nop_insn = b"\x03\x6c" # mov r0, r0
    infloop_insn = b"\x00\x04" # br self
    trap_insn = b"\x00\x00" # bkpt
    ret_insn = b"\x3c\x78" # rts
    syscall_insn = b"\x00\xc0\x20\x20" # trap 0

    def is_syscall(self, insn):
        return insn.mnemonic == "trap" and insn.operands[0] == "0"

    def is_call(self, insn):
        return insn.mnemonic in ["bsr", "jsri", "jsr"]

    def is_jump(self, insn):
        if self.is_conditional_branch(insn):
            return True
        return insn.mnemonic in ["br", "jmpi", "jmp", "jmpix"]

    def is_ret(self, insn):
        return insn.mnemonic in ["rts"]

    def is_conditional_branch(self, insn):
        return insn.mnemonic in ["bt", "bf", "bez", "bnez", "bhz", "blsz", "blz", "bhsz"]

    def is_branch_taken(self, insn):
        mnemo, ops = insn.mnemonic, insn.operands
        val = get_register(self.flag_register)
        flags = {self.flags_table[k]: k for k in self.flags_table}
        taken, reason = False, ""

        carry = bool(val & (1 << flags["carry"]))

        pI = lambda a: struct.pack("<I", a & 0xffffffff)
        ui = lambda a: struct.unpack("<i", a)[0]
        u2i = lambda a: ui(pI(a))

        if mnemo == "bt":
            taken, reason = carry, "C"
        elif mnemo == "bf":
            taken, reason = not carry, "!C"
        elif mnemo == "bez":
            v0 = get_register(ops[0])
            taken, reason = v0 == 0, "{:s}==0".format(ops[0])
        elif mnemo == "bnez":
            v0 = get_register(ops[0])
            taken, reason = v0 != 0, "{:s}==0".format(ops[0])
        elif mnemo == "bhz":
            v0s = u2i(get_register(ops[0]))
            taken, reason = v0s > 0, "{:s}>0".format(ops[0])
        elif mnemo == "blsz":
            v0s = u2i(get_register(ops[0]))
            taken, reason = v0s <= 0, "{:s}<=0".format(ops[0])
        elif mnemo == "blz":
            v0s = u2i(get_register(ops[0]))
            taken, reason = v0s < 0, "{:s}<0".format(ops[0])
        elif mnemo == "bhsz":
            v0s = u2i(get_register(ops[0]))
            taken, reason = v0s >= 0, "{:s}>=0".format(ops[0])
        return taken, reason

    def flag_register_to_human(self, val=None):
        if not val:
            reg = self.flag_register
            val = get_register(reg)
        return Architecture.flags_to_human(val, self.flags_table)

    def get_ra(self, insn, frame):
        ra = None
        try:
            if self.is_ret(insn):
                ra = get_register("$r15")
            elif frame.older():
                ra = frame.older().pc()
        except gdb.error:
            pass
        return ra

    def get_tls(self):
        return get_register("$r31")

    def decode_cookie(self, value, cookie):
        return value ^ cookie

    def encode_cookie(self, value, cookie):
        return value ^ cookie

    def mprotect_asm(self, addr, size, perm):
        def movi(dstreg, imm):
            x = "1_11010_10000_{:05b}_{:016b}".format(dstreg, imm)
            x = int(x, 2)
            return p16((x >> 16) & 0xffff) + p16(x & 0xffff)

        def lsli(dstreg, srcreg, bit):
            x = "0_1000_{:03b}_{:03b}_{:05b}".format(dstreg, srcreg, bit)
            return p16(int(x, 2))

        def ori(dstreg, srcreg, imm):
            x = "1_11011_{:05b}_{:05b}_{:016b}".format(dstreg, srcreg, imm)
            x = int(x, 2)
            return p16((x >> 16) & 0xffff) + p16(x & 0xffff)

        insns = [
            movi(0, (addr >> 16) & 0xffff), # mov r0, addr[31:16]
            lsli(0, 0, 16), # lsli r0, r0, 16
            ori(0, 0, (addr & 0xffff)), # ori r0, r0, addr[15:0]

            movi(1, (size >> 16) & 0xffff), # mov r1, size[31:16]
            lsli(1, 1, 16), # lsli r1, r1, 16
            ori(1, 1, (size & 0xffff)), # ori r1, r1, size[15:0]

            movi(2, (perm >> 16) & 0xffff), # mov r2, perm[31:16]
            lsli(2, 2, 16), # lsli r2, r2, 16
            ori(2, 2, (perm & 0xffff)), # ori r2, r2, perm[15:0]

            movi(7, 226), # movi, r7, _NR_mprotect (=226)
            b"\x00\xc0\x20\x20", # trap 0
        ]
        return b"".join(insns)


# The prototype for new architecture.
#
#class XXX(Architecture):
#    arch = "XXX"
#    mode = "XXX"
#
#    load_condition = [
#        Elf.EM_XXX,
#        "XXX",
#    ]
#
#    all_registers = [
#        "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
#        "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
#        "$pc", "$sr",
#    ]
#    alias_registers = {
#        "$r15": "$sp",
#    }
#    #flag_register = "$flags"
#    #flags_table = {
#    #    0: "negative",
#    #    1: "zero",
#    #}
#    #return_register = "$r0"
#    #function_parameters = ["$r1", "$r2", "$r3", "$r4", "$r5", "$r6"]
#    #syscall_register = "$r0"
#    #syscall_parameters = ["$r1", "$r2", "$r3", "$r4", "$r5", "$r6"]
#
#    bit_length = 32
#    endianness = "little"
#    #instruction_length = 4
#    #has_delay_slot = False
#    #has_syscall_delay_slot = False
#    #has_ret_delay_slot = False
#    #stack_grow_down = False
#    #tls_supported = False
#
#    #keystone_support = False
#    #capstone_support = False
#    #unicorn_support = False
#
#    #nop_insn = b"\x00\x00" # nop
#    #infloop_insn = b"\x11\x11" # bra self
#    #trap_insn = None
#    #ret_insn = b"\x22\x22" # ret
#    #syscall_insn = b"\x33\x33" # ecall
#
#    #def is_syscall(self, insn):
#    #    return insn.mnemonic in []
#
#    #def is_call(self, insn):
#    #    return insn.mnemonic in []
#
#    #def is_jump(self, insn):
#    #    if self.is_conditional_branch(insn):
#    #        return True
#    #    return insn.mnemonic in []
#
#    #def is_ret(self, insn):
#    #    return insn.mnemonic in []
#
#    #def is_conditional_branch(self, insn):
#    #    return insn.mnemonic in []
#
#    #def is_branch_taken(self, insn):
#    #    mnemo = insn.mnemonic
#    #    val = get_register(self.flag_register)
#    #    flags = {self.flags_table[k]: k for k in self.flags_table}
#    #    taken, reason = False, ""
#    #    return taken, reason
#
#    #def flag_register_to_human(self, val=None):
#    #    if not val:
#    #        reg = self.flag_register
#    #        val = get_register(reg)
#    #    return Architecture.flags_to_human(val, self.flags_table)
#
#    #def get_ith_parameter(self, i, in_func=True):
#    #    if in_func:
#    #        i += 1 # Account for RA being at the top of the stack
#    #    sp = current_arch.sp
#    #    sz = current_arch.ptrsize
#    #    loc = sp + (i * sz)
#    #    val = read_int_from_memory(loc)
#    #    key = "[sp + {:#x}]".format(i * sz)
#    #    return key, val
#
#    #def get_ra(self, insn, frame):
#    #    ra = None
#    #    try:
#    #        if self.is_ret(insn):
#    #            ra = get_register("$sr")
#    #        elif frame.older():
#    #            ra = frame.older().pc()
#    #    except gdb.error:
#    #        pass
#    #    return ra
#
#    #def get_tls(self):
#    #    return None
#
#    #def decode_cookie(self, value, cookie):
#    #    return value ^ cookie
#
#    #def encode_cookie(self, value, cookie):
#    #    return value ^ cookie
#
#    #def mprotect_asm(self, addr, size, perm):
#    #    insns = [
#    #        b"\x00\x00", # nop
#    #    ]
#    #    return b"".join(insns)


def write_memory(addr, data):
    """Write `data` at address `addr`."""

    def write_memory_qemu_user(pid, addr, data, length):
        """Write `data` at address `addr` for qemu-user or Intel Pin."""

        def read_memory_via_proc_mem(pid, addr, length):
            with open("/proc/{:d}/mem".format(pid), "rb") as fd:
                try:
                    fd.seek(addr)
                    return fd.read(length)
                except OSError:
                    return None

        def write_memory_via_proc_mem(pid, addr, data, length):
            with open("/proc/{:d}/mem".format(pid), "wb") as fd:
                try:
                    fd.seek(addr)
                    ret = fd.write(data[:length])
                    fd.flush()
                    gdb.execute("maintenance flush dcache", to_string=True)
                    return ret
                except (OSError, gdb.error):
                    return None

        def write_with_check(pid, addr, data, length, offset=0):
            before = read_memory_via_proc_mem(pid, addr + offset, length)
            if before is None:
                return None

            ret = write_memory_via_proc_mem(pid, addr + offset, data, length)
            after = read_memory(addr, length)

            if ret:
                if after == data[:length]:
                    return ret
                else:
                    # fail, revert
                    write_memory_via_proc_mem(pid, addr + offset, before, length)
                    return None
            return None

        # qemu-user (32bit) maps the memory at +0x10000 (fast path)
        if is_qemu_user() and is_32bit():
            ret = write_with_check(pid, addr, data, length, offset=0x10000)
            if ret:
                return ret

        # we assume addr is same
        ret = write_with_check(pid, addr, data, length)
        if ret:
            return ret

        # heuristic addr search and try use it
        if is_qemu_user():
            inner_section = ProcessMap.lookup_address(addr).section
            target_path = inner_section.path

            outer_maps = ProcessMap.get_process_maps(outer=True)
            for m in outer_maps:
                if m.path != target_path:
                    continue
                offset = m.page_start - inner_section.page_start
                ret = write_with_check(pid, addr, data, length, offset=offset)
                if ret:
                    return ret

        raise Exception("Write memory error for qemu-user or Intel Pin")

    # ----

    length = len(data)
    if length == 0:
        return 0

    try:
        gdb.selected_inferior().write_memory(addr, data, length)
        return length
    except gdb.MemoryError:
        pass

    # Under qemu-user/pin, you can not patch to `code` areas,
    # so you have to patch via /proc/pid/mem
    if is_qemu_user() or is_pin():
        pid = Pid.get_pid()
        if pid:
            return write_memory_qemu_user(pid, addr, data, length)

    raise Exception("Write memory error")


def read_memory(addr, length):
    """Return a `length` long byte array with the copy of the process memory at `addr`."""
    if length == 0:
        return b""

    if is_pin():
        # Memory read of Intel Pin is very slow, so speed it up
        try:
            pid = Pid.get_pid()
            fd = open("/proc/{:d}/mem".format(pid), "rb")
            fd.seek(addr)
            content = fd.read(length)
            fd.close()
            return content
        except Exception:
            pass

    # Don't include it in a try-catch, as we might expect a memory error on read_memory.
    return gdb.selected_inferior().read_memory(addr, length).tobytes()


def read_int_from_memory(addr):
    """Return an integer read from memory."""
    sz = current_arch.ptrsize
    mem = read_memory(addr, sz)
    unpack = {2:u16, 4:u32, 8:u64}[sz]
    return unpack(mem)


def read_cstring_from_memory(addr, max_length=None):
    """Return a C-string read from memory."""
    # original GEF uses gdb.Value().cast("char"), but this is too slow if string is too large.
    # for example 0xcccccccccccccccc....(too long), this is in kernel or firmware commonly.
    # to avoid this, gdb.Value().cast() is removed.

    if max_length is None:
        max_length = Config.get_gef_setting("context.nb_max_string_length")

    if is_kgdb():
        # read_memory when kgdb is very slow, this is dirty hack
        block_size = 1
    else:
        block_size = gef_getpagesize()

    # first, read to page boundary
    length = block_size - (addr % block_size)
    try:
        res = read_memory(addr, length)
    except gdb.MemoryError:
        return None

    # if too short, more read
    while len(res) < max_length:
        if b"\x00" in res:
            break
        try:
            read_length = min(max_length - len(res), block_size)
            res += read_memory(addr + len(res), read_length)
        except gdb.MemoryError:
            break

    # check if ascii
    res = res.split(b"\x00")[0]
    ustr = String.bytes2str(res)

    if ustr and any(x not in String.STRING_PRINTABLE for x in ustr):
        return None

    if len(ustr) > max_length:
        ustr = "{}[...]".format(ustr[:max_length])

    return ustr


def read_physmem(paddr, size):
    """Return a `size` long byte array with the copy of the physical memory at `paddr`."""

    def transparent_read(paddr, size):
        # switch virt/phys mode
        orig_mode = QemuMonitor.get_current_mmu_mode()
        try:
            if orig_mode == "virt":
                enable_phys()
            out = read_memory(paddr, size)
            if orig_mode == "virt":
                disable_phys()
            return out
        except gdb.MemoryError:
            if orig_mode == "virt":
                disable_phys()
        return None

    def qemu_system_strict_way(paddr, size):
        qemu_system_pid = Pid.get_pid()
        if qemu_system_pid is None:
            return None
        res = gdb.execute("monitor gpa2hva {:#x}".format(paddr), to_string=True)
        r = re.search("is (0x[0-9a-f]+)", res)
        if not r:
            return None
        virt_addr = int(r.group(1), 16)
        with open("/proc/{:d}/mem".format(qemu_system_pid), "rb") as fd:
            fd.seek(virt_addr)
            try:
                return fd.read(size)
            except Exception:
                pass
        return None

    def qemu_system_use_xp(paddr, size):
        # for older than qemu 4.1.0-rc0
        try:
            res = gdb.execute("monitor xp/{:d}xb {:#x}".format(size, paddr), to_string=True)
            """
            gef> monitor xp/16xb 0
            0000000000000000: 0x53 0xff 0x00 0xf0 0x53 0xff 0x00 0xf0
            0000000000000008: 0xc3 0xe2 0x00 0xf0 0x53 0xff 0x00 0xf0
            """
        except gdb.error:
            return None
        out = b""
        for line in res.splitlines():
            if not line:
                continue
            data = line.split()[1:]
            out += bytes([int(x, 16) for x in data])
        return out

    def kgdb_use_mdp(paddr, size): # for kgdb
        # Note: `mdp` command can only handle aligned addresses.
        paddr_aligned = paddr & ~0xf
        read_n_line = (size + (paddr - paddr_aligned) + 15) // 16
        try:
            res = gdb.execute("monitor mdp {:#x} {:d}".format(paddr_aligned, read_n_line), to_string=True)
            """
            gef> monitor mdp 0 2
            phys 0x0000000000000000 f000ff53f000ff53 f000ff53f000e2c3   S...S.......S...
            phys 0x0000000000000010 f000ff54f000ff53 f000ff53f0008488   S...T.......S...
            """
        except gdb.error:
            return None
        out = b""
        for line in res.splitlines():
            if not line:
                continue
            if line.endswith("zero suppressed"):
                start, end = AddressUtil.parse_string_range(line.split(" ")[0])
                zlen = (end + 1) - start
                out += b"\x00" * zlen
                continue
            out += b"".join([bytes.fromhex(x)[::-1] for x in line.split()[2:4]])
        return out[paddr & 0xf:][:size]

    # ----
    if size == 0:
        return b""

    if not is_qemu_system() and not is_vmware() and not is_kgdb():
        return None

    if is_qemu_system():
        out = qemu_system_strict_way(paddr, size)
        if out:
            return out
        if is_supported_physmode():
            out = transparent_read(paddr, size)
            if out:
                return out
        out = qemu_system_use_xp(paddr, size)
        if out:
            return out
        return None

    if is_vmware():
        return transparent_read(paddr, size)

    if is_kgdb():
        return kgdb_use_mdp(paddr, size)
    return None


def write_physmem(paddr, data):
    """Write `data` at physical memory address `paddr`."""

    def transparent_write(paddr, data):
        # switch virt/phys mode
        orig_mode = QemuMonitor.get_current_mmu_mode()
        try:
            if orig_mode == "virt":
                enable_phys()
            out = write_memory(paddr, data)
            if orig_mode == "virt":
                disable_phys()
            return out
        except Exception:
            if orig_mode == "virt":
                disable_phys()
        return None

    # ----

    if len(data) == 0:
        return 0

    if not is_qemu_system() and not is_vmware(): # kgdb is unsupported
        return None

    if not is_supported_physmode():
        return None

    return transparent_write(paddr, data)


@Cache.cache_until_next
def is_valid_addr(addr):
    if addr < 0:
        return False

    if is_x86_16():
        if current_arch.A20:
            shift = 21
        else:
            shift = 20
    elif is_64bit():
        shift = 64
    elif is_32bit():
        shift = 32

    if (1 << shift) - 1 < addr:
        return False

    if is_qemu_system():
        if QemuMonitor.check_gic_address(addr):
            return False

    try:
        gdb.selected_inferior().read_memory(addr, 1)
        return True
    except gdb.MemoryError:
        return False


@Cache.cache_until_next
def is_valid_addr_addr(addr):
    if is_valid_addr(addr):
        v = read_int_from_memory(addr)
        return is_valid_addr(v)
    return False


@Cache.cache_until_next
def is_double_link_list(addr):
    # list up next pointer
    seen = []
    while True:
        if not is_valid_addr(addr):
            return False
        if addr in seen:
            break
        seen.append(addr)
        addr = read_int_from_memory(addr)

    if addr != seen[0]:
        return False

    # check prev pointer
    for i, x in enumerate(seen):
        p = read_int_from_memory(x + current_arch.ptrsize)
        if p != seen[i - 1]:
            return False
    return True


class QemuMonitor:
    @staticmethod
    @Cache.cache_this_session
    def get_gic_addrs():
        """Return physical addresses of ARM GIC(General Interrupt Controller)."""
        if not is_qemu_system():
            return []

        if not is_arm32() and not is_arm64():
            return []

        try:
            res = gdb.execute("monitor info mtree -f", to_string=True)
        except gdb.error:
            return []

        gic_list = []
        for line in res.splitlines():
            # gef> monitor info mtree -f # these are physical addresses
            #   0000000008000000-0000000008000fff (prio 0, i/o): gic_dist
            #   0000000008010000-0000000008011fff (prio 0, i/o): gic_cpu
            if not line.startswith("  "):
                continue
            m = re.search(r"  ([0-9a-f]+)-([0-9a-f]+).*i/o\): gic_(dist|cpu)", line)
            if not m:
                continue
            paddr = int(m.group(1), 16)
            pend = int(m.group(2), 16)
            # fix size
            size = pend - paddr
            if (size & 0xfff) == 0xfff:
                size += 1
            gic_list.append([paddr, paddr + size])
        return gic_list

    @staticmethod
    @Cache.cache_until_next
    def check_gic_address(vaddr):
        gic_addrs = QemuMonitor.get_gic_addrs()
        if not gic_addrs:
            return False

        try:
            ret = gdb.execute("monitor gva2gpa {:#x}".format(vaddr), to_string=True)
        except gdb.error:
            return False
        r = re.search(r"gpa: (0x\S+)", ret)
        if not r:
            return False
        paddr = int(r.group(1), 16)

        for s, e in gic_addrs:
            if s <= paddr < e:
                return True
        return False

    @staticmethod
    def get_current_mmu_mode():
        if is_qemu_system():
            try:
                response = gdb.execute("maintenance packet qqemu.PhyMemMode", to_string=True, from_tty=False)
                if 'received: "0"' in response:
                    return "virt"
                elif 'received: "1"' in response:
                    return "phys"
                else:
                    return False
            except gdb.error:
                return False
        elif is_vmware():
            try:
                read_memory(0, 1)
                return "phys"
            except gdb.MemoryError:
                return "virt"
        return None

    @staticmethod
    def get_secure_memory_map(verbose=False):
        # find secure-ram base
        ret = gdb.execute("monitor info mtree -f", to_string=True)
        for line in ret.splitlines():
            m = re.search(r"([0-9a-f]{16})-([0-9a-f]{16}).*: \S+.secure-ram", line)
            if m:
                secure_memory_base = int(m.group(1), 16)
                secure_memory_size = int(m.group(2), 16) + 1 - secure_memory_base
                if verbose:
                    info("secure memory base: {:#x}-{:#x} ({:#x} bytes)".format(
                        secure_memory_base,
                        secure_memory_base + secure_memory_size,
                        secure_memory_size,
                    ))
                break
        else:
            return None

        # find virtual address
        ret = gdb.execute("monitor gpa2hva {:#x}".format(secure_memory_base), to_string=True)
        r = re.search("is (0x[0-9a-f]+)", ret)
        if not r:
            return None
        secure_memory_page_addr = int(r.group(1), 16)

        # find target map of qemu-system's pid
        qemu_system_pid = Pid.get_pid()
        if qemu_system_pid is None:
            if verbose:
                err("Not found qemu-system pid")
            return None
        maps = ProcessMap.get_process_maps_linux(qemu_system_pid)
        for m in maps:
            if m.page_start != secure_memory_page_addr:
                continue
            if m.size != secure_memory_size:
                continue
            if verbose:
                info("secure memory page of pid {:d}: {:#x}".format(qemu_system_pid, m.page_start))
            return m
        return None


def is_supported_physmode():
    """GDB mode determination function for physmem support."""
    return QemuMonitor.get_current_mmu_mode() in ["virt", "phys"]


def enable_phys():
    if is_qemu_system():
        response = gdb.execute("maintenance packet Qqemu.PhyMemMode:1", to_string=True, from_tty=False)
        response = gdb.execute("maintenance packet qqemu.PhyMemMode", to_string=True, from_tty=False)
        return 'received: "1"' in response
    elif is_vmware():
        gdb.execute("monitor phys", to_string=True)
        return True


def disable_phys():
    if is_qemu_system():
        response = gdb.execute("maintenance packet Qqemu.PhyMemMode:0", to_string=True, from_tty=False)
        response = gdb.execute("maintenance packet qqemu.PhyMemMode", to_string=True, from_tty=False)
        return 'received: "0"' in response
    elif is_vmware():
        gdb.execute("monitor virt", to_string=True)
        return True


@Cache.cache_until_next
def p8(x, s=False):
    """Pack one byte respecting the current architecture endianness."""
    if not s:
        return struct.pack("{}B".format(Endian.endian_str()), x)
    else:
        return struct.pack("{}b".format(Endian.endian_str()), x)


@Cache.cache_until_next
def p16(x, s=False):
    """Pack one word respecting the current architecture endianness."""
    if not s:
        return struct.pack("{}H".format(Endian.endian_str()), x)
    else:
        return struct.pack("{}h".format(Endian.endian_str()), x)


@Cache.cache_until_next
def p32(x, s=False):
    """Pack one dword respecting the current architecture endianness."""
    if not s:
        return struct.pack("{}I".format(Endian.endian_str()), x)
    else:
        return struct.pack("{}i".format(Endian.endian_str()), x)


@Cache.cache_until_next
def p64(x, s=False):
    """Pack one qword respecting the current architecture endianness."""
    if not s:
        return struct.pack("{}Q".format(Endian.endian_str()), x)
    else:
        return struct.pack("{}q".format(Endian.endian_str()), x)


@Cache.cache_until_next
def u8(x, s=False):
    """Unpack one byte respecting the current architecture endianness."""
    if not s:
        return struct.unpack("{}B".format(Endian.endian_str()), x)[0]
    else:
        return struct.unpack("{}b".format(Endian.endian_str()), x)[0]


@Cache.cache_until_next
def u16(x, s=False):
    """Unpack one word respecting the current architecture endianness."""
    if not s:
        return struct.unpack("{}H".format(Endian.endian_str()), x)[0]
    else:
        return struct.unpack("{}h".format(Endian.endian_str()), x)[0]


@Cache.cache_until_next
def u32(x, s=False):
    """Unpack one dword respecting the current architecture endianness."""
    if not s:
        return struct.unpack("{}I".format(Endian.endian_str()), x)[0]
    else:
        return struct.unpack("{}i".format(Endian.endian_str()), x)[0]


@Cache.cache_until_next
def u64(x, s=False):
    """Unpack one qword respecting the current architecture endianness."""
    if not s:
        return struct.unpack("{}Q".format(Endian.endian_str()), x)[0]
    else:
        return struct.unpack("{}q".format(Endian.endian_str()), x)[0]


@Cache.cache_until_next
def u128(x):
    """Unpack one oword respecting the current architecture endianness."""
    upper = struct.unpack("{}Q".format(Endian.endian_str()), x[8:])[0]
    lower = struct.unpack("{}Q".format(Endian.endian_str()), x[:8])[0]
    return (upper << 64) | lower


def is_ascii_string(addr):
    """Helper function to determine if the buffer pointed by `addr` is an ASCII string (in GDB)"""
    try:
        return read_cstring_from_memory(addr) is not None
    except gdb.MemoryError:
        return False


def is_alive():
    """GDB mode determination function for running."""
    try:
        return gdb.selected_inferior().pid > 0
    except gdb.error:
        return False
    return False


def parse_args(f):
    """Decorator wrapper to parse args for command."""

    @functools.wraps(f)
    def wrapper(self, argv, **kwargs):
        try:
            self.parser.exit = lambda *_: exec("if _: print(_[1]);\nraise(GefUtil.ArgparseExitProxyException(_))")
            args = self.parser.parse_args(argv)
        except GefUtil.ArgparseExitProxyException as e:
            if not e.args[0]: # when --help or -h
                if hasattr(self, "_example_") and self._example_:
                    gef_print("\nexample:\n" + "  " + self._example_.strip().replace("\n", "\n  "))
                if hasattr(self, "_note_") and self._note_:
                    gef_print("\nnote:\n" + "  " + self._note_.strip().replace("\n", "\n  "))
            return
        except Exception as e:
            err("Invalid argument: {}".format(e))
            return
        return f(self, args, **kwargs)

    return wrapper


def switch_to_intel_syntax(f):
    """Decorator to temporarily switch to Intel syntax."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        if not is_x86():
            return f(*args, **kwargs)

        att = gdb.parameter("disassembly-flavor") == "att"
        if att:
            gdb.execute("set disassembly-flavor intel", to_string=True)
        ret = f(*args, **kwargs)
        if att:
            gdb.execute("set disassembly-flavor att", to_string=True)
        return ret

    return wrapper


def only_if_gdb_running(f):
    """Decorator wrapper to check if GDB is running."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        if is_alive():
            return f(*args, **kwargs)
        else:
            warn("No debugging session active")
            return

    return wrapper


def only_if_gdb_target_local(f):
    """Decorator wrapper to check if GDB is running locally (target not remote)."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        if not is_remote_debug():
            return f(*args, **kwargs)
        else:
            warn("This command cannot work for remote sessions.")
            return

    return wrapper


def only_if_in_kernel(f):
    """Decorator wrapper to check if context is in kernel."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        if is_in_kernel():
            return f(*args, **kwargs)
        else:
            warn("Run in kernel context.")
            return

    return wrapper


def only_if_in_kernel_or_kpti_disabled(f):
    """Decorator wrapper to check if context is in kernel or kpti disabled."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        def is_kpti_enabled():
            s = KernelAddressHeuristicFinder.get_saved_command_line()
            if s and is_valid_addr(s):
                # You can access the kernel's .data area while in userland.
                # This means KPTI is disabled.
                return False
            return True

        if is_in_kernel():
            return f(*args, **kwargs)
        elif not is_kpti_enabled():
            return f(*args, **kwargs)
        else:
            warn("Run in kernel context, or disable KPTI.")
            return

    return wrapper


def only_if_kvm_disabled(f):
    """Decorator wrapper to check if there is not -enable-kvm option."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        if is_kvm_enabled():
            err("Disable `-enable-kvm` option for qemu-system.")
            return
        return f(*args, **kwargs)

    return wrapper


def only_if_specific_gdb_mode(mode=()):
    """Decorator wrapper to check if the gdb mode is specific."""

    def wrapper(f):
        @functools.wraps(f)
        def inner_f(*args, **kwargs):
            dic = {
                "pin": is_pin,
                "qemu-system": is_qemu_system,
                "qemu-user": is_qemu_user,
                "vmware": is_vmware,
                "kgdb": is_kgdb,
                "qiling": is_qiling,
                "rr": is_rr,
                "wine": is_wine,
            }
            for m in mode:
                if dic.get(m, lambda: False)():
                    return f(*args, **kwargs)
            warn("This command cannot work under this gdb mode.")
            return

        return inner_f

    return wrapper


def exclude_specific_gdb_mode(mode=()):
    """Decorator wrapper to check if the gdb mode is specific."""

    def wrapper(f):
        @functools.wraps(f)
        def inner_f(*args, **kwargs):
            dic = {
                "pin": is_pin,
                "qemu-system": is_qemu_system,
                "qemu-user": is_qemu_user,
                "vmware": is_vmware,
                "kgdb": is_kgdb,
                "qiling": is_qiling,
                "rr": is_rr,
                "wine": is_wine,
            }
            for m in mode:
                if dic.get(m, lambda: False)():
                    warn("This command cannot work under this gdb mode.")
                    return
            return f(*args, **kwargs)

        return inner_f

    return wrapper


def only_if_specific_arch(arch=()):
    """Decorator wrapper to check if the architecture is specific."""

    def wrapper(f):
        @functools.wraps(f)
        def inner_f(*args, **kwargs):
            dic = {
                "x86_32": is_x86_32,
                "x86_64": is_x86_64,
                "x86_16": is_x86_16,
                "ARM64": is_arm64,
                "ARM32": is_arm32,
                "MIPS32": is_mips32,
                "MIPS64": is_mips64,
                "MIPSN32": is_mipsn32,
                "PPC32": is_ppc32,
                "PPC64": is_ppc64,
                "SPARC32": is_sparc32,
                "SPARC32PLUS": is_sparc32plus,
                "SPARC64": is_sparc64,
                "RISCV32": is_riscv32,
                "RISCV64": is_riscv64,
                "S390X": is_s390x,
                "SH4": is_sh4,
                "M68K": is_m68k,
                "ALPHA": is_alpha,
                "HPPA32": is_hppa32,
                "HPPA64": is_hppa64,
                "OR1K": is_or1k,
                "NIOS2": is_nios2,
                "MICROBLAZE": is_microblaze,
                "XTENSA": is_xtensa,
                "CRIS": is_cris,
                "LOONGARCH64": is_loongarch64,
                "ARC32": is_arc32,
                "ARC64": is_arc64,
                "CSKY": is_csky,
            }
            for a in arch:
                if dic.get(a, lambda: False)():
                    return f(*args, **kwargs)
            warn("This command cannot work under this architecture.")
            return

        return inner_f

    return wrapper


def exclude_specific_arch(arch=()):
    """Decorator wrapper to check if the architecture is specific."""

    def wrapper(f):
        @functools.wraps(f)
        def inner_f(*args, **kwargs):
            dic = {
                "x86_32": is_x86_32,
                "x86_64": is_x86_64,
                "x86_16": is_x86_16,
                "ARM64": is_arm64,
                "ARM32": is_arm32,
                "MIPS32": is_mips32,
                "MIPS64": is_mips64,
                "MIPSN32": is_mipsn32,
                "PPC32": is_ppc32,
                "PPC64": is_ppc64,
                "SPARC32": is_sparc32,
                "SPARC32PLUS": is_sparc32plus,
                "SPARC64": is_sparc64,
                "RISCV32": is_riscv32,
                "RISCV64": is_riscv64,
                "S390X": is_s390x,
                "SH4": is_sh4,
                "M68K": is_m68k,
                "ALPHA": is_alpha,
                "HPPA32": is_hppa32,
                "HPPA64": is_hppa64,
                "OR1K": is_or1k,
                "NIOS2": is_nios2,
                "MICROBLAZE": is_microblaze,
                "XTENSA": is_xtensa,
                "CRIS": is_cris,
                "LOONGARCH64": is_loongarch64,
                "ARC32": is_arc32,
                "ARC64": is_arc64,
                "CSKY": is_csky,
            }
            for a in arch:
                if dic.get(a, lambda: False)():
                    warn("This command cannot work under this architecture.")
                    return
            return f(*args, **kwargs)

        return inner_f

    return wrapper


def timeout(duration):
    """Decorator to handle timeout."""

    def wrapper(function):
        import multiprocessing
        queue = multiprocessing.Queue(maxsize=1)

        def run_function(function, *args, **kwargs):
            try:
                # len(result) must be less than 0xffe8
                result = function(*args, **kwargs)
            except Exception as e:
                queue.put((False, e))
            else:
                queue.put((True, result))
            return

        def inner_f(*args, **kwargs):
            fargs = [function] + list(args)
            p = multiprocessing.Process(target=run_function, args=fargs, kwargs=kwargs)
            p.start()
            p.join(duration)
            if p.is_alive():
                p.kill()
                raise multiprocessing.TimeoutError
            assert queue.full()
            success, result = queue.get()
            if success:
                return result
            else:
                raise result

        return inner_f

    return wrapper


def to_unsigned_long(v):
    """Cast a gdb.Value to unsigned long."""
    bits = AddressUtil.get_memory_alignment(in_bits=True)
    mask = (1 << bits) - 1
    return int(v.cast(gdb.Value(mask).type)) & mask


# Don't use cache.
# This is because there is a command that performs step execution internally.
def get_register(regname, use_mbed_exec=False, use_monitor=False):
    """Return a register's value."""

    if regname[0] in ["%", "@"]:
        regname = "$" + regname[1:]

    if regname[0] != "$":
        regname = "$" + regname

    try:
        value = gdb.parse_and_eval(regname)
        if value.type.code == gdb.TYPE_CODE_INT:
            return to_unsigned_long(value)
        else:
            return int(value)
    except gdb.error:
        if (is_hppa32() or is_hppa64()) and regname == "$r0":
            return 0
        try:
            value = gdb.selected_frame().read_register(regname[1:])
            return int(value)
        except (gdb.error, ValueError):
            pass

    if use_mbed_exec and is_qemu_system() and is_arm32():
        # Note that attempting to read a non-existent register will jump to an Undefined exception
        try:
            r = gdb.execute("read-system-register {:s}".format(regname), to_string=True)
            if r:
                return int(r.split("=")[1], 16)
        except gdb.error:
            pass

    if use_monitor and is_qemu_system() and is_x86():
        regname = regname.lstrip("$").upper()
        res = gdb.execute("monitor info registers", to_string=True)
        r = re.search(r"{:s}=(\S+)".format(regname), res)
        if r:
            return int(r.group(1), 16)

    if use_monitor and is_vmware() and is_x86_64():
        regname = regname.lstrip("$")
        res = gdb.execute("monitor r {:s}".format(regname), to_string=True)
        r = re.search(r"{:s}=(\S+)".format(regname), res)
        if r:
            return int(r.group(1), 16)

    if use_mbed_exec and is_kgdb() and is_x86_64():
        regname = regname.lstrip("$")
        if regname in ["cr0", "cr2", "cr3", "cr4"]:
            try:
                r = gdb.execute("read-control-register {:s}".format(regname), to_string=True)
                if r:
                    return int(r.split("=")[1], 16)
            except gdb.error:
                pass

    return None


@Cache.cache_this_session
def is_remote_debug():
    """GDB mode determination function for remote debugging."""
    try:
        connection = gdb.selected_inferior().connection
        if connection is None:
            return False
        return connection and connection.type == "remote"
    except AttributeError:
        # before gdb 11.x: AttributeError: 'gdb.Inferior' object has no attribute 'connection'
        res = gdb.execute("maintenance print target-stack", to_string=True)
        return "remote" in res


# Removed is_remote_same_host.
# It can detect that gdb connects to a process in the same host.
# However, it cannot detect that traffic is being redirected to another host.


@Cache.cache_this_session
def is_normal_run():
    """GDB mode determination function for normal running."""
    ret = gdb.execute("info files", to_string=True)
    return "Using the running image of child" in ret


@Cache.cache_this_session
def is_attach():
    """GDB mode determination function for attaching."""
    try:
        return gdb.selected_inferior().was_attached
    except AttributeError:
        ret = gdb.execute("info files", to_string=True)
        return "Using the running image of attached" in ret


@Cache.cache_this_session
def is_container_attach():
    """GDB mode determination function for attaching another namespace."""
    return not is_remote_debug() and is_attach() and gdb.current_progspace().filename.startswith("target:")


@Cache.cache_this_session
def is_pin():
    """GDB mode determination function for pin and SDE."""
    if not is_remote_debug():
        return False
    try:
        response = gdb.execute("maintenance packet qSupported", to_string=True, from_tty=False)
    except gdb.error as e:
        err("{}".format(e))
        os._exit(0)
    return "intel.name=" in response


@Cache.cache_this_session
def is_qemu():
    """GDB mode determination function for qemu-user or qemu-system."""
    if not is_remote_debug():
        return False
    try:
        response = gdb.execute("maintenance packet Qqemu.sstepbits", to_string=True, from_tty=False)
    except gdb.error as e:
        err("{}".format(e))
        os._exit(0)
    return "ENABLE=" in response


@Cache.cache_this_session
def is_qemu_user():
    """GDB mode determination function for qemu-user gdb stub."""
    if is_qemu() is False:
        return False
    try:
        response = gdb.execute("maintenance packet qOffsets", to_string=True, from_tty=False)
    except gdb.error as e:
        err("{}".format(e))
        os._exit(0)
    return "Text=" in response


@Cache.cache_this_session
def is_qemu_system():
    """GDB mode determination function for qemu-system gdb stub."""
    if is_qemu() is False:
        return False
    try:
        response = gdb.execute("maintenance packet qOffsets", to_string=True, from_tty=False)
    except gdb.error as e:
        err("{}".format(e))
        os._exit(0)
    return 'received: ""' in response


@Cache.cache_this_session
def is_over_serial():
    """GDB mode determination function for serial device."""
    if not is_remote_debug():
        return False
    try:
        dev = gdb.selected_inferior().connection.details
        return dev.startswith(("/dev/ttyS", "/dev/ttyAMA"))
    except AttributeError:
        # before gdb 11.x: AttributeError: 'gdb.Inferior' object has no attribute 'connection'
        return False


def is_kgdb():
    """GDB mode determination function for KGDB."""
    return is_x86_64() and is_over_serial()


@Cache.cache_this_session
def is_vmware():
    """GDB mode determination function for VMware gdb stub."""
    if not is_remote_debug():
        return False
    # The `monitor help` command takes a very long time in kgdb mode.
    # We can speed it up by making sure we're not in kgdb mode beforehand.
    if is_over_serial():
        return False
    # https://xuanxuanblingbling.github.io/ctf/tools/2021/10/22/vmware/
    try:
        res = gdb.execute("monitor help r", to_string=True)
        return "Dump hidden register" in res
    except gdb.error:
        return False


@Cache.cache_this_session
def is_qiling():
    """GDB mode determination function for qiling framework gdb stub."""
    if not is_remote_debug():
        return False
    pid = Pid.get_pid(remote=True)
    if pid is None or pid < 42000:
        return False
    for m in ProcessMap.get_process_maps():
        if m.path == "[hook_mem]":
            return True
    return False


@Cache.cache_this_session
def is_rr():
    """GDB mode determination function for rr."""
    return Pid.get_pid_from_tcp_session(filepath="rr") is not None


@Cache.cache_this_session
def is_wine():
    """GDB mode determination function for winedbg."""
    return Pid.get_pid_from_tcp_session(filepath="wineserver") is not None


@Cache.cache_until_next
def is_in_kernel():
    """GDB mode determination function for kernel mode."""
    if not is_alive():
        return False
    if is_qiling():
        return False
    # If it fails to obtain the flag register required for the judgment,
    # it will be considered as userland.
    if is_x86():
        cs = get_register("$cs")
        if cs is None:
            return False
        return (cs & 0b11) != 3
    elif is_arm32():
        cpsr = get_register(current_arch.flag_register)
        if cpsr is None:
            return False
        return (cpsr & 0b11111) not in [0b10000, 0b11010]
    elif is_arm64():
        cpsr = get_register(current_arch.flag_register)
        if cpsr is None:
            return False
        return ((cpsr >> 2) & 0b11) == 1
    # All other architectures are considered userland.
    return False


@Cache.cache_this_session
def is_kvm_enabled():
    """GDB mode determination function for KVM."""
    try:
        res = gdb.execute("monitor info kvm", to_string=True)
        return "enabled" in res
    except gdb.error:
        return False


class Pid:
    @staticmethod
    def get_tcp_sess(pid):
        # get inode information from opened file descriptor
        inodes = []
        for openfd in os.listdir("/proc/{:d}/fd".format(pid)):
            try:
                fdname = os.readlink("/proc/{:d}/fd/{:s}".format(pid, openfd))
            except (FileNotFoundError, ProcessLookupError, OSError):
                continue
            if fdname.startswith("socket:["):
                inode = fdname[8:-1]
                inodes.append(inode)

        def decode(addr):
            ip, port = addr.split(":")
            import socket
            ip = socket.inet_ntop(socket.AF_INET, bytes.fromhex(ip)[::-1])
            port = int(port, 16)
            return (ip, port)

        # get connection information
        sessions = []
        with open("/proc/{:d}/net/tcp".format(pid)) as fd:
            for line in fd.readlines()[1:]:
                _, laddr, raddr, status, _, _, _, _, _, inode = line.split()[:10]
                if status != "01": # ESTABLISHED
                    continue
                if inode not in inodes:
                    continue
                laddr = decode(laddr)
                raddr = decode(raddr)
                sessions.append({"laddr": laddr, "raddr": raddr})
        return sessions

    @staticmethod
    def get_all_process():
        pids = [int(x) for x in os.listdir("/proc") if x.isdigit()]
        process = []
        for pid in pids:
            try:
                filepath = os.readlink("/proc/{:d}/exe".format(pid))
            except (FileNotFoundError, ProcessLookupError, OSError):
                continue
            process.append({"pid": pid, "filepath": os.path.basename(filepath)})
        return process

    @staticmethod
    def get_pid_from_name(filepath):
        candidate = []
        for process in Pid.get_all_process():
            if filepath in process["filepath"]:
                candidate.append(process)
        if len(candidate) == 1:
            return candidate[0]["pid"]
        return None

    @staticmethod
    def get_pid_from_tcp_session(filepath=None):
        gdb_tcp_sess = [x["raddr"] for x in Pid.get_tcp_sess(os.getpid())]
        if not gdb_tcp_sess:
            return None
        for process in Pid.get_all_process():
            if filepath and not process["filepath"].startswith(filepath):
                continue
            for c in Pid.get_tcp_sess(process["pid"]):
                if c["laddr"] in gdb_tcp_sess:
                    return process["pid"]
        return None

    @staticmethod
    def get_pid_wine():
        ws_pid = Pid.get_pid_from_tcp_session(filepath="wineserver")
        if ws_pid is None:
            return None

        def get_external_pipe_inodes(pid):
            inodes = set()
            if not os.path.exists("/proc/{:d}/".format(pid)):
                return inodes
            # get inode information from opened file descriptor
            for openfd in os.listdir("/proc/{:d}/fd".format(pid)):
                try:
                    fdname = os.readlink("/proc/{:d}/fd/{:s}".format(pid, openfd))
                except (FileNotFoundError, ProcessLookupError, OSError):
                    continue
                if fdname.startswith("pipe:["):
                    inode = fdname[6:-1]
                    if inode in inodes:
                        inodes.remove(inode)
                    else:
                        inodes.add(inode)
            return inodes

        ws_inodes = get_external_pipe_inodes(ws_pid)

        gdb_pid = os.getpid()
        for candidate_pid in range(gdb_pid - 1, ws_pid, -1):
            candidate_inodes = get_external_pipe_inodes(candidate_pid)
            if candidate_inodes & ws_inodes:
                return candidate_pid
        return None

    @staticmethod
    @Cache.cache_this_session
    def get_pid(remote=False):
        """Return the PID of the debuggee process."""
        if is_pin():
            return Pid.get_pid_from_tcp_session()
        elif is_qemu_user() or is_qemu_system():
            pid = Pid.get_pid_from_tcp_session("qemu") # strict way
            if pid is None:
                pid = Pid.get_pid_from_name("qemu") # ambiguous way
            return pid
        elif is_wine():
            return Pid.get_pid_wine()
        elif remote is False and is_remote_debug():
            return None # gdbserver etc.
        return gdb.selected_inferior().pid


class Path:
    @staticmethod
    def append_proc_root(filepath):
        if filepath is None:
            return None
        pid = Pid.get_pid()
        if pid is None:
            return None
        if pid == 0: # under gdbserver, when target exited then pid is 0
            return None
        prefix = "/proc/{}/root".format(pid)
        relative_path = filepath.lstrip("/")
        return os.path.join(prefix, relative_path)

    @staticmethod
    @Cache.cache_this_session
    def get_filepath(append_proc_root_prefix=True):
        """Return the local absolute path of the file currently debugged."""
        filepath = gdb.current_progspace().filename

        if is_remote_debug():
            if filepath is None:
                return None
            elif filepath.startswith("target:"):
                return None
            elif filepath.startswith(".gnu_debugdata for target:"):
                return None
            else:
                return filepath
        else:
            # inferior probably did not have name, extract cmdline from info proc
            if filepath is None:
                filepath = Path.get_filepath_from_info_proc()
                if append_proc_root_prefix:
                    # maybe different mnt namespace, so use /proc/<PID>/root
                    filepath = Path.append_proc_root(filepath)
            # not remote, but different PID namespace and attaching by pid. it shows with `target:`
            elif filepath.startswith("target:"):
                # /proc/PID/root is not given when used for purposes such as comparing with entry in vmmap
                filepath = filepath[len("target:"):]
                if append_proc_root_prefix:
                    # maybe different mnt namespace, so use /proc/<PID>/root
                    filepath = Path.append_proc_root(filepath)
            # normal path
            return filepath

    @staticmethod
    def get_filepath_from_info_proc():
        try:
            response = gdb.execute("info proc", to_string=True)
        except gdb.error:
            return None
        for x in response.splitlines():
            if x.startswith("exe = "):
                return x.split(" = ")[1].replace("'", "")
        return None

    @staticmethod
    @Cache.cache_this_session
    def get_filename():
        """Return the full filename of the file currently debugged."""
        filename = Path.get_filepath()
        if filename is None:
            return None
        return os.path.basename(filename)

    @staticmethod
    def read_remote_file(filepath, as_byte=True):
        tmp_name = os.path.join(GEF_TEMP_DIR, "read_remote_file.tmp")
        try:
            gdb.execute("remote get {:s} {:s}".format(filepath, tmp_name), to_string=True)
        except gdb.error:
            return ""
        if as_byte:
            data = open(tmp_name, "rb").read()
        else:
            data = open(tmp_name, "r").read()
        os.unlink(tmp_name)
        return data


class ProcessMap:
    @staticmethod
    @Cache.cache_until_next
    def get_process_maps_linux(pid, remote=False):
        """Parse the Linux process `/proc/pid/maps` file."""

        # open & read maps
        proc_map_file = "/proc/{:d}/maps".format(pid)
        if remote:
            data = Path.read_remote_file(proc_map_file, as_byte=False)
            if not data:
                return []
            lines = data.splitlines()
        else:
            lines = open(proc_map_file, "r").readlines()

        # tls and $sp of each threads
        extra_info = []
        if is_x86():
            tls_list = []
            orig_thread = gdb.selected_thread()
            orig_frame = gdb.selected_frame()
            if orig_thread: # orig_thread may be None if under winedbg
                for thread in gdb.selected_inferior().threads():
                    thread.switch() # change thread
                    # note: for speed up, do not use current_arch.get_tls()
                    tls = get_register("$fs_base" if is_x86_64() else "$gs_base") # get tls address
                    tls_list.append([thread.num, tls, current_arch.sp])
                orig_thread.switch() # revert thread
                orig_frame.select()
                extra_info = sorted(tls_list)

                # When using gdbserver, thread.num may start from 2 even though there is no thread.
                # This is confusing, so if there is only the main thread, force it to 1.
                if len(extra_info) == 1:
                    extra_info = [ [1] + extra_info[0][1:] ]

        # parse
        maps = []
        for line in lines:
            line = line.replace("\t", " ") # for qiling framework
            line = line.strip()
            addr, perm, off, _, rest = line.split(" ", 4)
            addr_start, addr_end = [int(x, 16) for x in addr.split("-")]
            rest = rest.split(" ", 1)
            if len(rest) == 1:
                pathname = ""
            else:
                pathname = rest[1].lstrip()
            inode = int(rest[0])

            for th_num, tls_addr, _ in extra_info:
                if tls_addr and addr_start <= tls_addr < addr_end:
                    pathname += "<tls-th{:d}>".format(th_num)
                    break

            for th_num, _, stack_addr in extra_info:
                if th_num > 1 and stack_addr and addr_start <= stack_addr < addr_end:
                    pathname += "<stack-th{:d}>".format(th_num)
                    break

            off = int(off, 16)
            perm = Permission.from_process_maps(perm)
            sect = Section(page_start=addr_start, page_end=addr_end, offset=off, permission=perm, inode=inode, path=pathname)
            maps.append(sect)
        return maps

    # get_explored_regions (used at qemu-user mode) is very slow,
    # Because it repeats read_memory many times to find the upper and lower bounds of the page.
    # Cache.cache_until_next is not effective as-is, as it is cleared by Cache.reset_gef_caches() each time the `stepi` runs.
    # Fortunately, memory maps rarely change.
    # I decided to clear and recheck the cache when the `vmmap` command is called explicitly.
    @staticmethod
    @Cache.cache_this_session
    def get_explored_regions():
        """Return sections from auxv exploring"""

        if current_arch is None:
            return []

        def is_valid_addr_fast(addr):
            try:
               gdb.selected_inferior().read_memory(addr, 1)
               return True
            except gdb.MemoryError:
                return False

        def get_region_start_end(addr):
            addr &= gef_getpagesize_mask_high()
            if not is_valid_addr_fast(addr):
                return None, None
            region_start = addr
            region_end = addr + gef_getpagesize()

            nonlocal regions
            end_addrs = [r.page_end for r in regions]
            start_addrs = [r.page_start for r in regions]

            # up search
            lower_bound = 0
            while True:
                if region_start <= lower_bound:
                    break
                if region_start in end_addrs:
                    break
                if not is_valid_addr_fast(region_start - gef_getpagesize()):
                    break
                region_start -= gef_getpagesize()

            upper_bound = 1 << AddressUtil.get_memory_alignment(in_bits=True)
            # down search
            while True:
                if region_end >= upper_bound:
                    break
                if region_end in start_addrs:
                    break
                if not is_valid_addr_fast(region_end):
                    break
                region_end += gef_getpagesize()
            return region_start, region_end

        def make_regions(addr, label, perm="rw-"):
            if addr is None:
                return []
            # check if already in region
            nonlocal regions
            for rg in regions:
                if rg.page_start <= addr < rg.page_end:
                    return []
            # make region
            start, end = get_region_start_end(addr)
            if start is None:
                return []
            perm = Permission.from_process_maps(perm)
            sect = Section(page_start=start, page_end=end, permission=perm, path=label)
            return [sect]

        def get_ehdr(addr):
            upper_bound = 1 << AddressUtil.get_memory_alignment(in_bits=True)
            for _ in range(128):
                if addr < 0 or addr > upper_bound:
                    return None
                try:
                    if read_memory(addr, 4) == b"\x7fELF":
                        return Elf.get_elf(addr)
                except gdb.MemoryError:
                    return None
                addr -= gef_getpagesize()
            return None

        def parse_region_from_ehdr(addr, label):
            elf = get_ehdr(addr & gef_getpagesize_mask_high())
            if elf is None:
                return []

            pages = []
            for phdr in elf.phdrs:
                if not phdr.p_memsz:
                    continue

                vaddr = phdr.p_vaddr
                if elf.is_pie():
                    vaddr += elf.addr
                vaddr_end = vaddr + phdr.p_memsz

                offset = phdr.p_offset
                flags = phdr.p_flags

                # align
                vaddr &= gef_getpagesize_mask_high()
                offset &= gef_getpagesize_mask_high()
                vaddr_end = (vaddr_end + gef_getpagesize_mask_low()) & gef_getpagesize_mask_high()

                # add per pages
                for page_addr in range(vaddr, vaddr_end, gef_getpagesize()):
                    # check already exist
                    for i, page in enumerate(pages):
                        if page["vaddr"] == page_addr:
                            # found, so fix flags
                            if page["flags"] & Elf.Phdr.PF_X: # already has PF_X
                                flags |= Elf.Phdr.PF_X
                            pages[i]["flags"] = flags # overwrite, because RELRO
                            break
                    else:
                        # not found, so add new page
                        page = {
                            "vaddr": page_addr,
                            "memsize": gef_getpagesize(),
                            "flags": flags,
                            "offset": offset + (page_addr - vaddr),
                        }
                        pages.append(page)

            pages = sorted(pages, key=lambda x: x["vaddr"])

            # merge contiguous
            prev = pages[0]
            for page in pages[1:]:
                prev_vend = prev["vaddr"] + prev["memsize"]
                if prev["flags"] == page["flags"] and prev_vend == page["vaddr"]:
                    prev["memsize"] += page["memsize"]
                    pages.remove(page)
                else:
                    prev = page

            # page -> section
            sects = []
            for page in pages:
                perm = Permission.from_process_maps(ElfInfoCommand.pflags[page["flags"]].lower())
                page_start = page["vaddr"]
                page_end = page["vaddr"] + page["memsize"]
                off = page["offset"]
                sect = Section(page_start=page_start, page_end=page_end, offset=off, permission=perm, path=label)
                sects.append(sect)
            return sects

        def get_linker(addr):
            if addr is None:
                return None

            # get interp
            elf = get_ehdr(addr & gef_getpagesize_mask_high())
            phdr = elf.get_phdr(Elf.Phdr.PT_INTERP)
            if phdr is None:
                return None

            vaddr = phdr.p_vaddr
            if elf.is_pie():
                vaddr += elf.addr

            linker = read_cstring_from_memory(vaddr)
            return linker

        def get_link_map(addr):
            if addr is None:
                return None

            # get dynamic
            elf = get_ehdr(addr & gef_getpagesize_mask_high())
            phdr = elf.get_phdr(Elf.Phdr.PT_DYNAMIC)
            if phdr is None:
                return None

            vaddr = phdr.p_vaddr
            vaddr_end = vaddr + phdr.p_memsz
            if elf.is_pie():
                vaddr += elf.addr
                vaddr_end += elf.addr

            # search DT_DEBUG
            for tag_addr in range(vaddr, vaddr_end, current_arch.ptrsize * 2):
                tag = read_int_from_memory(tag_addr)
                if tag == 21: # DT_DEBUG
                    dt_debug = read_int_from_memory(tag_addr + current_arch.ptrsize)
                    break
            else:
                # not found
                return None

            # get link_map
            try:
                link_map = read_int_from_memory(dt_debug + current_arch.ptrsize)
            except gdb.MemoryError:
                return None
            return link_map

        def get_filepath_wrapper():
            filepath = Path.get_filepath()
            if filepath:
                return filepath
            filepath = gdb.current_progspace().filename
            if filepath and filepath.startswith("target:"):
                filepath = filepath[7:]
            return filepath

        def parse_region_from_link_map(link_map):
            current = link_map
            new_regions = []
            while True:
                l_addr = read_int_from_memory(current + current_arch.ptrsize * 0)
                l_name = read_int_from_memory(current + current_arch.ptrsize * 1)
                l_next = read_int_from_memory(current + current_arch.ptrsize * 3)
                name = read_cstring_from_memory(l_name)
                if not name:
                    name = get_filepath_wrapper() or "[code]"
                new_regions += parse_region_from_ehdr(l_addr, name)
                if l_next == 0:
                    break
                current = l_next
            return new_regions

        def parse_auxv():
            auxv = Auxv.get_auxiliary_values()
            if not auxv:
                return []

            new_regions = []
            codebase = auxv.get("AT_PHDR", None) or auxv.get("AT_ENTRY", None)

            # plan1: from link_map info (code, all loaded shared library)
            link_map = get_link_map(codebase)
            if link_map:
                new_regions += parse_region_from_link_map(link_map)

            # plan2: use each auxv info (for code, linker)
            else:
                # code
                if "AT_PHDR" in auxv:
                    new_regions += parse_region_from_ehdr(auxv["AT_PHDR"], get_filepath_wrapper() or "[code]")
                elif "AT_ENTRY" in auxv:
                    new_regions += parse_region_from_ehdr(auxv["AT_ENTRY"], get_filepath_wrapper() or "[code]")
                # linker
                if "AT_BASE" in auxv:
                    new_regions += parse_region_from_ehdr(auxv["AT_BASE"], get_linker(codebase) or "[linker]")

            # vdso
            if "AT_SYSINFO_EHDR" in auxv:
                new_regions += parse_region_from_ehdr(auxv["AT_SYSINFO_EHDR"], "[vdso]")
            elif "AT_SYSINFO" in auxv:
                new_regions += parse_region_from_ehdr(auxv["AT_SYSINFO"], "[vdso]")
            return new_regions

        def parse_stack_register():
            # get permission
            stack_permission = "rw-" # default
            auxv = Auxv.get_auxiliary_values()
            if auxv and "AT_PHDR" in auxv:
                elf = get_ehdr(auxv["AT_PHDR"] & gef_getpagesize_mask_high())
                phdr = elf.get_phdr(Elf.Phdr.PT_GNU_STACK)
                if phdr:
                    stack_permission = ElfInfoCommand.pflags[phdr.p_flags].lower()
                else:
                    stack_permission = "rwx" # no GNU_STACK phdr means no-NX
            # add region
            return make_regions(current_arch.sp, "[stack]", stack_permission)

        def parse_registers_and_stack():
            queue = set()

            # registers
            for regname in current_arch.all_registers:
                v = get_register(regname)
                if v is None:
                    continue
                queue.add(v & gef_getpagesize_mask_high())

            # walk value from stack top
            sp = current_arch.sp
            if sp is not None:
                try:
                    data = read_memory(sp & gef_getpagesize_mask_high(), gef_getpagesize())
                    data = slice_unpack(data, current_arch.ptrsize)
                    queue |= {d & gef_getpagesize_mask_high() for d in set(data)}
                except gdb.MemoryError:
                    pass

            # contiguous areas are removed from the queue
            merged_queue = []
            for addr in sorted(queue):
                if not is_valid_addr(addr):
                    continue
                if addr - gef_getpagesize() in merged_queue:
                    continue
                merged_queue.append(addr)

            # add regions
            new_regions = []
            for addr in merged_queue:
                skip = False
                for rg in new_regions:
                    if rg.page_start <= addr < rg.page_end:
                        skip = True
                if not skip:
                    new_regions += make_regions(addr, "<explored>")
            return new_regions

        regions = []
        regions += parse_auxv()
        regions += parse_stack_register()

        # walk from known map, because qemu may maps extra regions (?)
        for r in regions.copy():
            regions += make_regions(r.page_start - 1, "<explored>", str(r.permission))
            regions += make_regions(r.page_end + 1, "<explored>", str(r.permission))

        regions += parse_registers_and_stack()

        # ok
        regions = sorted(regions, key=lambda x: x.page_start)

        return regions

    @staticmethod
    def get_process_maps_from_info_proc():
        res = gdb.execute("info proc mappings", to_string=True)

        """
        process 2897541
        Mapped address spaces:

                  Start Addr           End Addr       Size     Offset  Perms  objfile
                    0x400000           0x478000    0x78000        0x0  r-xp   /tmp/a.out
                    0x478000           0x48c000    0x14000        0x0  ---p
                    0x48c000           0x492000     0x6000    0x7c000  rw-p   /tmp/a.out
                    0x492000           0x498000     0x6000        0x0  rw-p
              0x400000000000     0x400000001000     0x1000        0x0  ---p
              0x400000001000     0x400000801000   0x800000        0x0  rw-p   [stack]
              0x400000801000     0x400000802000     0x1000        0x0  r-xp
        """
        maps = []
        for line in res.splitlines()[4:]:
            line = line.strip()
            addr_start, addr_end, size, offset, perm, *path = line.split()
            addr_start = int(addr_start, 16)
            addr_end = int(addr_end, 16)
            size = int(size, 16)
            offset = int(offset, 16)
            perm = Permission.from_process_maps(perm)
            if len(path) == 1:
                path = path[0]
            else:
                path = ""
            sect = Section(page_start=addr_start, page_end=addr_end, offset=offset, permission=perm, inode=None, path=path)
            maps.append(sect)
        return maps

    __gef_use_info_proc_mappings__ = None # the flag to use `info proc mappings`

    @staticmethod
    def get_process_maps_heuristic():
        if ProcessMap.__gef_use_info_proc_mappings__ is None:
            try:
                res = gdb.execute("info proc mappings", to_string=True)
                if "warning" in res:
                    ProcessMap.__gef_use_info_proc_mappings__ = False
                elif "Perms" not in res: # xtensa-linux-gdb
                    ProcessMap.__gef_use_info_proc_mappings__ = False
                else:
                    ProcessMap.__gef_use_info_proc_mappings__ = True
            except gdb.error:
                ProcessMap.__gef_use_info_proc_mappings__ = False

        # fast path
        if ProcessMap.__gef_use_info_proc_mappings__ is True:
            res = ProcessMap.get_process_maps_from_info_proc() # don't use cache
            if res:
                return res
            # something is wrong
            ProcessMap.__gef_use_info_proc_mappings__ = False

        # slow path
        return ProcessMap.get_explored_regions() # use cache

    @staticmethod
    @Cache.cache_until_next
    def get_process_maps(outer=False):
        """Return the mapped memory sections"""
        if is_qemu_user():
            if outer:
                pid = Pid.get_pid()
                if pid:
                    return ProcessMap.get_process_maps_linux(pid)
                return []
            else: # scan heuristic
                return ProcessMap.get_process_maps_heuristic()

        elif is_pin():
            pid = Pid.get_pid()
            if pid:
                return ProcessMap.get_process_maps_linux(pid)

        elif is_qemu_system():
            return []

        elif is_wine():
            # wine loads the EXE at wine's own virtual address.
            # Due to pwner's use case, wine itself and its libraries should also be displayed.
            # However, wine's `monitor mem` does not display them, so I did not adopt them.
            # It's more reliable to resolve wine's PID and get its maps.
            pid = Pid.get_pid()
            if pid:
                return ProcessMap.get_process_maps_linux(pid)
            return []

        elif is_remote_debug():
            remote_pid = Pid.get_pid(remote=True)
            if remote_pid:
                return ProcessMap.get_process_maps_linux(remote_pid, remote=True)

        elif is_rr():
            return ProcessMap.get_process_maps_from_info_proc()

        else: # normal pattern
            pid = Pid.get_pid()
            if pid:
                return ProcessMap.get_process_maps_linux(pid)

        return ProcessMap.get_process_maps_heuristic()

    # `info files` called from get_info_files is heavy processing.
    # Moreover, AddressUtil.recursive_dereference causes each address to be resolved every time.
    # Cache.cache_until_next is not effective as-is, as it is cleared by Cache.reset_gef_caches() each time the `stepi` runs.
    # Fortunately, zone information rarely changes.
    # I decided to keep the cache until it is explicitly cleared.
    @staticmethod
    @Cache.cache_this_session
    def get_info_files():
        """Retrieve all the files loaded by debuggee."""
        lines = gdb.execute("info files", to_string=True).splitlines()
        info_files = []
        for line in lines:
            line = line.strip()
            if not line:
                break
            if not line.startswith("0x"):
                continue
            blobs = [x.strip() for x in line.split(" ")]
            addr_start = int(blobs[0], 16)
            addr_end = int(blobs[2], 16)
            section_name = blobs[4]
            if "system-supplied DSO" in line:
                filepath = "[vdso]"
            elif len(blobs) == 7:
                filepath = blobs[6]
            else:
                filepath = Path.get_filepath(append_proc_root_prefix=False)
            Zone = collections.namedtuple("Zone", ["name", "zone_start", "zone_end", "filename"])
            info = Zone(section_name, addr_start, addr_end, filepath)
            info_files.append(info)
        return info_files

    @staticmethod
    @Cache.cache_until_next
    def process_lookup_address(addr):
        """Look up for an address in memory. Return an Address object if found, None otherwise."""
        if not is_alive():
            err("Process is not running")
            return None
        if is_qemu_system() or is_vmware() or is_kgdb():
            return None
        for sect in ProcessMap.get_process_maps():
            if sect.page_start <= addr < sect.page_end:
                return sect
        return None

    @staticmethod
    @Cache.cache_until_next
    def process_lookup_path(names, perm_mask=Permission.ALL):
        """Look up for paths in the process memory mapping.
        Return a Section object of load base if found, None otherwise."""
        if not is_alive():
            err("Process is not running")
            return None
        if isinstance(names, str):
            names = tuple([names]) # make tuple to iterate
        for sect in ProcessMap.get_process_maps():
            for name in names:
                if name in sect.path and sect.permission.value & perm_mask:
                    return sect
        return None

    @staticmethod
    @Cache.cache_until_next
    def file_lookup_address(addr):
        """Look up for a file by its address. Return a Zone object if found, None otherwise."""
        if is_qemu_system() or is_vmware() or is_kgdb():
            # If FGKASLR is enabled, there are too many sections and it will take a long time, so skip them.
            return None
        for info in ProcessMap.get_info_files():
            if info.zone_start <= addr < info.zone_end:
                return info
        return None

    @staticmethod
    @Cache.cache_until_next
    def lookup_address(addr):
        """Try to find the address in the process address space.
        Return an Address object, with validity flag set based on success."""
        sect = ProcessMap.process_lookup_address(addr)
        info = ProcessMap.file_lookup_address(addr)
        if sect is None and info is None:
            # i.e. there is no info on this address
            return Address(value=addr, valid=False)
        return Address(value=addr, section=sect, info=info)

    @staticmethod
    @Cache.cache_until_next
    def get_section_base_address(name):
        if name is None:
            return None
        section = ProcessMap.process_lookup_path(name)
        if section:
            return section.page_start
        # Fail, retry with real path
        section = ProcessMap.process_lookup_path(os.path.realpath(name))
        if section:
            return section.page_start
        return None

    @staticmethod
    def get_section_base_address_by_list(names):
        for name in names:
            page_start = ProcessMap.get_section_base_address(name)
            if page_start is not None:
                return page_start
        return None


class EventHandler:
    @staticmethod
    def continue_handler(_event):
        """GDB event handler for new object continue cases."""
        return

    __gef_check_once__ = True # the flag to process only once at startup
    __gef_check_disabled_bp__ = False # the flag to remove unnecessary breakpoints

    @staticmethod
    def hook_stop_handler(event):
        """GDB event handler for stop cases."""
        Cache.reset_gef_caches()

        # There seems to be a bug in some architecture (e.g. i386) where temporary breakpoints are
        # not deleted even if they are hit. I don't know the conditions under which this happens,
        # but if remains, gef would manually remove them.
        if EventHandler.__gef_check_disabled_bp__:
            for bp in gdb.breakpoints():
                if not bp.visible and bp.temporary:
                    if not bp.enabled:
                        bp.delete()
            EventHandler.__gef_check_disabled_bp__ = False

        # when kgdb, assume x86-64 or ARM
        if EventHandler.__gef_check_once__:
            if is_over_serial():
                dev = gdb.selected_inferior().connection.details
                if dev.startswith("/dev/ttyS"):
                    gdb.execute("set architecture i386:x86-64:intel", to_string=True)
                elif dev.startswith("/dev/ttyAMA"):
                    gdb.execute("set architecture armv7", to_string=True)
                else:
                    raise
                Cache.reset_gef_caches()

        # set `c`, `ni` and `si` command hooks for qemu-user and pin
        if EventHandler.__gef_check_once__:
            if is_qemu_user() or is_pin():
                gdb.execute("define c\ncontinue-for-qemu-user\nend")
                if is_or1k() or is_cris():
                    gdb.execute("define si\nstepi-for-qemu-user\nend")
                    gdb.execute("define ni\nnexti-for-qemu-user\nend")

        # GEF will resolve the architecture if it is unknown.
        if current_arch is None:
            set_arch(get_arch())

        # If the silent command is specified for a breakpoint, skip `context` command.
        context_flag = True
        if type(event) == gdb.BreakpointEvent:
            if event.breakpoint.is_valid() and event.breakpoint.enabled:
                if event.breakpoint.commands:
                    if event.breakpoint.commands.startswith("silent"):
                        context_flag = False
        if context_flag:
            gdb.execute("context")

        # Message if file is not loaded.
        if EventHandler.__gef_check_once__:
            if not (is_qemu_system() or is_kgdb() or is_vmware()):
                if not gdb.current_progspace().filename:
                    err("Missing info about architecture. Please set: `file /path/to/target_binary`")
                    err("Some architectures may not be automatically recognized. Please set: `set architecture YOUR_ARCH`.")
            EventHandler.__gef_check_once__ = False
        return

    @staticmethod
    def new_objfile_handler(_event):
        """GDB event handler for new object file cases."""
        Cache.reset_gef_caches(all=True)
        if current_arch is None:
            set_arch(get_arch())

        # delayed breakpoint for brva
        if BreakRelativeVirtualAddressCommand.delayed_bp_set is False and is_alive():
            if not (is_qemu_system() or is_kgdb() or is_vmware()):
                codebase = ProcessMap.get_section_base_address(Path.get_filepath(append_proc_root_prefix=False))
                if codebase is None:
                    codebase = ProcessMap.get_section_base_address(Path.get_filepath_from_info_proc())
                if codebase:
                    for offset in BreakRelativeVirtualAddressCommand.delayed_breakpoints:
                        gdb.execute("b *{:#x}".format(codebase + offset))
                    BreakRelativeVirtualAddressCommand.delayed_bp_set = True
        return

    @staticmethod
    def exit_handler(_event):
        """GDB event handler for exit cases."""
        Cache.reset_gef_caches(all=True)
        return

    @staticmethod
    def memchanged_handler(_event):
        """GDB event handler for mem changes cases."""
        Cache.reset_gef_caches()
        return

    @staticmethod
    def regchanged_handler(_event):
        """GDB event handler for reg changes cases."""
        Cache.reset_gef_caches()
        return


class UnicornKeystoneCapstone:
    @staticmethod
    def get_generic_arch(module, prefix, arch, mode, big_endian, to_string):
        """Retrieves architecture and mode from the arguments for use for the holy
        capstone/keystone/unicorn trinity."""
        if isinstance(mode, tuple):
            modes = list(mode)
        else:
            modes = [mode, ]

        if big_endian:
            modes.append("BIG_ENDIAN")
        else:
            modes.append("LITTLE_ENDIAN")

        if to_string:
            # arch
            arch = "{:s}.{:s}_ARCH_{:s}".format(module.__name__, prefix, arch)
            # mode
            tmp = []
            for m in modes:
                if not m:
                    tmp.append("0")
                else:
                    tmp.append("{:s}.{:s}_MODE_{:s}".format(module.__name__, prefix, m))
            mode = " + ".join(tmp)
        else:
            # arch
            arch = getattr(module, "{:s}_ARCH_{:s}".format(prefix, arch))
            # mode
            mode = 0
            for m in modes:
                if m:
                    mode |= getattr(module, "{:s}_MODE_{:s}".format(prefix, m))
        return arch, mode

    @staticmethod
    @load_unicorn
    def get_unicorn_arch(arch=None, mode=None, endian=None, to_string=False):
        if (arch, mode, endian) == (None, None, None):
            arch = current_arch.arch
            mode = current_arch.mode
            endian = Endian.is_big_endian()
        if (arch, mode) == ("RISCV", "32"):
            mode = "RISCV32"
        elif (arch, mode) == ("RISCV", "64"):
            mode = "RISCV64"
        elif (arch, mode) == ("PPC", "32"):
            mode = "PPC32"
        elif (arch, mode) == ("PPC", "64"):
            mode = "PPC64"
        elif (arch, mode) == ("SPARC", "32"):
            mode = "SPARC32"
        elif (arch, mode) == ("SPARC", "32PLUS"):
            mode = "SPARC32"
        elif (arch, mode) == ("SPARC", "64"):
            mode = "SPARC64"
        elif (arch, mode) == ("MIPS", "32"):
            mode = "MIPS32"
        elif (arch, mode) == ("MIPS", "64"):
            mode = "MIPS64"
        elif arch == "S390X":
            mode = None
        elif arch == "M68K":
            mode = None
        return UnicornKeystoneCapstone.get_generic_arch(sys.modules["unicorn"], "UC", arch, mode, endian, to_string)

    @staticmethod
    @load_capstone
    def get_capstone_arch(arch=None, mode=None, endian=None, to_string=False):
        if (arch, mode, endian) == (None, None, None):
            arch = current_arch.arch
            mode = current_arch.mode
            endian = Endian.is_big_endian()
        # hacky patch for applying to capstone's mode
        if (arch, mode) == ("RISCV", "32"):
            mode = ("RISCV32", "RISCVC")
        elif (arch, mode) == ("RISCV", "64"):
            mode = ("RISCV64", "RISCVC")
        elif (arch, mode) == ("SPARC", "32"):
            mode = ""
        elif (arch, mode) == ("SPARC", "32PLUS"):
            mode = ""
        elif (arch, mode) == ("SPARC", "64"):
            mode = "V9"
        elif (arch, mode) == ("MIPS", "32"):
            mode = "MIPS32"
        elif (arch, mode) == ("MIPS", "64"):
            mode = "MIPS64"
        elif arch == "S390X":
            arch, mode = "SYSZ", None
        elif arch == "M68K":
            mode = "M68K_060"
        return UnicornKeystoneCapstone.get_generic_arch(sys.modules["capstone"], "CS", arch, mode, endian, to_string)

    @staticmethod
    @load_keystone
    def get_keystone_arch(arch=None, mode=None, endian=None, to_string=False):
        if (arch, mode, endian) == (None, None, None):
            arch = current_arch.arch
            mode = current_arch.mode
            endian = Endian.is_big_endian()
        # hacky patch for applying to capstone's mode
        if arch == "ARM64":
            mode = None
        elif (arch, mode) == ("PPC", "32"):
            mode = "PPC32"
        elif (arch, mode) == ("PPC", "64"):
            mode = "PPC64"
        elif (arch, mode) == ("SPARC", "32"):
            mode = "SPARC32"
        elif (arch, mode) == ("SPARC", "32PLUS"):
            mode = "SPARC32"
        elif (arch, mode) == ("SPARC", "64"):
            mode = "SPARC64"
        elif (arch, mode) == ("MIPS", "32"):
            mode = "MIPS32"
        elif (arch, mode) == ("MIPS", "64"):
            mode = "MIPS64"
        elif arch == "S390X":
            arch, mode = "SYSTEMZ", None
        return UnicornKeystoneCapstone.get_generic_arch(sys.modules["keystone"], "KS", arch, mode, endian, to_string)

    @staticmethod
    @load_unicorn
    def get_unicorn_registers(to_string=False, add_sse=False):
        "Return a dict matching the Unicorn identifier for a specific register."
        unicorn = sys.modules["unicorn"]
        regs = {}

        if current_arch is not None:
            arch = current_arch.arch.lower()
        else:
            raise OSError("Oops")

        const = getattr(unicorn, "{}_const".format(arch))

        extra_regs = []
        if add_sse:
            if is_x86():
                extra_regs = ["$xmm{:d}".format(i) for i in range(16)]

        for reg in current_arch.all_registers + extra_regs:
            if arch == "ppc" and reg.startswith("$r"):
                regname = "UC_{:s}_REG_{:s}".format(arch.upper(), reg.lstrip("$r").upper())
            else:
                regname = "UC_{:s}_REG_{:s}".format(arch.upper(), reg.lstrip("$").upper())
            try:
                getattr(const, regname)
            except AttributeError:
                continue
            if to_string:
                regs[reg] = "{:s}.{:s}".format(const.__name__, regname)
            else:
                regs[reg] = getattr(const, regname)
        return regs

    @staticmethod
    @load_keystone
    def keystone_assemble(code, arch, mode, *args, **kwargs):
        """Assembly encoding function based on keystone."""
        import multiprocessing
        keystone = sys.modules["keystone"]
        code = String.str2bytes(code)
        addr = kwargs.get("addr", 0x1000)

        # `asm "[]"` returns no response
        @timeout(duration=1)
        def ks_asm(code, addr):
            return ks.asm(code, addr)

        try:
            ks = keystone.Ks(arch, mode)
            enc, cnt = ks_asm(code, addr)
        except keystone.KsError as e:
            err("Keystone assembler error: {!s}".format(e))
            return None
        except multiprocessing.TimeoutError:
            err("Keystone assembler timeout error")
            return None

        if cnt == 0:
            return ""

        enc = bytearray(enc)
        if "raw" not in kwargs:
            s = binascii.hexlify(enc)
            enc = b"\\x" + b"\\x".join([s[i : i + 2] for i in range(0, len(s), 2)])
            enc = enc.decode("utf-8")

        return enc


def is_64bit():
    """GDB mode determination function for 64-bit architecture."""
    return AddressUtil.ptr_width() == 8


def is_32bit():
    """GDB mode determination function for 32-bit architecture."""
    return AddressUtil.ptr_width() == 4


def is_emulated32():
    """GDB mode determination function for 32-bit architecture on 64-bit environment."""
    if is_64bit():
        return False

    if is_qemu_user():
        # This case cannot be determined
        return False

    if is_qemu_system():
        # corner case (e.g.: using qemu-system-x86_64, but process is executed as 32bit mode)
        # is not able to be detected
        return True

    for m in ProcessMap.get_process_maps():
        # native x86:
        # 0xbffdf000 0xc0000000 0x021000 0x000000 rw- [stack]
        # emulated x86 on x86_64
        # 0xfffdd000 0xffffe000 0x021000 0x000000 rw- [stack]
        # native arm:
        # 0xbefdf000 0xbf000000 0x021000 0x000000 rw- [stack]
        # emulated arm on aarch64
        # 0xfffcf000 0xffff0000 0x021000 0x000000 rw- [stack]
        if m.path == "[stack]":
            return (m.page_start >> 28) == 0xf
    else:
        return False # by default it considers on native


def is_x86_64():
    """Architecture determination function for x86-64."""
    return current_arch and current_arch.arch == "X86" and current_arch.mode == "64"


def is_x86_32():
    """Architecture determination function for x86-32."""
    return current_arch and current_arch.arch == "X86" and current_arch.mode == "32"


def is_x86_16():
    """Architecture determination function for x86-16."""
    return current_arch and current_arch.arch == "X86" and current_arch.mode == "16"


def is_x86():
    """Architecture determination function for x86-32 or x86-64 or x86_16."""
    return is_x86_32() or is_x86_64() or is_x86_16()


def is_arm32():
    """Architecture determination function for ARM 32 bit."""
    return current_arch and current_arch.arch == "ARM"


def is_arm64():
    """Architecture determination function for ARM 64 bit."""
    return current_arch and current_arch.arch == "ARM64"


def is_mips32():
    """Architecture determination function for mips 32 bit (o32 ABI)."""
    return current_arch and current_arch.arch == "MIPS" and current_arch.mode == "32"


def is_mips64():
    """Architecture determination function for mips 64 bit."""
    return current_arch and current_arch.arch == "MIPS" and current_arch.mode == "64"


def is_mipsn32():
    """Architecture determination function for mips 32 bit (n32 ABI)."""
    return current_arch and current_arch.arch == "MIPS" and current_arch.mode == "n32"


def is_ppc32():
    """Architecture determination function for powerpc 32 bit."""
    return current_arch and current_arch.arch == "PPC" and current_arch.mode == "32"


def is_ppc64():
    """Architecture determination function for powerpc 64 bit."""
    return current_arch and current_arch.arch == "PPC" and current_arch.mode == "64"


def is_sparc32():
    """Architecture determination function for sparc 32 bit."""
    return current_arch and current_arch.arch == "SPARC" and current_arch.mode == "32"


def is_sparc32plus():
    """Architecture determination function for sparc 32 bit (v8+)."""
    return current_arch and current_arch.arch == "SPARC" and current_arch.mode == "32PLUS"


def is_sparc64():
    """Architecture determination function for sparc 64 bit."""
    return current_arch and current_arch.arch == "SPARC" and current_arch.mode == "64"


def is_riscv32():
    """Architecture determination function for RISC-V 32 bit."""
    return current_arch and current_arch.arch == "RISCV" and current_arch.mode == "32"


def is_riscv64():
    """Architecture determination function for RISC-V 64 bit."""
    return current_arch and current_arch.arch == "RISCV" and current_arch.mode == "64"


def is_s390x():
    """Architecture determination function for s390x."""
    return current_arch and current_arch.arch == "S390X"


def is_sh4():
    """Architecture determination function for sh4."""
    return current_arch and current_arch.arch == "SH4"


def is_m68k():
    """Architecture determination function for m68k."""
    return current_arch and current_arch.arch == "M68K"


def is_alpha():
    """Architecture determination function for alpha."""
    return current_arch and current_arch.arch == "ALPHA"


def is_hppa32():
    """Architecture determination function for HP-PA 32 bit."""
    return current_arch and current_arch.arch == "HPPA" and current_arch.mode == "32"


def is_hppa64():
    """Architecture determination function for HP-PA 64 bit."""
    return current_arch and current_arch.arch == "HPPA" and current_arch.mode == "64"


def is_or1k():
    """Architecture determination function for OpenRISC 1000."""
    return current_arch and current_arch.arch == "OR1K"


def is_nios2():
    """Architecture determination function for Nios II."""
    return current_arch and current_arch.arch == "NIOS2"


def is_microblaze():
    """Architecture determination function for Microblaze."""
    return current_arch and current_arch.arch == "MICROBLAZE"


def is_xtensa():
    """Architecture determination function for Xtensa."""
    return current_arch and current_arch.arch == "XTENSA"


def is_cris():
    """Architecture determination function for CRIS."""
    return current_arch and current_arch.arch == "CRIS"


def is_loongarch64():
    """Architecture determination function for Loongarch 64 bit."""
    return current_arch and current_arch.arch == "LOONGARCH" and current_arch.mode == "64"


def is_arc32():
    """Architecture determination function for ARC 32 bit."""
    return current_arch and current_arch.arch == "ARC" and current_arch.mode in ["32v2", "32v3"]


def is_arc64():
    """Architecture determination function for ARC 64 bit."""
    return current_arch and current_arch.arch == "ARC" and current_arch.mode == "64v3"


def is_csky():
    """Architecture determination function for csky."""
    return current_arch and current_arch.arch == "CSKY"


@Cache.cache_until_next
def get_arch():
    """Return the binary's architecture."""
    if is_alive():
        try:
            arch = gdb.selected_frame().architecture()
            name = arch.name()
            # check i386 or i8086
            if name != "i386":
                return name
        except gdb.error:
            # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
            # Resolve by moving to the slow path.
            pass

    # slow path
    arch_str = gdb.execute("show architecture", to_string=True).strip()

    # The target architecture is set automatically (currently i386)
    # The target architecture is set to "auto" (currently "i386").
    # The target architecture is assumed to be mips
    # The target architecture is set to "mips".

    if "The target architecture is set automatically (currently " in arch_str:
        arch_str = arch_str.split("(currently ", 1)[1]
        arch_str = arch_str.split(")", 1)[0]
    elif 'The target architecture is set to "auto" (currently "' in arch_str:
        arch_str = arch_str.split('(currently "', 1)[1]
        arch_str = arch_str.split('")', 1)[0]
    elif "The target architecture is assumed to be " in arch_str:
        arch_str = arch_str.replace("The target architecture is assumed to be ", "")
    elif "The target architecture is set to " in arch_str:
        arch_str = arch_str.split('"')[1]
    else:
        # Unknown, we throw an exception to be safe
        raise RuntimeError("Unknown architecture: {}".format(arch_str))
    return arch_str


def set_arch(arch_str=None):
    """Sets the current architecture.
    If an arch is explicitly specified, use that one, otherwise try to parse it out of the current target.
    If that fails, and default is specified, select and set that arch.
    Return the selected arch, or raise an OSError."""
    global current_arch

    # get defined arch
    arches = {}
    queue = Architecture.__subclasses__()
    while queue:
        cls = queue.pop(0)
        for lc in cls.load_condition:
            arches[lc] = cls
        queue.extend(cls.__subclasses__())

    # Determined from the specified arch string
    if arch_str:
        key = arch_str.upper()

    else:
        # Determined from loaded ELF
        elf = Elf.get_elf()
        if not elf or not elf.is_valid():
            raise OSError("Could not determine architecture.")

        if elf.e_machine not in [Elf.EM_MIPS, Elf.EM_RISCV, Elf.EM_PARISC]:
            key = elf.e_machine

        else:
            # On some architectures, it is not possible to determine whether it is 32-bit or 64-bit
            # from the ELF header e_machine. so we use the detection result of gdb.
            key = get_arch().upper()

    # Even if it is determined to be MIPS64, if it is in 32-bit mode, it is n32.
    if key in MIPS64.load_condition and is_32bit():
        key = "MIPSN32"

    try:
        current_arch = arches[key]()
    except KeyError as err:
        raise OSError("Specified arch {!s} is not supported".format(key)) from err

    Cache.reset_gef_caches(all=True)
    return


class Auxv:
    @staticmethod
    def get_auxiliary_walk(offset=0):
        """Find AUXV by walking stack"""

        # do not use gef_getpagesize(), gef_getpagesize_mask_high(), etc.
        # because gef_getpagesize() -> Auxv.get_auxiliary_values() -> Auxv.get_auxiliary_walk()
        if current_arch.sp is None:
            return None
        addr = current_arch.sp & DEFAULT_PAGE_SIZE_MASK_HIGH

        # check readable or not
        if not is_valid_addr(addr):
            return None

        # find stack bottom
        try:
            while True:
                if b"\x7fELF" == read_memory(addr, 4):
                    break
                addr += DEFAULT_PAGE_SIZE
        except gdb.MemoryError: # if read error, that is stack bottom
            pass
        current = addr - current_arch.ptrsize * 2 - offset

        # check readable or not again
        if not is_valid_addr(current):
            # something is wrong, maybe stack is pivoted
            return None

        # find auxv end
        while True:
            a = read_int_from_memory(current)
            b = read_int_from_memory(current + current_arch.ptrsize)
            if a == b == 0:
                break
            current -= current_arch.ptrsize * 2

        # skip dummy null if exist
        for _ in range(1024):
            a = read_int_from_memory(current)
            if a == 7: # AT_BASE
                break
            current -= current_arch.ptrsize * 2
        else:
            return None

        # find auxv start
        while read_int_from_memory(current) <= 37: # AT_L3_CACHESHAPE
            current -= current_arch.ptrsize * 2
        current += current_arch.ptrsize * 2

        # parse auxv
        res = {}
        while True:
            key = read_int_from_memory(current)
            val = read_int_from_memory(current + current_arch.ptrsize)
            if key not in AuxvCommand.AT_CONSTANTS:
                break
            res[AuxvCommand.AT_CONSTANTS[key]] = val
            if key == 0:
                break
            current += current_arch.ptrsize * 2

        # test
        if "AT_ENTRY" not in res:
            return None
        if "AT_PHDR" not in res:
            return None
        if "AT_RANDOM" not in res:
            return None
        if "AT_BASE" not in res:
            return None
        if "AT_NULL" not in res:
            return None

        return res

    # Auxv.get_auxiliary_values (under qemu-user mode) is very slow,
    # Because it may call Auxv.get_auxiliary_walk that repeats read_memory many times to find the auxv value.
    # Cache.cache_until_next is not effective as-is, as it is cleared by Cache.reset_gef_caches() each time the `stepi` runs.
    # Fortunately, auxv rarely changes.
    # I decided to keep the cache until it is explicitly cleared.
    @staticmethod
    @Cache.cache_this_session
    def get_auxiliary_values(force_heuristic=False):
        """Retrieves the auxiliary values of the current execution.
        Returns None if not running, or a dict() of values."""
        if not is_alive():
            return None
        if is_qemu_system() or is_kgdb() or is_vmware() or is_wine():
            return None

        def fast_path():
            try:
                result = gdb.execute("info auxv", to_string=True)
            except gdb.error:
                return None
            res = {}
            for line in result.splitlines():
                tmp = line.split()
                auxv_type = tmp[1]
                if auxv_type in ("AT_PLATFORM", "AT_EXECFN", "AT_BASE_PLATFORM"):
                    m = re.match("^.+?(0x[0-9a-f]+)", line)
                    res[auxv_type] = int(m.group(1), 0)
                else:
                    res[auxv_type] = int(tmp[-1], 0)
            return res

        def slow_path():
            if current_arch is None:
                return None
            for offset in [0, current_arch.ptrsize]:
                res = Auxv.get_auxiliary_walk(offset)
                if res:
                    return res
            return None

        if force_heuristic:
            return slow_path()

        return fast_path() or slow_path()


@Cache.cache_this_session
def gef_getpagesize():
    """Get the page size from auxiliary values."""
    auxval = Auxv.get_auxiliary_values()
    if not auxval or "AT_PAGESZ" not in auxval:
        return DEFAULT_PAGE_SIZE
    return auxval["AT_PAGESZ"]


@Cache.cache_this_session
def gef_getpagesize_mask_low():
    """Get the page size mask from auxiliary values."""
    auxval = Auxv.get_auxiliary_values()
    if not auxval or "AT_PAGESZ" not in auxval:
        return DEFAULT_PAGE_SIZE_MASK_LOW
    return auxval["AT_PAGESZ"] - 1


@Cache.cache_this_session
def gef_getpagesize_mask_high():
    """Get the page size mask from auxiliary values."""
    auxval = Auxv.get_auxiliary_values()
    if not auxval or "AT_PAGESZ" not in auxval:
        return DEFAULT_PAGE_SIZE_MASK_HIGH
    return ~(auxval["AT_PAGESZ"] - 1)


def only_if_events_supported(event_type):
    """Decorator for checking if GDB supports events without crashing."""

    def wrap(f):
        def wrapped_f(*args, **kwargs):
            if gdb.events and getattr(gdb.events, event_type):
                return f(*args, **kwargs)
            warn("GDB events cannot be set")
        return wrapped_f

    return wrap


class EventHooking:
    @staticmethod
    @only_if_events_supported("cont")
    def gef_on_continue_hook(func):
        return gdb.events.cont.connect(func)

    @staticmethod
    @only_if_events_supported("cont")
    def gef_on_continue_unhook(func):
        return gdb.events.cont.disconnect(func)

    @staticmethod
    @only_if_events_supported("stop")
    def gef_on_stop_hook(func):
        return gdb.events.stop.connect(func)

    @staticmethod
    @only_if_events_supported("stop")
    def gef_on_stop_unhook(func):
        return gdb.events.stop.disconnect(func)

    @staticmethod
    @only_if_events_supported("exited")
    def gef_on_exit_hook(func):
        return gdb.events.exited.connect(func)

    @staticmethod
    @only_if_events_supported("exited")
    def gef_on_exit_unhook(func):
        return gdb.events.exited.disconnect(func)

    @staticmethod
    @only_if_events_supported("new_objfile")
    def gef_on_new_hook(func):
        return gdb.events.new_objfile.connect(func)

    @staticmethod
    @only_if_events_supported("new_objfile")
    def gef_on_new_unhook(func):
        return gdb.events.new_objfile.disconnect(func)

    @staticmethod
    @only_if_events_supported("memory_changed")
    def gef_on_memchanged_hook(func):
        return gdb.events.memory_changed.connect(func)

    @staticmethod
    @only_if_events_supported("memory_changed")
    def gef_on_memchanged_unhook(func):
        return gdb.events.memory_changed.disconnect(func)

    @staticmethod
    @only_if_events_supported("register_changed")
    def gef_on_regchanged_hook(func):
        return gdb.events.register_changed.connect(func)

    @staticmethod
    @only_if_events_supported("register_changed")
    def gef_on_regchanged_unhook(func):
        return gdb.events.register_changed.disconnect(func)


#
# Commands
#


def register_command(cls):
    """Decorator for registering new GEF (sub-)command to GDB."""
    global __gef_commands__
    __gef_commands__.append(cls)
    return cls


def register_priority_command(cls):
    """Decorator for registering new command with priority, meaning that it must
    loaded before the other generic commands."""
    global __gef_commands__
    __gef_commands__.insert(0, cls)
    return cls


class GenericCommand(gdb.Command):
    """This is an abstract class for invoking commands, should not be instantiated."""
    __metaclass__ = abc.ABCMeta

    @abc.abstractproperty
    def _cmdline_(self):
        pass

    @abc.abstractproperty
    def _syntax_(self):
        pass

    @abc.abstractproperty
    def _example_(self):
        pass

    @abc.abstractproperty
    def _note_(self):
        pass

    @abc.abstractproperty
    def _repeat_(self):
        pass

    @abc.abstractproperty
    def _aliases_(self):
        pass

    @abc.abstractmethod
    def do_invoke(self, argv):
        pass

    def pre_load(self):
        pass

    def post_load(self):
        pass

    def __init__(self, *args, **kwargs):
        self.pre_load()

        def tab(lines):
            return "\n".join(["  " + line for line in lines.splitlines()])

        self.__doc__ += "\n"

        if self._syntax_:
            self.__doc__ += "\n"
            self.__doc__ += Color.colorify("Syntax:", "bold yellow")
            self.__doc__ += "\n"
            self.__doc__ += self._syntax_.strip()
            self.__doc__ += "\n"

        if self._example_:
            self.__doc__ += "\n"
            self.__doc__ += Color.colorify("Example:", "bold yellow")
            self.__doc__ += "\n"
            self.__doc__ += tab(self._example_.strip())
            self.__doc__ += "\n"

        if self._note_:
            self.__doc__ += "\n"
            self.__doc__ += Color.colorify("Note:", "bold yellow")
            self.__doc__ += "\n"
            self.__doc__ += tab(self._note_.strip())
            self.__doc__ += "\n"

        if hasattr(self._aliases_, "__iter__") and self._aliases_:
            self.__doc__ += "\n"
            self.__doc__ += Color.colorify("Aliases:", "bold yellow")
            self.__doc__ += "\n"
            self.__doc__ += tab(str(self._aliases_))
            self.__doc__ += "\n"

        self.repeat = False
        self.repeat_count = 0
        self.__last_command = None

        command_type = kwargs.get("command", gdb.COMMAND_NONE)
        complete_type = kwargs.get("complete", gdb.COMPLETE_NONE)
        prefix = kwargs.get("prefix", False)

        if complete_type == "use_user_complete":
            super().__init__(self._cmdline_, command_type, prefix=prefix)
        else:
            super().__init__(self._cmdline_, command_type, complete_type, prefix)
        self.post_load()
        return

    def invoke(self, args, from_tty): # noqa
        try:
            argv = gdb.string_to_argv(args)
            if self._repeat_:
                self.set_repeat_count(argv, from_tty)
            else:
                self.dont_repeat()
            self.do_invoke(argv)
        except Exception:
            # Since we are intercepting cleaning exceptions here, commands preferably should avoid
            # catching generic Exception, but rather specific ones. This is allows a much cleaner use.
            GefUtil.show_last_exception()
        return

    def usage(self):
        gef_print(Color.colorify("Syntax:", "bold yellow"))
        gef_print(self._syntax_.strip())

        if self._example_:
            gef_print("")
            gef_print(Color.colorify("Example:", "bold yellow"))
            gef_print(self._example_.strip())

        if self._note_:
            gef_print("")
            gef_print(Color.colorify("Note:", "bold yellow"))
            gef_print(self._note_.strip())
        return

    def add_setting(self, name, value, description=""):
        # make sure settings are always associated to the root command
        # which derives from GenericCommand directly.
        if "GenericCommand" not in [x.__name__ for x in self.__class__.__bases__]:
            return

        # sanitize
        class_name = self.__class__._cmdline_
        class_name = class_name.replace(" ", "_")
        # gdb's user complete feature does not work well if "-" is included.
        class_name = class_name.replace("-", "_")

        # add
        key = "{:s}.{:s}".format(class_name, name)
        Config.__gef_config__[key] = [value, type(value), description]
        Config.__gef_config_orig__[key] = [value, type(value), description] # for debugging

        # reset cache
        Cache.reset_gef_caches(function=Config.get_gef_setting)
        return

    def set_repeat_count(self, argv, from_tty):
        if not from_tty:
            self.repeat = False
            self.repeat_count = 0
            return

        command = gdb.execute("show commands", to_string=True).strip().split("\n")[-1]
        self.repeat = self.__last_command == command
        self.repeat_count = self.repeat_count + 1 if self.repeat else 0
        self.__last_command = command
        return


class BufferingOutput:
    def ok(self, msg):
        msg = "{} {}".format(Color.colorify("[+]", "bold green"), msg)
        self.out.append(msg)
        return

    def info(self, msg):
        msg = "{} {}".format(Color.colorify("[+]", "bold blue"), msg)
        self.out.append(msg)
        return

    def warn(self, msg):
        msg = "{} {}".format(Color.colorify("[+]", "bold yellow"), msg)
        self.out.append(msg)
        return

    def err(self, msg):
        msg = "{} {}".format(Color.colorify("[+]", "bold red"), msg)
        self.out.append(msg)
        return

    def print_output(self, args, term=False):
        if term:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        else:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


# Copy/paste this template for new command
# @register_command
# class TemplateCommand(GenericCommand):
#     """TemplateCommand: description here will be seen in the help menu for the command."""
#     _cmdline_ = "template-fake"
#     _category_ = "99. GEF Maintenance Command"
#     _aliases_ = ["tpl-fk"]
#
#     parser = argparse.ArgumentParser(prog=_cmdline_)
#     _syntax_ = parser.format_help()
#
#     _example_ = "{:s}".format(_cmdline_)
#     _note_ = "..."
#
#     def __init__(self):
#         super().__init__(complete=gdb.COMPLETE_FILENAME)
#         return
#
#     @parse_args
#     def do_invoke(self, args):
#         return


@register_command
class ResetCacheCommand(GenericCommand):
    """Reset all caches (both Cache.cache_until_next and Cache.cache_this_session)."""
    _cmdline_ = "reset-cache"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--hard", action="store_true",
                        help="also delete under {:s}.".format(GEF_TEMP_DIR))
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        Cache.reset_gef_caches(all=True)

        if args.hard:
            for root, _dirs, files in os.walk(GEF_TEMP_DIR, followlinks=False):
                for f in sorted(files):
                    path = os.path.join(root, f)
                    if os.path.islink(path):
                        continue
                    if os.path.isdir(path):
                        continue
                    os.unlink(path)
                    gef_print("{:s} is deleted".format(path))
        return


@register_command
class ResetBreakpointsCommand(GenericCommand):
    """Show and reset all breakpoints (include internal breakpoints)."""
    _cmdline_ = "reset-bp"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-c", "--commit", action="store_true",
                        help="actually perform delete.")
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        breakpoints = gdb.breakpoints()
        n = len(breakpoints)

        for bp in breakpoints:
            bp_str = repr(bp)
            if args.commit:
                bp.delete()
                gef_print("Delete successfully: {:s}".format(bp_str))
            else:
                info("Breakpoint is found: {:s}".format(bp_str))

        if not args.commit and n > 0:
            warn('This is dry run mode. No breakpoint is deleted yet. To delete, please add "--commit".')
        return


@register_priority_command
class GefThemeCommand(GenericCommand):
    """Customize GEF appearance."""
    _cmdline_ = "theme"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("key", metavar="KEY", nargs="?", help="color theme key.")
    parser.add_argument("value", metavar="VALUE", nargs="*", help="color theme value.")
    parser.add_argument("--color-sample", action="store_true", help="print available name of colors.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}                        # show all theme settings\n".format(_cmdline_)
    _example_ += "{:s} address_code           # show specified theme setting\n".format(_cmdline_)
    _example_ += "{:s} address_code bold cyan # set new theme".format(_cmdline_)

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.add_setting("context_title_line", "cyan", "Color of the borders in context window")
        self.add_setting("context_title_message", "cyan", "Color of the title in context window")
        self.add_setting("default_title_line", "cyan", "Default color of borders")
        self.add_setting("default_title_message", "cyan", "Default color of title")
        self.add_setting("table_heading", "bold blue", "Color of the column headings to tables (e.g. vmmap)")
        self.add_setting("context_code_past", "bright_black", "Color to display past code")
        self.add_setting("context_code_future", "", "Color to display future code")
        self.add_setting("disassemble_address", "", "Color of address when disassembling")
        self.add_setting("disassemble_address_highlight", "bold green", "Color of address when disassembling (=$pc)")
        self.add_setting("disassemble_opcode", "white", "Color of location when disassembling")
        self.add_setting("disassemble_opcode_highlight", "bold white", "Color of location when disassembling (=$pc)")
        self.add_setting("disassemble_mnemonic_normal", "yellow", "Color of normal mnemonic when disassembling")
        self.add_setting("disassemble_mnemonic_normal_highlight", "bold bright_yellow", "Color of normal mnemonic when disassembling (=$pc)")
        self.add_setting("disassemble_mnemonic_branch", "bold bright_yellow", "Color of branch mnemonic when disassembling")
        self.add_setting("disassemble_mnemonic_branch_highlight", "bold bright_yellow", "Color of branch mnemonic when disassembling (=$pc)")
        self.add_setting("disassemble_operands_normal", "cyan", "Color of normal operands when disassembling")
        self.add_setting("disassemble_operands_normal_highlight", "bold cyan", "Color of normal operands when disassembling (=$pc)")
        self.add_setting("disassemble_operands_const", "bright_blue", "Color of const operands when disassembling")
        self.add_setting("disassemble_operands_const_highlight", "bold bright_blue", "Color of const operands when disassembling (=$pc)")
        self.add_setting("disassemble_operands_symbol", "white", "Color of symbol operands when disassembling)")
        self.add_setting("disassemble_operands_symbol_highlight", "bold white", "Color of symbol operands when disassembling (=$pc)")
        self.add_setting("dereference_string", "yellow", "Color of dereferenced string")
        self.add_setting("dereference_base_address", "cyan", "Color of dereferenced address")
        self.add_setting("dereference_register_value", "bold blue", "Color of dereferenced register")
        self.add_setting("registers_register_name", "blue", "Color of the register name in the register window")
        self.add_setting("registers_value_changed", "bold red", "Color of the changed register in the register window")
        self.add_setting("address_stack", "magenta", "Color to use when a stack address is found")
        self.add_setting("address_heap", "bright_blue", "Color to use when a heap address is found")
        self.add_setting("address_code", "red", "Color to use when a code address is found")
        self.add_setting("address_writable", "green", "Color to use when a writable address is found")
        self.add_setting("address_readonly", "white", "Color to use when a read-only address is found")
        self.add_setting("address_rwx", "underline", "Color to use when a RWX address is found")
        self.add_setting("address_valid_but_none", "bright_black", "Color to use when a --- address is found")
        self.add_setting("source_current_line", "green", "Color to use for the current code line in the source window")
        self.add_setting("heap_arena_label", "bold cyan underline", "Color of the arena label used heap")
        self.add_setting("heap_chunk_label", "bold cyan underline", "Color of the chunk label used heap")
        self.add_setting("heap_label_active", "bold green underline", "Color of the (active) label used heap")
        self.add_setting("heap_label_inactive", "bold red underline", "Color of the (inactive) label used heap")
        self.add_setting("heap_chunk_address_used", "bright_black", "Color of the chunk address used heap")
        self.add_setting("heap_chunk_address_freed", "bold yellow", "Color of the freed chunk address used heap")
        self.add_setting("heap_chunk_used", "bright_black", "Color of the used chunk used heap")
        self.add_setting("heap_chunk_freed", "yellow", "Color of the freed chunk used heap")
        self.add_setting("heap_chunk_size", "bold magenta", "Color of the size used heap")
        self.add_setting("heap_chunk_flag_prev_inuse", "bold red", "Color of the prev_in_use flag used heap")
        self.add_setting("heap_chunk_flag_non_main_arena", "bold yellow", "Color of the non_main_arena flag used heap")
        self.add_setting("heap_chunk_flag_is_mmapped", "bold blue", "Color of the is_mmapped flag used heap")
        self.add_setting("heap_freelist_hint", "bold blue", "Color of the freelist hint used heap")
        self.add_setting("heap_page_address", "bold", "Color of the page address used heap")
        self.add_setting("heap_management_address", "bright_blue", "Color of the management address used heap")
        self.add_setting("heap_corrupted_msg", "bold red", "Color of the corrupted message used heap")
        return

    def show_all_config(self):
        gef_print(titlify("settings"))

        settings = []
        for x in Config.__gef_config__:
            if x.startswith("theme."):
                settings.append(x.split(".", 1)[1])

        for setting in sorted(settings):
            value = Config.get_gef_setting("theme.{:s}".format(setting))
            if value:
                value = Color.colorify(value, value)
                gef_print("{:40s}: {:s}".format(setting, value))
            else:
                gef_print("{:40s}: {:s}".format(setting, "None"))
        return

    def show_color_sample(self):
        gef_print(titlify("defined colors"))
        i = 0
        for k, v in Color.colors.items():
            if k.endswith("_off") or k == "normal":
                continue
            gef_print("{}{:20s}{}  ".format(v, k, Color.colors["normal"]), end="")

            if k in ["blink", "cyan", "bright_white", "_black"]: # group terminators
                gef_print("")
                i = 0
                continue

            if i % 5 == 4:
                gef_print("")
            i += 1
        return

    @parse_args
    def do_invoke(self, args):
        # show all
        if args.key is None:
            self.show_all_config()
            if args.color_sample:
                self.show_color_sample()
            else:
                gef_print("* use --color-sample to see available color name")
            return

        # show one
        key = "theme.{:s}".format(args.key)
        if key not in Config.__gef_config__:
            err("Invalid key")
            return
        if args.value == []:
            value = Config.get_gef_setting(key)
            value = Color.colorify(value, value)
            gef_print("{:40s}: {:s}".format(args.key, value))
            return

        # set
        val = [x for x in args.value if x in Color.colors]
        gdb.execute("gef config theme.{:s} '{:s}'".format(args.key, " ".join(val)))
        return


@register_command
class VersionCommand(GenericCommand):
    """Display GEF version info."""
    _cmdline_ = "version"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--compact", action="store_true", help="show compact style.")
    _syntax_ = parser.format_help()

    def os_version(self):
        try:
            lsb_release_command = GefUtil.which("lsb_release")
            res = GefUtil.gef_execute_external([lsb_release_command, "-d"], as_list=True)
            for line in res:
                if line.startswith("Description:"):
                    return line.split(":")[1].strip("\\t")
        except FileNotFoundError:
            pass

        if os.path.exists("/etc/issue.net"):
            content = open("/etc/issue.net").read().strip()
            if content:
                return content

        if os.path.exists("/etc/issue"):
            content = open("/etc/issue").read().strip()
            content = content.replace(" \\n \\l", "")
            if content:
                return content

        if os.path.exists("/etc/os-release"):
            content = open("/etc/os-release").read()
            for line in content.splitlines():
                r = re.search(r'PRETTY_NAME="(.+)"', line)
                if r:
                    return r.group(1)

        return "Not found"

    def kernel_version_from_uname(self):
        try:
            uname_command = GefUtil.which("uname")
            res = GefUtil.gef_execute_external([uname_command, "-a"], as_list=True)
            return res[0]
        except FileNotFoundError:
            return "Not found"

    def kernel_version_from_proc(self):
        try:
            return open("/proc/version").read().strip()
        except FileNotFoundError:
            return "Not found"

    def system_libc_version(self):
        res = GefUtil.gef_execute_external(["cat", "/proc/self/maps"], as_list=True)
        libc_targets = ("libc-2.", "libc.so.6", "libuClibc-")
        for line in res:
            if not any(kw in line for kw in libc_targets):
                continue
            path = line.split()[-1]
            if not os.path.exists(path):
                continue
            data = open(path, "rb").read()
            pos = re.search(b"(GNU C Library|uClibc-ng release) [\x20-\x7e]*", data)
            if pos:
                return String.bytes2str(pos.group(0))
        return "Not found"

    def qemu_system_version(self):
        return gdb.execute("monitor info version", to_string=True).strip()

    def qemu_user_version(self):
        pid = Pid.get_pid()
        try:
            res = GefUtil.gef_execute_external(["/proc/{:d}/exe".format(pid), "--version"], as_list=True)
            return res[0].strip()
        except (IndexError, FileNotFoundError):
            return "Not recognized"

    def gef_version(self):
        gef_hash = hashlib.sha1(open(GEF_FILEPATH, "rb").read()).hexdigest()
        import datetime
        dt = datetime.datetime.fromtimestamp(os.stat(GEF_FILEPATH).st_mtime)
        return "Last modified: {} SHA1: {}".format(dt.strftime("%Y-%m-%d %H:%M:%S"), gef_hash)

    def gdb_version(self):
        try:
            return gdb.VERSION # GDB >= 8.1 (or earlier?)
        except AttributeError:
            return gdb.execute("show version", to_string=True).split("\n")[0]

    def python_version(self):
        return sys.version.replace("\n", " ")

    def capstone_version(self):
        @load_capstone
        def _capstone_version():
            capstone = sys.modules["capstone"]
            return ".".join(map(str, capstone.cs_version()))
        try:
            return _capstone_version()
        except (KeyError, ImportWarning):
            return "Not found"

    def keystone_version(self):
        @load_keystone
        def _keystone_version():
            keystone = sys.modules["keystone"]
            return ".".join(map(str, keystone.ks_version()))
        try:
            return _keystone_version()
        except (KeyError, ImportWarning):
            return "Not found"

    def unicorn_version(self):
        @load_unicorn
        def _unicorn_version():
            unicorn = sys.modules["unicorn"]
            return unicorn.__version__
        try:
            return _unicorn_version()
        except (KeyError, ImportWarning):
            return "Not found"

    def ropper_version(self):
        @load_ropper
        def _ropper_version():
            ropper = sys.modules["ropper"]
            return ".".join(map(str, ropper.VERSION))

        try:
            return _ropper_version()
        except (KeyError, ImportWarning):
            return "Not found"

    def gcc_version(self):
        try:
            gcc_command = GefUtil.which("gcc")
        except FileNotFoundError:
            return "Not found"
        res = GefUtil.gef_execute_external([gcc_command, "--version"], as_list=True)
        return res[0]

    def readelf_version(self):
        try:
            readelf_command = GefUtil.which("readelf")
        except FileNotFoundError:
            return "Not found"
        res = GefUtil.gef_execute_external([readelf_command, "-v"], as_list=True)
        return res[0]

    def objdump_version(self):
        try:
            objdump_command = GefUtil.which("objdump")
        except FileNotFoundError:
            return "Not found"
        res = GefUtil.gef_execute_external([objdump_command, "-v"], as_list=True)
        return res[0]

    def seccomp_tools_version(self):
        try:
            seccomp_tools_command = GefUtil.which("seccomp-tools")
        except FileNotFoundError:
            return "Not found"
        res = GefUtil.gef_execute_external([seccomp_tools_command, "--version"], as_list=True)
        return res[0]

    def one_gadget_version(self):
        try:
            one_gadget_command = GefUtil.which("one_gadget")
        except FileNotFoundError:
            return "Not found"
        res = GefUtil.gef_execute_external([one_gadget_command, "--version"], as_list=True)
        return res[0]

    def rp_version(self):
        try:
            rp_lin_command = GefUtil.which("rp-lin")
        except FileNotFoundError:
            return "Not found"
        res = GefUtil.gef_execute_external([rp_lin_command, "--version", "--file", "a"], as_list=True)
        if "You are currently using " in res[0]:
            return res[0].replace("You are currently using ", "")
        return "Not found"

    def show_compact_info(self):
        gef_print("gdb:     {:s}".format(self.gdb_version()))
        gef_print("python:  {:s}".format(self.python_version()))
        gef_print("OS:      {:s}".format(self.os_version()))
        gef_print("kernel:  {:s}".format(self.kernel_version_from_uname()))
        if is_qemu_system():
            gef_print("qemu:    {:s}".format(self.qemu_system_version()))
        return

    def show_full_info(self):
        gef_print(titlify("versions"))
        gef_print("OS:                     {:s}".format(self.os_version()))
        gef_print("kernel (uname -a):      {:s}".format(self.kernel_version_from_uname()))
        gef_print("kernel (/proc/version): {:s}".format(self.kernel_version_from_proc()))
        gef_print("System libc:            {:s}".format(self.system_libc_version()))
        if is_qemu_system():
            gef_print("qemu:                   {:s}".format(self.qemu_system_version()))
        if is_qemu_user():
            gef_print("qemu:                   {:s}".format(self.qemu_user_version()))
        gef_print("GEF:                    {:s}".format(self.gef_version()))
        gef_print("gdb:                    {:s}".format(self.gdb_version()))
        gef_print("python:                 {:s}".format(self.python_version()))
        gef_print("capstone:               {:s}".format(self.capstone_version()))
        gef_print("keystone:               {:s}".format(self.keystone_version()))
        gef_print("unicorn:                {:s}".format(self.unicorn_version()))
        gef_print("ropper:                 {:s}".format(self.ropper_version()))
        gef_print("gcc:                    {:s}".format(self.gcc_version()))
        gef_print("readelf:                {:s}".format(self.readelf_version()))
        gef_print("objdump:                {:s}".format(self.objdump_version()))
        gef_print("seccomp-tools:          {:s}".format(self.seccomp_tools_version()))
        gef_print("one_gadget:             {:s}".format(self.one_gadget_version()))
        gef_print("rp:                     {:s}".format(self.rp_version()))

        gef_print(titlify("gdb build config"))
        gdb.execute("show configuration")
        return

    @parse_args
    def do_invoke(self, args):
        if args.compact:
            self.show_compact_info()
        else:
            self.show_full_info()
        return


@register_command
class HighlightCommand(GenericCommand):
    """The base command to highlight user defined text matches which modifies GEF output universally."""
    _cmdline_ = "highlight"
    _category_ = "01-f. Debugging Support - Context Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("add")
    subparsers.add_parser("remove")
    subparsers.add_parser("list")
    subparsers.add_parser("clear")
    _syntax_ = parser.format_help()

    highlight_table = {}

    @staticmethod
    def highlight_text(text):
        """Highlight text using highlight_table { match -> color } settings.

        If RegEx is enabled it will create a match group around all items in the
        highlight_table and wrap the specified color in the highlight_table
        around those matches.

        If RegEx is disabled, split by ANSI codes and 'colorify' each match found
        within the specified string."""
        if not HighlightCommand.highlight_table:
            return text

        if Config.get_gef_setting("highlight.regex"):
            for match, color in HighlightCommand.highlight_table.items():
                text = re.sub("(" + match + ")", Color.colorify("\\1", color), text)
            return text

        ansiSplit = re.split(r"(\033\[[\d;]*m)", text)
        for match, color in HighlightCommand.highlight_table.items():
            for index, val in enumerate(ansiSplit):
                found = val.find(match)
                if found > -1:
                    ansiSplit[index] = val.replace(match, Color.colorify(match, color))
                    break
            text = "".join(ansiSplit)
            ansiSplit = re.split(r"(\033\[[\d;]*m)", text)
        return "".join(ansiSplit)

    def __init__(self):
        super().__init__(prefix=True)
        self.add_setting("regex", False, "Enable regex highlighting")
        return

    @parse_args
    def do_invoke(self, args):
        self.usage()
        return


@register_command
class HighlightListCommand(GenericCommand):
    """Display the current highlight table with matches to colors."""
    _cmdline_ = "highlight list"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["highlight ls"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    def print_highlight_table(self):
        if not HighlightCommand.highlight_table:
            err("no matches found")
            return

        left_pad = max(map(len, HighlightCommand.highlight_table.keys()))
        for match, color in sorted(HighlightCommand.highlight_table.items()):
            gef_print("{:s} {:s} {:s}".format(
                Color.colorify(match.ljust(left_pad), color),
                VERTICAL_LINE,
                Color.colorify(color, color),
            ))
        return

    @parse_args
    def do_invoke(self, args):
        self.print_highlight_table()
        return


@register_command
class HighlightClearCommand(GenericCommand):
    """Clear the highlight table, remove all matches."""
    _cmdline_ = "highlight clear"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["highlight reset"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        HighlightCommand.highlight_table.clear()
        return


@register_command
class HighlightAddCommand(GenericCommand):
    """Add a match to the highlight table."""
    _cmdline_ = "highlight add"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["highlight set"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("match", metavar="MATCH", help="the keyword phrase to highlight.")
    parser.add_argument("color", metavar="COLOR", nargs="+", help="the color used to highlight.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} "call   rcx" bold yellow'.format(_cmdline_)

    _note_ = "use config `gef config highlight.regex true` if need regex."

    @parse_args
    def do_invoke(self, args):
        HighlightCommand.highlight_table[args.match] = " ".join(args.color)
        return


@register_command
class HighlightRemoveCommand(GenericCommand):
    """Remove a match in the highlight table."""
    _cmdline_ = "highlight remove"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["highlight del", "highlight unset", "highlight rm"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("match", metavar="MATCH", help="the keyword phrase to remove from highlight.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} "call   rcx"'.format(_cmdline_)

    @parse_args
    def do_invoke(self, args):
        HighlightCommand.highlight_table.pop(args.match, None)
        return


class SimpleInternalTemporaryBreakpoint(gdb.Breakpoint):
    """A simple wrapper that takes into account the bug where temporary breakpoints isn't deleted after it is hit."""
    def __init__(self, loc):
        super().__init__("*{:#x}".format(loc), gdb.BP_BREAKPOINT, internal=True, temporary=True)
        return

    def stop(self):
        EventHandler.__gef_check_disabled_bp__ = True
        self.enabled = False

        Cache.reset_gef_caches()
        return True


class SecondBreakpoint(gdb.Breakpoint):
    """Breakpoint which sets a 2nd breakpoint, when hit."""
    def __init__(self, loc, second_loc):
        self.second_loc = second_loc
        super().__init__("*{:#x}".format(loc), gdb.BP_BREAKPOINT, internal=True, temporary=True)
        return

    def stop(self):
        EventHandler.__gef_check_disabled_bp__ = True
        self.enabled = False

        Cache.reset_gef_caches()
        SimpleInternalTemporaryBreakpoint(loc=self.second_loc)
        return True


@register_command
class NiCommand(GenericCommand):
    """`ni` wrapper for specific arch.
    or1k: branch operations don't work well, so use breakpoints to simulate.
    cris: si/ni commands don't work well. so use breakpoints to simulate."""
    _cmdline_ = "nexti-for-qemu-user"
    _category_ = "01-c. Debugging Support - Basic Command Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("args", metavar="ARGS", nargs="*",
                        help="An array of arguments to pass as is to the nexti command. (default: %(default)s)")
    _syntax_ = parser.format_help()

    _note_ = "Only when qemu-user with specific arch, the `ni` command is redirected to `nexti-for-qemu-user`.\n"
    _note_ += "This setting is done only once, when hook_stop_handler is called for the first time."

    def ni_set_bp_for_branch(self):
        target = None
        delay_slot = False

        try:
            frame = gdb.selected_frame()
        except gdb.error:
            # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
            frame = None

        insn = get_insn()
        insn_next = get_insn_next()

        if insn and current_arch.is_jump(insn):
            target = ContextCommand.get_branch_addr(insn)
            delay_slot = current_arch.has_delay_slot
        elif insn and current_arch.is_ret(insn):
            target = current_arch.get_ra(insn, frame)
            delay_slot = current_arch.has_ret_delay_slot

        if target is None:
            return

        # something wrong if infinity loop under cris architecture
        if is_cris() and target == insn.address:
            SecondBreakpoint(loc=insn_next.address, second_loc=target)
            return

        SimpleInternalTemporaryBreakpoint(loc=target)
        if delay_slot:
            SimpleInternalTemporaryBreakpoint(loc=insn_next.address)
        return

    def ni_set_bp_next(self):
        insn_next = get_insn_next()
        SimpleInternalTemporaryBreakpoint(loc=insn_next.address)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-user",))
    @only_if_specific_arch(arch=("OR1K", "CRIS"))
    def do_invoke(self, args):
        if is_cris():
            self.ni_set_bp_for_branch()
            self.ni_set_bp_next()
            gdb.execute("c") # use c wrapper
            return

        if is_or1k():
            self.ni_set_bp_for_branch()

        cmd = "nexti " + " ".join(args.args)
        try:
            gdb.execute(cmd.rstrip())
        except gdb.error:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            if str(exc_value).startswith("Cannot access memory at address"):
                if is_valid_addr(current_arch.pc):
                    gdb.execute("xuntil")
                else:
                    err(exc_value)
            else:
                err(exc_value)
        return


@register_command
class SiCommand(GenericCommand):
    """`si` wrapper for specific arch.
    or1k: branch operations don't work well, so use breakpoints to simulate.
    cris: si/ni commands don't work well. so use breakpoints to simulate."""
    _cmdline_ = "stepi-for-qemu-user"
    _category_ = "01-c. Debugging Support - Basic Command Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("args", metavar="ARGS", nargs="*",
                        help="An array of arguments to pass as is to the stepi command. (default: %(default)s)")
    _syntax_ = parser.format_help()

    _note_ = "Only when qemu-user with specific arch, the `si` command is redirected to `stepi-for-qemu-user`.\n"
    _note_ += "This setting is done only once, when hook_stop_handler is called for the first time."

    def si_set_bp_for_branch(self):
        target = None
        delay_slot = False

        try:
            frame = gdb.selected_frame()
        except gdb.error:
            # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
            frame = None

        insn = get_insn()
        insn_next = get_insn_next()

        if insn and current_arch.is_jump(insn) or current_arch.is_call(insn): # si also stops at `call` target
            target = ContextCommand.get_branch_addr(insn)
            delay_slot = current_arch.has_delay_slot
        elif insn and current_arch.is_ret(insn):
            target = current_arch.get_ra(insn, frame)
            delay_slot = current_arch.has_ret_delay_slot

        if target is None:
            return

        # something wrong if infinity loop under cris architecture
        if is_cris() and target == insn.address:
            SecondBreakpoint(loc=insn_next.address, second_loc=target)
            return

        SimpleInternalTemporaryBreakpoint(loc=target)
        if delay_slot:
            SimpleInternalTemporaryBreakpoint(loc=insn_next.address)
        return

    def si_set_bp_next(self):
        insn_next = get_insn_next()
        SimpleInternalTemporaryBreakpoint(loc=insn_next.address)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-user",))
    @only_if_specific_arch(arch=("OR1K", "CRIS"))
    def do_invoke(self, args):
        if is_cris():
            self.si_set_bp_for_branch()
            self.si_set_bp_next()
            gdb.execute("c") # use c wrapper
            return

        if is_or1k():
            self.si_set_bp_for_branch()

        cmd = "stepi " + " ".join(args.args)
        try:
            gdb.execute(cmd.rstrip())
        except gdb.error:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            if str(exc_value).startswith("Cannot access memory at address"):
                if is_valid_addr(current_arch.pc):
                    gdb.execute("xuntil")
                else:
                    err(exc_value)
            else:
                err(exc_value)
        return


@register_command
class ContCommand(GenericCommand):
    """`c` wrapper to solve the problem that Ctrl+C cannot interrupt when using gdb stub of qemu-user or Intel Pin."""
    _cmdline_ = "continue-for-qemu-user"
    _category_ = "01-c. Debugging Support - Basic Command Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("args", metavar="ARGS", nargs="*",
                        help="An array of arguments to pass as is to the continue command. (default: %(default)s)")
    _syntax_ = parser.format_help()

    _note_ = "Only when qemu-user or pin, the `c` command is redirected to `continue-for-qemu-user`.\n"
    _note_ += "This setting is done only once, when hook_stop_handler is called for the first time.\n"
    _note_ += "Nested `c` command causes a problem, so in that case gef executes the original continue command instead."

    def __init__(self):
        super().__init__()
        self.nest_count = 0
        return

    def continue_for_qemu(self):
        import signal
        import threading
        thread_started = False
        thread_finished = False

        pid = Pid.get_pid()

        def continue_thread():
            nonlocal thread_started, thread_finished
            thread_started = True
            try:
                gdb.execute("continue")
            except gdb.error:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                err(exc_value)
            thread_finished = True
            return

        def sig_handler(_signum, _frame):
            # do not use get_pid() in this func.
            # get_pid() uses `maintenance packet` command internally,
            # but it cannot be used when the non-static program is running.
            os.kill(pid, signal.SIGTRAP)
            return

        th = threading.Thread(target=continue_thread, daemon=True)
        th.start()
        while thread_started is False:
            time.sleep(0.1)
        old = signal.signal(signal.SIGINT, sig_handler)
        while thread_finished is False:
            time.sleep(0.1)
        th.join()
        signal.signal(signal.SIGINT, old)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-user", "pin"))
    def do_invoke(self, args):
        if is_qemu_user() or is_pin():
            if Pid.get_pid():
                if self.nest_count == 0:
                    self.nest_count += 1
                    self.continue_for_qemu()
                    self.nest_count -= 1
                    return

        # fall back to original continue command
        try:
            cmd = "continue " + " ".join(args.args)
            gdb.execute(cmd.rstrip())
        except gdb.error:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err(exc_value)
        return


@register_command
class UpCommand(GenericCommand):
    """`up` wrapper."""
    _cmdline_ = "up"
    _category_ = "01-c. Debugging Support - Basic Command Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("n", metavar="N", nargs="?", type=int, default=1,
                        help="Number of frames to move. (default: %(default)s)")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        try:
            current_frame = gdb.selected_frame()
        except gdb.error:
            # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
            err("Failed to get frame information.")
            return

        # check if target frame is available
        n = args.n
        while current_frame and n:
            if not current_frame.is_valid():
                break
            current_frame = current_frame.older()
            n -= 1

        # go to target frame
        if n == 0 and current_frame:
            current_frame.select()

        # back up
        nb_lines_backtrace_before = Config.get_gef_setting("context.nb_lines_backtrace_before")
        nb_lines_backtrace = Config.get_gef_setting("context.nb_lines_backtrace")

        # change temporarily
        Config.set_gef_setting("context.nb_lines_backtrace_before", 0x100)
        Config.set_gef_setting("context.nb_lines_backtrace", 0x100)

        # print
        gdb.execute("context trace")

        # restore
        Config.set_gef_setting("context.nb_lines_backtrace_before", nb_lines_backtrace_before)
        Config.set_gef_setting("context.nb_lines_backtrace", nb_lines_backtrace)
        return


@register_command
class DownCommand(GenericCommand):
    """`down` wrapper."""
    _cmdline_ = "down"
    _category_ = "01-c. Debugging Support - Basic Command Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("n", metavar="N", nargs="?", type=int, default=1,
                        help="Number of frames to move. (default: %(default)s)")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        try:
            current_frame = gdb.selected_frame()
        except gdb.error:
            # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
            err("Failed to get frame information.")
            return

        # check if target frame is available
        n = args.n
        while current_frame and n:
            if not current_frame.is_valid():
                break
            current_frame = current_frame.newer()
            n -= 1

        # go to target frame
        if n == 0 and current_frame:
            current_frame.select()

        # back up
        nb_lines_backtrace_before = Config.get_gef_setting("context.nb_lines_backtrace_before")
        nb_lines_backtrace = Config.get_gef_setting("context.nb_lines_backtrace")

        # change temporarily
        Config.set_gef_setting("context.nb_lines_backtrace_before", 0x100)
        Config.set_gef_setting("context.nb_lines_backtrace", 0x100)

        # print
        gdb.execute("context trace")

        # restore
        Config.set_gef_setting("context.nb_lines_backtrace_before", nb_lines_backtrace_before)
        Config.set_gef_setting("context.nb_lines_backtrace", nb_lines_backtrace)
        return


@register_command
class DisplayTypeCommand(GenericCommand, BufferingOutput):
    """Makes it easier to use `ptype /ox TYPE` and `p ((TYPE*) ADDRESS)[0]`."""
    _cmdline_ = "dt"
    _category_ = "02-h. Process Information - Type"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("type", metavar="TYPE", help="the type name.")
    parser.add_argument("address", metavar="ADDRESS", nargs="?", type=AddressUtil.parse_address,
                        help="the address to apply the type.")
    parser.add_argument("-s", "--smart", action="store_true",
                        help="temporarily override by `context.smart_cpp_function_name = True`.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} "struct malloc_state"        # shortcut for `ptype /ox struct malloc_state`\n'.format(_cmdline_)
    _example_ += '{:s} "struct malloc_state" $rsp   # shortcut for `p ((struct malloc_state*) $rsp)[0]`\n'.format(_cmdline_)

    _note_ = "This command is designed for several purposes.\n"
    _note_ += "1. When displaying very large struct, you may want to go through a pager because the results will not fit on one screen.\n"
    _note_ += "   However, using a pager, the color information disappears. This command calls the pager with preserving colors.\n"
    _note_ += "2. When `ptype /ox TYPE`, interpreting member type recursively often result is too long and difficult to read.\n"
    _note_ += "   This command keeps result compact by displaying only top-level members.\n"
    _note_ += "3. When `p ((TYPE*) ADDRESS)[0]` for large struct, the setting of `max-value-size` is too small to display.\n"
    _note_ += "   This command adjusts it automatically.\n"
    _note_ += "4. When debugging a binary written in the golang, the offset information of the type is not displayed.\n"
    _note_ += "   This command also displays the offset.\n"
    _note_ += "5. When debugging a binary written in the golang, the `p ((TYPE*) ADDRESS)[0]` command will be broken.\n"
    _note_ += "   Because the golang helper script is automatically loaded and overwrites the behavior of `p` command.\n"
    _note_ += "   This command creates the display results on the python side, so we can display it without any problems."

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        # lookup type
        tp = GefUtil.cached_lookup_type(args.type)
        if not args.type.startswith(("struct", "union",  "enum")):
            if tp is None:
                tp = GefUtil.cached_lookup_type("struct {:s}".format(args.type))
            if tp is None:
                tp = GefUtil.cached_lookup_type("union {:s}".format(args.type))
            if tp is None:
                tp = GefUtil.cached_lookup_type("enum {:s}".format(args.type))

        if tp is None:
            err("Not found {:s}".format(args.type))
            return

        # remove pointer
        while str(tp).endswith("*"):
            tp = tp.target()

        if tp.code not in [gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION, gdb.TYPE_CODE_ENUM]:
            err("{:s} is not struct or union or enum".format(tp.name or args.type))
            return

        if args.smart:
            old_smart_setting = Config.get_gef_setting("context.smart_cpp_function_name")
            Config.set_gef_setting("context.smart_cpp_function_name", True)

        if args.address is None:
            if tp.code == gdb.TYPE_CODE_STRUCT:
                type_prefix = "struct"
            elif tp.code == gdb.TYPE_CODE_UNION:
                type_prefix = "union"
            elif tp.code == gdb.TYPE_CODE_ENUM:
                type_prefix = "enum"
            else:
                err("{:s} is not struct or union".format(tp.name or args.type))
                return

            self.out = [
                "{:s} {:s} {{".format(type_prefix, Instruction.smartify_text(tp.name or args.type)),
                "    /* offset | size   */",
            ]
            for name, field in tp.items():
                if tp.code in [gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION]:
                    if hasattr(field, "bitpos") and hasattr(field.type, "sizeof"):
                        offsz_str = "/* {:#06x} | {:#06x} */".format(field.bitpos // 8, field.type.sizeof)
                    elif hasattr(field.type, "sizeof"):
                        offsz_str = "/*        | {:#06x} */".format(field.type.sizeof)
                    elif hasattr(field, "bitpos"):
                        offsz_str = "/* {:#06x} |        */".format(field.bitpos // 8)
                    else:
                        offsz_str = "/*        |        */"
                    type_str = Instruction.smartify_text(str(field.type))
                    name_str = Color.cyanify(Instruction.smartify_text(name))
                    if field.bitsize == 0:
                        msg = "    {:s}    {} {:s};".format(offsz_str, type_str, name_str)
                    else:
                        msg = "    {:s}    {} {:s} : {:d};".format(offsz_str, type_str, name_str, field.bitsize)

                else: # gdb.TYPE_CODE_ENUM
                    offsz_str = "/* {:#06x} | {:#06x} */".format(0, 4)
                    type_str = "int"
                    name_str = Color.cyanify(Instruction.smartify_text(name))
                    msg = "    {:s}    {} {:s} = {:#x};".format(offsz_str, type_str, name_str, field.enumval)

                self.out.append(msg)

            self.out.append("}} // total: {:#x} bytes".format(tp.sizeof))
            self.print_output(args)

        else:
            if not is_valid_addr(args.address):
                err("Memory access error")
                return
            if tp.sizeof > 2200: # 2200 is default value of max-value-size
                gdb.execute("set max-value-size {:#x}".format(tp.sizeof))
            v = gdb.Value(args.address)
            s = v.cast(tp.pointer()).dereference()
            out = s.format_string(styling=True)
            gef_print(out, less=not args.no_pager)

        if args.smart:
            Config.set_gef_setting("context.smart_cpp_function_name", old_smart_setting)
        return


@register_command
class BreakRelativeVirtualAddressCommand(GenericCommand):
    """Set a breakpoint at relative offset from codebase."""
    _cmdline_ = "break-rva"
    _category_ = "01-b. Debugging Support - Breakpoint"
    _aliases_ = ["brva"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("offset", metavar="OFFSET", type=AddressUtil.parse_address,
                        help="the offset from codebase to set a breakpoint.")
    _syntax_ = parser.format_help()

    delayed_breakpoints = set()
    delayed_bp_set = False

    @parse_args
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        elf = Elf.get_elf()
        if not elf.is_valid():
            err("Invalid elf")
            return

        if not elf.is_pie():
            err("No-PIE elf is unsupported")
            return

        if is_alive():
            codebase = ProcessMap.get_section_base_address(Path.get_filepath(append_proc_root_prefix=False))
            if codebase is None:
                codebase = ProcessMap.get_section_base_address(Path.get_filepath_from_info_proc())
            if codebase is None:
                gef_print("Codebase is not found")
                return
            gdb.execute("b *{:#x}".format(codebase + args.offset))
        else:
            # use delayed breakpoints
            BreakRelativeVirtualAddressCommand.delayed_breakpoints.add(args.offset)
            info("Add delayed breakpoint to codebase+{:#x}".format(args.offset))
        return


@register_command
class PrintFormatCommand(GenericCommand):
    """Print bytes format in high level languages."""
    _cmdline_ = "print-format"
    _category_ = "09-c. Misc - Generation"
    _aliases_ = ["pf"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", dest="format", default="py", choices=["py", "c", "js", "asm", "hex", "longhex"],
                        help="the output format. (default: %(default)s)")
    parser.add_argument("-b", dest="bitlen", type=int, default=8, choices=[8, 16, 32, 64],
                        help="the size of bit. (default: %(default)s)")
    parser.add_argument("-l", dest="length", type=AddressUtil.parse_address, default=256,
                        help="the length of array. (default: %(default)s)")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the address of data to dump.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -f py -b 8 -l 256 $rsp".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        """Default value for print-format command."""
        bit_format = {8: "<B", 16: "<H", 32: "<I", 64: "<Q"}
        c_type = {8: "char", 16: "short", 32: "int", 64: "long long"}
        asm_type = {8: "db", 16: "dw", 32: "dd", 64: "dq"}

        if args.format in ["hex", "longhex"] and args.bitlen != 8:
            err("{:s} must be bit == 8".format(args.format))
            return

        unit_size = args.bitlen // 8
        start_addr = args.location
        end_addr = start_addr + args.length * unit_size
        bf = bit_format[args.bitlen]

        # extract memory
        data = []
        for address in range(start_addr, end_addr, unit_size):
            try:
                mem = read_memory(address, unit_size)
            except gdb.MemoryError:
                err("Memory read error")
                return None
            value = struct.unpack(bf, mem)[0]
            data.append(value)

        # parse data
        sdata = ""
        if args.format == "hex":
            for i, x in enumerate(data):
                sdata += "{:02x}".format(x)
                if (i % 16) == 15:
                    sdata += "\n"
        elif args.format == "longhex":
            for x in data:
                sdata += "{:02x}".format(x)
        else:
            for i, x in enumerate(data):
                if (i % 8) == 0:
                    sdata += "    "
                sdata += "{:#0{}x}, ".format(x, args.bitlen // 4 + 2)
                if (i % 8) == 7:
                    sdata += "\n"
        sdata = sdata.rstrip()

        # make format
        if args.format == "py":
            out = "buf = [\n{:s}\n]".format(sdata)
        elif args.format == "c":
            out = "unsigned {:s} buf[{:d}] = {{\n{:s}\n}};".format(c_type[args.bitlen], args.length, sdata)
        elif args.format == "js":
            out = "var buf = [\n{:s}\n];".format(sdata)
        elif args.format == "asm":
            out = "buf {:s}\n{:s}".format(asm_type[args.bitlen], sdata)
        elif args.format in ["hex", "longhex"]:
            out = sdata

        gef_print(out)
        return


@register_command
class CanaryCommand(GenericCommand):
    """Display the canary value of the current process from auxv information."""
    _cmdline_ = "canary"
    _category_ = "02-f. Process Information - Security"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @staticmethod
    @Cache.cache_this_session
    def gef_read_canary():
        """Read the canary of a running process using Auxiliary Vector.
        Return a tuple of (canary, location) if found, None otherwise."""
        auxval = Auxv.get_auxiliary_values()
        if not auxval:
            return None
        try:
            canary_location = auxval["AT_RANDOM"]
            canary = read_int_from_memory(canary_location)
            canary &= ~0xFF
            return canary, canary_location
        except (KeyError, gdb.MemoryError):
            return None

    def dump_canary(self):
        res = CanaryCommand.gef_read_canary()
        if not res:
            err("Failed to get the canary")
            return

        canary, location = res
        gef_print(titlify("canary value"))
        info("Found AT_RANDOM at {!s}, reading {} bytes".format(ProcessMap.lookup_address(location), current_arch.ptrsize))
        info("The canary is {:s}".format(Color.boldify("{:#x}".format(canary))))

        gef_print(titlify("found canary"))
        vmmap = ProcessMap.get_process_maps()
        unpack = u32 if current_arch.ptrsize == 4 else u64
        sp = current_arch.sp
        for m in vmmap:
            if not (m.permission & Permission.READ) or not (m.permission & Permission.WRITE):
                continue
            if m.path in ["[vvar]", "[vsyscall]", "[vectors]", "[sigpage]"]:
                continue
            try:
                data = read_memory(m.page_start, m.page_end - m.page_start)
            except gdb.MemoryError:
                continue
            prev_addr = -1
            for pos in range(0, m.page_end - m.page_start, current_arch.ptrsize):
                addr = m.page_start + pos
                d = data[pos: pos + current_arch.ptrsize]
                if canary != unpack(d):
                    continue
                if m.path == "":
                    path = "unknown"
                else:
                    path = m.path
                if prev_addr <= sp <= addr:
                    info("(Stack pointer is at {!s})".format(ProcessMap.lookup_address(sp)))
                if path == "[stack]":
                    info("Found at {!s} in {!r} (sp{:+#x})".format(ProcessMap.lookup_address(addr), path, addr - sp))
                else:
                    info("Found at {!s} in {!r}".format(ProcessMap.lookup_address(addr), path))
                prev_addr = addr
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        self.dump_canary()
        return


@register_command
class AuxvCommand(GenericCommand):
    """Display ELF auxiliary vectors."""
    _cmdline_ = "auxv"
    _category_ = "02-d. Process Information - Trivial Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--force-heuristic", action="store_true", help="use heuristic detection.")
    _syntax_ = parser.format_help()

    AT_CONSTANTS = {
        0  : "AT_NULL",              # End of vector
        1  : "AT_IGNORE",            # Entry should be ignored
        2  : "AT_EXECFD",            # File descriptor of program
        3  : "AT_PHDR",              # Program headers for program
        4  : "AT_PHENT",             # Size of program header entry
        5  : "AT_PHNUM",             # Number of program headers
        6  : "AT_PAGESZ",            # System page size
        7  : "AT_BASE",              # Base address of interpreter
        8  : "AT_FLAGS",             # Flags
        9  : "AT_ENTRY",             # Entry point of program
        10 : "AT_NOTELF",            # Program is not ELF
        11 : "AT_UID",               # Real uid
        12 : "AT_EUID",              # Effective uid
        13 : "AT_GID",               # Real gid
        14 : "AT_EGID",              # Effective gid
        15 : "AT_PLATFORM",          # String identifying platform
        16 : "AT_HWCAP",             # Machine dependent hints about processor capabilities
        17 : "AT_CLKTCK",            # Frequency of times()
        18 : "AT_FPUCW",             #
        19 : "AT_DCACHEBSIZE",       #
        20 : "AT_ICACHEBSIZE",       #
        21 : "AT_UCACHEBSIZE",       #
        22 : "AT_IGNOREPPC",         # A special ignored type value for PPC, for glibc compatibility
        23 : "AT_SECURE",            #
        24 : "AT_BASE_PLATFORM",     # String identifying real platforms
        25 : "AT_RANDOM",            # Address of 16 random bytes
        26 : "AT_HWCAP2",            # extension of AT_HWCAP
        27 : "AT_RSEQ_FEATURE_SIZE", # seq supported feature size
        28 : "AT_RSEQ_ALIGN",        # rseq allocation alignment
        31 : "AT_EXECFN",            # Filename of executable
        32 : "AT_SYSINFO",           #
        33 : "AT_SYSINFO_EHDR",      #
        34 : "AT_L1I_CACHESHAPE",    #
        35 : "AT_L1D_CACHESHAPE",    #
        36 : "AT_L2_CACHESHAPE",     #
        37 : "AT_L3_CACHESHAPE",     #
        40 : "AT_L1I_CACHESIZE",     #
        41 : "AT_L1I_CACHEGEOMETRY", #
        42 : "AT_L1D_CACHESIZE",     #
        43 : "AT_L1D_CACHEGEOMETRY", #
        44 : "AT_L2_CACHESIZE",      #
        45 : "AT_L2_CACHEGEOMETRY",  #
        46 : "AT_L3_CACHESIZE",      #
        47 : "AT_L3_CACHEGEOMETRY",  #
        51 : "AT_MINSIGSTKSZ",       # stack needed for signal delivery
    }

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        auxval = Auxv.get_auxiliary_values(args.force_heuristic)
        if not auxval:
            return None

        reverse_AT_CONSTS = {v: "{:#04x}".format(k) for k, v in self.AT_CONSTANTS.items()}

        gef_print(titlify("ELF auxiliary vector"))
        fmt = "{:6s} {:22s} {:s}"
        legend = ["Const", "Name", "Value"]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        for k, v in auxval.items():
            num = reverse_AT_CONSTS.get(k, "?")
            additional_message = ""
            if k == "AT_NULL":
                additional_message = " (End of vector)"
            elif k in ["AT_EXECFN", "AT_PLATFORM"]:
                s = read_cstring_from_memory(v)
                if s is None:
                    s = "Cannot access memory"
                s = Color.yellowify(repr(s))
                additional_message = "{:s}{:s}".format(RIGHT_ARROW, s)
            elif k in ["AT_RANDOM"]:
                try:
                    if is_64bit():
                        s1 = read_int_from_memory(v + current_arch.ptrsize * 0)
                        s2 = read_int_from_memory(v + current_arch.ptrsize * 1)
                        additional_message = "{:s}{:#018x}, {:#018x}".format(RIGHT_ARROW, s1, s2)
                    else:
                        s1 = read_int_from_memory(v + current_arch.ptrsize * 0)
                        s2 = read_int_from_memory(v + current_arch.ptrsize * 1)
                        s3 = read_int_from_memory(v + current_arch.ptrsize * 2)
                        s4 = read_int_from_memory(v + current_arch.ptrsize * 3)
                        additional_message = "{:s}{:#010x}, {:#010x}, {:#010x}, {:#010x}".format(
                            RIGHT_ARROW, s1, s2, s3, s4,
                        )
                except gdb.MemoryError:
                    s = Color.yellowify(repr("Cannot access memory"))
                    additional_message = "{:s}{:s}".format(RIGHT_ARROW, s)

            if is_valid_addr(v):
                v = str(ProcessMap.lookup_address(v))
            else:
                v = hex(v)
            gef_print("{:6s} {:22s} {:s}{:s}".format(num, k + ":", v, additional_message))
        return


@register_command
class ArgvCommand(GenericCommand, BufferingOutput):
    """Display argv."""
    _cmdline_ = "argv"
    _category_ = "02-d. Process Information - Trivial Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="print all elements. (default: outputs up to 100)")
    parser.add_argument("-i", "--increase-limit", action="store_true",
                        help="increase rounding limit from 128 bytes to 4096 bytes.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def get_address_from_symbol(self, symbol):
        try:
            return AddressUtil.parse_address(symbol)
        except Exception:
            return None

    def print_from_mem(self, array, verbose, increase_limit):
        fmt = "{:3s} {:{:d}s}  {:{:d}s}{:s}{:s}"
        legend = [
            "#",
            "ArrAddr", AddressUtil.get_format_address_width(),
            "StrAddr", AddressUtil.get_format_address_width(),
            RIGHT_ARROW, "String",
        ]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        max_size = gef_getpagesize() if increase_limit else 128

        i = 0
        while True:
            pos = array + i * current_arch.ptrsize
            addr = read_int_from_memory(pos)
            if addr == 0:
                break
            if not verbose and i >= 100:
                self.out.append("...")
                break

            s = read_cstring_from_memory(addr, gef_getpagesize())
            s = Color.yellowify(repr(s))
            if len(s) > max_size:
                s = s[:max_size] + "[...]"

            self.out.append("{:03d} {!s}: {!s}{:s}{:s}".format(
                i,
                ProcessMap.lookup_address(pos),
                ProcessMap.lookup_address(addr),
                RIGHT_ARROW, s,
            ))
            i += 1
        return

    def print_from_proc(self, filename, verbose, increase_limit):
        fmt = "{:3s} {:s}"
        legend = ["#", "String"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        max_size = gef_getpagesize() if increase_limit else 128

        lines = open(filename, "rb").read()
        lines = String.bytes2str(lines)
        for i, elem in enumerate(lines.split("\0")):
            if not elem:
                break
            if not verbose and i >= 100:
                self.out.append("...")
                break

            if len(elem) > max_size:
                elem = elem[:max_size] + "[...]"
            self.out.append("{:03d} {!s}".format(i, elem))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        self.out = []

        paddr1 = self.get_address_from_symbol("&_dl_argv")
        addr1 = self.get_address_from_symbol("_dl_argv")
        if paddr1 and addr1:
            self.out.append(titlify("ARGV from _dl_argv"))
            self.info("_dl_argv @ {}".format(ProcessMap.lookup_address(paddr1)))
            self.print_from_mem(addr1, args.verbose, args.increase_limit)

        paddr2 = self.get_address_from_symbol("&__libc_argv")
        addr2 = self.get_address_from_symbol("__libc_argv")
        if paddr2 and addr2:
            self.out.append(titlify("ARGV from __libc_argv"))
            self.info("__libc_argv @ {}".format(ProcessMap.lookup_address(paddr2)))
            self.print_from_mem(addr2, args.verbose, args.increase_limit)

        if not is_remote_debug():
            self.out.append(titlify("ARGV from /proc/{:d}/cmdline".format(Pid.get_pid())))
            self.print_from_proc("/proc/{:d}/cmdline".format(Pid.get_pid()), args.verbose, args.increase_limit)
        else:
            if not (paddr1 or paddr2):
                self.err("Not found argv")

        self.print_output(args, term=True)
        return


@register_command
class EnvpCommand(GenericCommand, BufferingOutput):
    """Display initial envp from __environ@ld, or modified envp from last_environ@libc."""
    _cmdline_ = "envp"
    _category_ = "02-d. Process Information - Trivial Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="print all elements. (default: outputs up to 100)")
    parser.add_argument("-i", "--increase-limit", action="store_true",
                        help="increase rounding limit from 128 bytes to 4096 bytes.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def get_address_from_symbol(self, symbol):
        try:
            return AddressUtil.parse_address(symbol)
        except Exception:
            return None

    def print_from_mem(self, array, verbose, increase_limit):
        fmt = "{:3s} {:{:d}s}  {:{:d}s}{:s}{:s}"
        legend = [
            "#",
            "ArrAddr", AddressUtil.get_format_address_width(),
            "StrAddr", AddressUtil.get_format_address_width(),
            RIGHT_ARROW, "String",
        ]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        max_size = gef_getpagesize() if increase_limit else 128

        i = 0
        while True:
            pos = array + i * current_arch.ptrsize
            addr = read_int_from_memory(pos)
            if addr == 0:
                break
            if not verbose and i >= 100:
                self.out.append("...")
                break

            s = read_cstring_from_memory(addr, gef_getpagesize())
            s = Color.yellowify(repr(s))
            if len(s) > max_size:
                s = s[:max_size] + "[...]"

            self.out.append("{:03d} {!s}: {!s}{:s}{:s}".format(
                i,
                ProcessMap.lookup_address(pos),
                ProcessMap.lookup_address(addr),
                RIGHT_ARROW, s,
            ))
            i += 1
        return

    def print_from_proc(self, filename, verbose, increase_limit):
        fmt = "{:3s} {:s}"
        legend = ["#", "Name=Value"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        max_size = gef_getpagesize() if increase_limit else 128

        lines = open(filename, "rb").read()
        lines = String.bytes2str(lines)
        for i, elem in enumerate(lines.split("\0")):
            if not elem:
                break
            if not verbose and i >= 100:
                self.out.append("...")
                break
            elem = re.sub(r"^(.*?=)", Color.boldify("\\1"), elem)
            if len(elem) > max_size:
                elem = elem[:max_size] + "[...]"
            self.out.append("{:03d} {:s}".format(i, elem))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        self.out = []

        self.out.append(titlify("ENVP from __environ"))
        paddr = self.get_address_from_symbol("&__environ")
        addr = self.get_address_from_symbol("__environ")
        if paddr and addr:
            self.info("__environ @ {}".format(ProcessMap.lookup_address(paddr)))
            self.print_from_mem(addr, args.verbose, args.increase_limit)
        elif addr == 0:
            self.err("___environ is 0x0")
        else:
            self.err("Not found __environ")

        self.out.append(titlify("ENVP from last_environ (for putenv, etc.)"))
        paddr = self.get_address_from_symbol("&last_environ")
        addr = self.get_address_from_symbol("last_environ")
        if paddr and addr:
            self.info("last_environ @ {}".format(ProcessMap.lookup_address(paddr)))
            self.print_from_mem(addr, args.verbose, args.increase_limit)
        elif addr == 0:
            self.err("last_environ is 0x0")
        else:
            self.err("Not found last_environ")

        if not is_remote_debug():
            self.out.append(titlify("ENVP from /proc/{:d}/environ".format(Pid.get_pid())))
            self.print_from_proc("/proc/{:d}/environ".format(Pid.get_pid()), args.verbose, args.increase_limit)

        self.print_output(args, term=True)
        return


@register_command
class DumpArgsCommand(GenericCommand):
    """Dump arguments of current function."""
    _cmdline_ = "dumpargs"
    _category_ = "02-d. Process Information - Trivial Information"
    _aliases_ = ["args"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-c", "--count", type=lambda x: int(x, 0), help="number of arguments to guess.")
    parser.add_argument("-o", "--out-of-function", action="store_true", help="assume here is out of the function.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        gef_print(titlify("info args (snapshot)"))
        gdb.execute("info args")

        gef_print(titlify("guessed arguments (current value)"))
        ret = gdb.execute("info args", to_string=True).strip()
        if args.count is not None:
            count = args.count
        elif "No symbol table info available" in ret:
            count = len(current_arch.function_parameters)
        else:
            count = len(ret.splitlines())

        for i in range(count):
            key, val = current_arch.get_ith_parameter(i, in_func=not args.out_of_function)

            width = len(key)
            while width % 4:
                width += 1
            gef_print("{:>{:d}s} = {:s}".format(key, width, AddressUtil.recursive_dereference_to_string(val)))
        return


@register_command
class VdsoCommand(GenericCommand, BufferingOutput):
    """Disassemble the text area of vdso smartly."""
    _cmdline_ = "vdso"
    _category_ = "02-d. Process Information - Trivial Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        # get map entry
        maps = ProcessMap.get_process_maps()
        if maps is None:
            err("Failed to get maps")
            return

        for entry in maps:
            if entry.path == "[vdso]":
                break
        else:
            err("vdso is not found")
            return

        # get dump area
        elf = Elf.get_elf(entry.page_start)
        if not elf or not elf.is_valid:
            err("parse failed")
            return
        shdr = elf.get_shdr(".text")

        text_start = entry.page_start + shdr.sh_addr
        text_size = shdr.sh_size
        text_end = text_start + text_size

        # disassemble
        try:
            __import__("capstone")
            ret = gdb.execute("capstone-disassemble {:#x} -l {:#x}".format(text_start, text_size), to_string=True)
            result_lines = ret.splitlines()
        except ImportError:
            gen = Disasm.gdb_disassemble(text_start, end_pc=text_end - 1)
            result_lines = [str(x) for x in gen]

        self.out = []
        for line in result_lines:
            if int(Color.remove_color(line.split()[0]), 16) < text_end:
                self.out.append(line)
            else:
                break

        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class VvarCommand(GenericCommand):
    """Dump the area of vvar (only x64/x86)."""
    _cmdline_ = "vvar"
    _category_ = "02-d. Process Information - Trivial Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    def read(self, addr, size):
        if is_x86_64():
            block_size = 128
            dynamic_read = current_arch.read128
        elif is_x86_32():
            block_size = 28
            dynamic_read = current_arch.read28

        out = b""
        pos = 0
        while pos < size:
            out += dynamic_read(addr + pos)
            pos += block_size
        return out[:size]

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "rr"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        # get map entry
        maps = ProcessMap.get_process_maps()
        if maps is None:
            err("Failed to get maps")
            return

        for entry in maps:
            if entry.path == "[vvar]":
                break
        else:
            err("vvar is not found")
            return

        # dump
        # arch/x86/include/asm/vvar.h
        self.out = []
        start = entry.page_start + 128 # DECLARE_VVAR(128, struct vdso_data, _vdso_data)
        size = 0x180 # >= sizeof(struct vdso_data)
        data = self.read(start, size)
        hex_data = hexdump(data, base=start, unit=current_arch.ptrsize)
        self.out.extend(hex_data.splitlines())

        # print
        if self.out:
            gef_print("\n".join(self.out).rstrip())
        return


@register_command
class IouringDumpCommand(GenericCommand):
    """Dump the area of iouring (only x64)."""
    _cmdline_ = "iouring-dump"
    _category_ = "02-e. Process Information - Complex Structure Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    def read(self, addr, size):
        block_size = 128
        dynamic_read = current_arch.read128

        out = b""
        pos = 0
        while pos < size:
            out += dynamic_read(addr + pos)
            pos += block_size
        return out[:size]

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "rr", "wine"))
    @only_if_specific_arch(arch=("x86_64",))
    def do_invoke(self, args):
        # get map entry
        maps = ProcessMap.get_process_maps()
        if maps is None:
            err("Failed to get maps")
            return

        # get anon_inode:[io_uring]
        iouring_entries = []
        for entry in maps:
            if entry.path == "anon_inode:[io_uring]":
                iouring_entries.append(entry)

        # dump
        self.out = []
        for entry in iouring_entries:
            if entry.offset in [0, 0x8000000]: # IORING_OFF_SQ_RING ,IORING_OFF_CQ_RING
                self.out.append(titlify("struct io_rings: {:#x}".format(entry.page_start)))
            elif entry.offset == 0x10000000: # IORING_OFF_SQES
                self.out.append(titlify("struct io_uring_sqe: {:#x}".format(entry.page_start)))

            data = self.read(entry.page_start, entry.size)
            hex_data = hexdump(data, base=entry.page_start, unit=current_arch.ptrsize)
            hex_data_merged = HexdumpCommand.merge_lines(hex_data.splitlines(), nb_skip_merge=0x10)
            self.out.extend(hex_data_merged)

        # print
        if self.out:
            gef_print("\n".join(self.out).rstrip())
        return


@register_command
class PidCommand(GenericCommand):
    """Display the local PID or remote PID."""
    _cmdline_ = "pid"
    _category_ = "02-d. Process Information - Trivial Information"
    _aliases_ = ["getpid"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        pid = Pid.get_pid()
        if pid:
            if is_qemu_user() or is_qemu_system():
                gef_print("Local qemu PID: {:d}".format(pid))
            else:
                gef_print("Local PID: {:d}".format(pid))
            return

        if is_remote_debug():
            pid = Pid.get_pid(remote=True)
            if pid:
                gef_print("Remote PID: {:d}".format(pid))
                return

        err("Failed to get pid")
        return


@register_command
class TidCommand(GenericCommand):
    """Display the Thread ID."""
    _cmdline_ = "tid"
    _category_ = "02-d. Process Information - Trivial Information"
    _aliases_ = ["gettid"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        ptid = gdb.selected_thread().ptid
        gef_print("TID: {:d}".format(ptid[1] or ptid[2]))
        return


@register_command
class FilenameCommand(GenericCommand):
    """Display current debugged filename."""
    _cmdline_ = "filename"
    _category_ = "02-d. Process Information - Trivial Information"
    _aliases_ = ["getfile"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        filepath = Path.get_filepath()
        if filepath:
            gef_print(repr(filepath))
            return

        elif is_remote_debug():
            filepath = gdb.current_progspace().filename
            if filepath and filepath.startswith("target:"):
                filepath = filepath[7:]
            if filepath:
                gef_print(repr(filepath))
                return

        err("Failed to get filename")
        return


@register_command
class ProcInfoCommand(GenericCommand):
    """Extend the info given by GDB `info proc`."""
    _cmdline_ = "proc-info"
    _category_ = "02-a. Process Information - General"
    _aliases_ = ["pr"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    def get_state_of(self, pid):
        try:
            status = open("/proc/{}/status".format(pid), "r").read()
        except (FileNotFoundError, OSError):
            return {}
        res = {}
        for line in status.splitlines():
            key, value = line.split(":", 1)
            res[key.strip()] = value.strip()
        return res

    def get_stat_of(self, pid):
        try:
            stat = open("/proc/{}/stat".format(pid), "r").read()
        except (FileNotFoundError, OSError):
            return []
        name = re.search(r"\((.+)\)", stat)
        other = re.sub(r"\(.+\) ", "", stat).split()
        res = [int(other[0]), name, other[1]] + [int(x) for x in other[2:]]
        return res

    def get_cmdline_of(self, pid):
        try:
            cmdline = open("/proc/{}/cmdline".format(pid), "r").read()
        except (FileNotFoundError, OSError):
            return ""
        return cmdline.replace("\x00", "\x20").strip()

    def get_process_path_of(self, pid):
        try:
            return os.readlink("/proc/{}/exe".format(pid))
        except (FileNotFoundError, OSError):
            return "Not found"

    def get_process_cwd(self, pid):
        try:
            return os.readlink("/proc/{}/cwd".format(pid))
        except (FileNotFoundError, OSError):
            return "Not found"

    def get_process_root(self, pid):
        try:
            return os.readlink("/proc/{}/root".format(pid))
        except (FileNotFoundError, OSError):
            return "Not found"

    def get_thread_ids(self, pid):
        try:
            tids = os.listdir("/proc/{}/task".format(pid))
            return [int(x) for x in tids]
        except (FileNotFoundError, OSError):
            return []

    def get_children_pids(self, pid):
        try:
            ps = GefUtil.which("ps")
        except FileNotFoundError as e:
            err("{}".format(e))
            return []

        cmd = [ps, "-o", "pid", "--ppid", "{}".format(pid), "--noheaders"]
        try:
            return [int(x) for x in GefUtil.gef_execute_external(cmd, as_list=True)]
        except (subprocess.CalledProcessError, ValueError):
            return []

    def get_uid_map(self, pid):
        try:
            uid_map = open("/proc/{}/uid_map".format(pid), "r").read().strip()
        except (FileNotFoundError, OSError):
            return []
        return slicer([int(x) for x in uid_map.split()], 3)

    def get_gid_map(self, pid):
        try:
            gid_map = open("/proc/{}/gid_map".format(pid), "r").read().strip()
        except (FileNotFoundError, OSError):
            return []
        return slicer([int(x) for x in gid_map.split()], 3)

    def get_tty_str(self, major, minor):
        try:
            devices = open("/proc/devices", "r").read()
        except (FileNotFoundError, OSError):
            return "Not found"
        for line in devices.splitlines():
            if not line or line.endswith(":"):
                continue
            n, name = line.strip().split()
            if major == int(n):
                if not name.startswith("/dev"):
                    name = os.path.join("/dev", name)
                break
        else:
            return "Not found"

        def get_major_minor(name):
            devnum = os.stat(name).st_rdev
            major = (devnum >> 8) & 0xff
            minor = devnum & 0xff
            return major, minor

        if not os.path.exists(name):
            return "Not found"

        if os.path.islink(name):
            return "Not found"

        if os.path.isfile(name):
            if get_major_minor(name) == (major, minor):
                return name

        if os.path.isdir(name):
            for root, _dirs, files in os.walk(name, followlinks=False):
                for f in files:
                    path = os.path.join(root, f)
                    if os.path.islink(path):
                        continue
                    if get_major_minor(path) == (major, minor):
                        return path
        return "Not found"

    def show_info_proc(self):
        gef_print(titlify("Process Information"))

        pid = Pid.get_pid()
        executable = self.get_process_path_of(pid)
        cmdline = self.get_cmdline_of(pid)
        cwd = self.get_process_cwd(pid)
        root = self.get_process_root(pid)
        gef_print("{:32s} {} {}".format("PID", RIGHT_ARROW, pid))
        gef_print("{:32s} {} {}".format("  Executable", RIGHT_ARROW, repr(executable)))
        gef_print("{:32s} {} {}".format("  Command Line", RIGHT_ARROW, repr(cmdline)))
        gef_print("{:32s} {} {}".format("  Current Working Directory", RIGHT_ARROW, repr(cwd)))
        gef_print("{:32s} {} {}".format("  Root Directory", RIGHT_ARROW, repr(root)))
        uids = re.sub(r"\s+", " : ", self.get_state_of(pid)["Uid"])
        gids = re.sub(r"\s+", " : ", self.get_state_of(pid)["Gid"])
        gef_print("{:32s} {} {}".format("  RUID:EUID:SavedUID:FSUID", RIGHT_ARROW, uids))
        gef_print("{:32s} {} {}".format("  RGID:EGID:SavedGID:FSGID", RIGHT_ARROW, gids))
        seccomp_n = self.get_state_of(pid)["Seccomp"]
        seccomp_s = {"0": "Disabled", "1": "Strict", "2": "CustomFilter"}[seccomp_n]
        gef_print("{:32s} {} {} ({})".format("  Seccomp Mode", RIGHT_ARROW, seccomp_n, seccomp_s))
        return

    def show_info_proc_extra(self):
        gef_print(titlify("Process Information Additional"))

        pid = Pid.get_pid()
        pgid = self.get_stat_of(pid)[4]
        pgid_exec = self.get_process_path_of(pgid)
        pgid_cmdline = self.get_cmdline_of(pgid)
        gef_print("{:32s} {} {}".format("Process Group ID", RIGHT_ARROW, pgid))
        gef_print("{:32s} {} {}".format("  Executable", RIGHT_ARROW, repr(pgid_exec)))
        gef_print("{:32s} {} {}".format("  Command Line", RIGHT_ARROW, repr(pgid_cmdline)))
        sid = self.get_stat_of(pid)[5]
        sid_exec = self.get_process_path_of(sid)
        sid_cmdline = self.get_cmdline_of(sid)
        gef_print("{:32s} {} {}".format("Session ID", RIGHT_ARROW, sid))
        gef_print("{:32s} {} {}".format("  Executable", RIGHT_ARROW, repr(sid_exec)))
        gef_print("{:32s} {} {}".format("  Command Line", RIGHT_ARROW, repr(sid_cmdline)))
        tpgid = self.get_stat_of(pid)[7]
        tpgid_exec = self.get_process_path_of(tpgid)
        tpgid_cmdline = self.get_cmdline_of(tpgid)
        gef_print("{:32s} {} {}".format("TTY Process Group ID", RIGHT_ARROW, tpgid))
        gef_print("{:32s} {} {}".format("  Executable", RIGHT_ARROW, repr(tpgid_exec)))
        gef_print("{:32s} {} {}".format("  Command Line", RIGHT_ARROW, repr(tpgid_cmdline)))
        ttynr = self.get_stat_of(pid)[6]
        major, minor = (ttynr >> 8) & 0xff, ((ttynr >> 20) << 8) | (ttynr & 0xff)
        ttystr = self.get_tty_str(major, minor)
        gef_print("{:32s} {} {} ({})".format("  TTY Device Number", RIGHT_ARROW, ttynr, repr(ttystr)))
        return

    def show_parent(self):
        gef_print(titlify("Parent Process Information"))
        ppid = int(self.get_state_of(Pid.get_pid())["PPid"])
        ppid_exec = self.get_process_path_of(ppid)
        ppid_cmdline = self.get_cmdline_of(ppid)
        gef_print("{:32s} {} {}".format("Parent PID", RIGHT_ARROW, ppid))
        gef_print("{:32s} {} {}".format("  Executable", RIGHT_ARROW, repr(ppid_exec)))
        gef_print("{:32s} {} {}".format("  Command Line", RIGHT_ARROW, repr(ppid_cmdline)))
        return

    def show_childs(self):
        gef_print(titlify("Child Process Information"))

        children = self.get_children_pids(Pid.get_pid())
        if not children:
            gef_print("No child process")
            return

        for i, cpid in enumerate(children, start=1):
            cpid_exec = self.get_process_path_of(cpid)
            cpid_cmdline = self.get_cmdline_of(cpid)
            gef_print("{:32s} {} {}".format("Child {} PID".format(i), RIGHT_ARROW, cpid))
            gef_print("{:32s} {} {}".format("  Executable", RIGHT_ARROW, repr(cpid_exec)))
            gef_print("{:32s} {} {}".format("  Command Line", RIGHT_ARROW, repr(cpid_cmdline)))
        return

    def show_info_thread(self):
        gef_print(titlify("Thread Information"))

        pid = Pid.get_pid()
        nthreads = self.get_state_of(pid)["Threads"]
        tgid = self.get_state_of(pid)["Tgid"]
        gef_print("{:32s} {} {}".format("Num of Threads", RIGHT_ARROW, nthreads))
        gef_print("{:32s} {} {}".format("Thread Group ID", RIGHT_ARROW, tgid))
        tids = self.get_thread_ids(pid)
        split = 8
        gef_print("{:32s} {} {}".format("Thread ID List", RIGHT_ARROW, tids[:split]))
        for i in range(split, len(tids), split):
            gef_print("{:32s} {} {}".format("", RIGHT_ARROW, tids[i:i + split]))
        return

    def show_info_proc_ns(self):
        gef_print(titlify("Namespace Information"))

        pid = Pid.get_pid()
        gdb_pid = os.getpid()
        ns_symbols = ["cgroup", "ipc", "mnt", "net", "pid", "time", "user", "uts"]
        for ns in ns_symbols:
            if not os.path.exists("/proc/{:d}/ns/{:s}".format(pid, ns)):
                continue
            if not os.path.exists("/proc/{:d}/ns/{:s}".format(gdb_pid, ns)):
                continue
            sym1 = os.readlink("/proc/{:d}/ns/{:s}".format(pid, ns))
            sym2 = os.readlink("/proc/{:d}/ns/{:s}".format(gdb_pid, ns))
            m = "{:s} namespace separation".format(ns.upper())
            gef_print("{:32s} {:s} {!s}".format(m, RIGHT_ARROW, sym1 != sym2))

        gef_print(titlify("Pid Namespace Information"))
        state = self.get_state_of(pid)
        if len(state["NSpid"].split()) > 1:
            gef_print("{:32s} {} {}".format("Host PID  : Namespace PID", RIGHT_ARROW, re.sub(r"\s+", " : ", state["NSpid"])))
            gef_print("{:32s} {} {}".format("Host PGID : Namespace PGID", RIGHT_ARROW, re.sub(r"\s+", " : ", state["NSpgid"])))
            gef_print("{:32s} {} {}".format("Host SID  : Namespace SID", RIGHT_ARROW, re.sub(r"\s+", " : ", state["NSsid"])))
            gef_print("{:32s} {} {}".format("Host TGID : Namespace TGID", RIGHT_ARROW, re.sub(r"\s+", " : ", state["NStgid"])))
        else:
            gef_print("{:32s}".format("No pid namespace"))

        gef_print(titlify("User Namespace Information"))
        for u in self.get_uid_map(pid):
            gef_print("{:32s} {} [{:#x} : {:#x} : {:#x}]".format("UID_MAP [NameSpace:Host:Range]", RIGHT_ARROW, u[0], u[1], u[2]))
        for g in self.get_gid_map(pid):
            gef_print("{:32s} {} [{:#x} : {:#x} : {:#x}]".format("GID_MAP [NameSpace:Host:Range]", RIGHT_ARROW, g[0], g[1], g[2]))
        return

    def show_fds(self):
        gef_print(titlify("File Descriptors"))

        pid = Pid.get_pid()
        path = "/proc/{:d}/fd".format(pid)

        gef_print("{:32s} {} {}".format("Num of FD slots", RIGHT_ARROW, self.get_state_of(pid)["FDSize"]))
        items = os.listdir(path)
        if not items:
            gef_print("No FD opened")
            return

        for fname in items:
            fullpath = os.path.join(path, fname)
            if os.path.islink(fullpath):
                gef_print("{:32s} {:s} {:s}".format(fullpath, RIGHT_ARROW, os.readlink(fullpath)))
        return

    def list_sockets(self, pid):
        sockets = []
        path = "/proc/{:d}/fd".format(pid)
        items = os.listdir(path)
        for fname in items:
            fullpath = os.path.join(path, fname)
            if os.path.islink(fullpath) and os.readlink(fullpath).startswith("socket:"):
                p = os.readlink(fullpath).replace("socket:", "")[1:-1]
                sockets.append(int(p))
        return sockets

    def parse_ip_port(self, addr):
        ip, port = addr.split(":")
        import socket
        return socket.inet_ntoa(struct.pack("<I", int(ip, 16))), int(port, 16)

    def show_connections(self):
        gef_print(titlify("Network Connections"))

        # https://github.com/torvalds/linux/blob/v4.7/include/net/tcp_states.h#L16
        tcp_states_str = {
            0x01: "TCP_ESTABLISHED",
            0x02: "TCP_SYN_SENT",
            0x03: "TCP_SYN_RECV",
            0x04: "TCP_FIN_WAIT1",
            0x05: "TCP_FIN_WAIT2",
            0x06: "TCP_TIME_WAIT",
            0x07: "TCP_CLOSE",
            0x08: "TCP_CLOSE_WAIT",
            0x09: "TCP_LAST_ACK",
            0x0A: "TCP_LISTEN",
            0x0B: "TCP_CLOSING",
            0x0C: "TCP_NEW_SYN_RECV",
        }

        udp_states_str = {
            0x07: "UDP_LISTEN",
        }

        pid = Pid.get_pid()
        sockets = self.list_sockets(pid)
        if not sockets:
            gef_print("No open connections")
            return

        entries = {}
        entries["TCP"] = [x.split() for x in open("/proc/{:d}/net/tcp".format(pid), "r").readlines()[1:]]
        entries["UDP"] = [x.split() for x in open("/proc/{:d}/net/udp".format(pid), "r").readlines()[1:]]

        for proto in entries:
            for entry in entries[proto]:
                local, remote, state = entry[1:4]
                inode = int(entry[9])
                if inode in sockets:
                    local = self.parse_ip_port(local)
                    remote = self.parse_ip_port(remote)
                    state = int(state, 16)
                    state_str = tcp_states_str[state] if proto == "TCP" else udp_states_str[state]

                    conn_local = "{}:{}".format(local[0], local[1])
                    conn_remote = "{}:{}".format(remote[0], remote[1])
                    gef_print("{:32s} {} {} ({})".format(conn_local, RIGHT_ARROW, conn_remote, state_str))
        return

    @parse_args
    @only_if_gdb_running
    @only_if_gdb_target_local
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "rr"))
    def do_invoke(self, args):
        self.show_info_proc()
        self.show_info_proc_extra()
        self.show_parent()
        self.show_childs()
        self.show_info_thread()
        self.show_info_proc_ns()
        self.show_fds()
        self.show_connections()
        return


@register_command
class FileDescriptorsCommand(GenericCommand):
    """Show opened file descriptors."""
    _cmdline_ = "fds"
    _category_ = "02-a. Process Information - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_gdb_target_local
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        pid = Pid.get_pid()
        path = "/proc/{:d}/fd".format(pid)

        items = os.listdir(path)
        if not items:
            gef_print("No FD opened")
            return

        for fname in items:
            fullpath = os.path.join(path, fname)
            if os.path.islink(fullpath):
                gef_print("{:32s} {:s} {:s}".format(fullpath, RIGHT_ARROW, os.readlink(fullpath)))
        return


@register_command
class ProcDumpCommand(GenericCommand):
    """Dump each file under `/proc/PID`."""
    _cmdline_ = "proc-dump"
    _category_ = "02-a. Process Information - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_gdb_target_local
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        pid = Pid.get_pid()

        self.out = []
        for root, dirs, files in os.walk("/proc/{:d}/".format(pid)):
            dirs = sorted(dirs)
            files = sorted(files)

            if "task" in dirs:
                dirs.remove("task")

            for f in files:
                path = os.path.join(root, f)
                self.out.append(titlify(path))

                if os.path.islink(path):
                    self.out.append(Color.colorify("{:s}{:s}{:s}".format(path, RIGHT_ARROW, os.readlink(path)), "blue"))
                    continue

                if f in ["pagemap", "mem"]:
                    self.out.append("{} skipped".format(Color.colorify("[*]", "bold yellow"))) # too large
                    continue

                if f == "environ":
                    data = open(path, "rb").read()
                    for line in sorted(data.split(b"\0")):
                        if line:
                            line = String.bytes2str(line)
                            key, val = line.split("=", 1)
                            self.out.append("{:s}={:s}".format(Color.boldify(key), val))
                    continue

                if f in ["cmdline", "context"]:
                    data = open(path, "rb").read()
                    for line in data.split(b"\0"):
                        if line:
                            self.out.append(String.bytes2str(line))
                    continue

                if f == "auxv":
                    data = open(path, "rb").read()
                    data = slice_unpack(data, current_arch.ptrsize)
                    for i in range(0, len(data), 2):
                        typ = data[i]
                        val = data[i+1]
                        self.out.append("{:#8x}: {:#x}".format(typ, val))
                    continue

                if f == "syscall":
                    try:
                        data = String.bytes2str(open(path, "rb").read())
                        self.out.append(data.strip())
                    except OSError:
                        continue
                    if int(data.split()[0]) < 0:
                        tag = ["NR", "sp", "pc"]
                    else:
                        tag = ["NR", "arg1", "arg2", "arg3", "arg4", "arg5", "arg6", "sp", "pc"]
                    for i, elem in enumerate(data.split()):
                        if i < len(tag):
                            elem_name = tag[i]
                        else:
                            elem_name = "???"
                        elem_name = Color.boldify("{:4s}".format(elem_name))
                        if i == 0: # NR
                            nr = int(elem)
                            table = get_syscall_table()
                            if nr >= 0 and table and nr in table.table:
                                syscall_name = table.table[nr].name
                                self.out.append("{:2d} {:s}: {:s} ({:s})".format(i + 1, elem_name, elem, syscall_name))
                            else:
                                self.out.append("{:2d} {:s}: {:s}".format(i + 1, elem_name, elem))
                        else: # argN, sp, pc
                            address = int(elem, 0)
                            sym = Symbol.get_symbol_string(address)
                            elem = "{!s}{:s}".format(ProcessMap.lookup_address(address), sym)
                            self.out.append("{:2d} {:s}: {:s}".format(i + 1, elem_name, elem))
                    continue

                if f == "stat":
                    try:
                        data = String.bytes2str(open(path, "rb").read())
                        self.out.append(data.strip())
                    except OSError:
                        continue
                    tag = [
                        "pid", "comm", "state", "ppid", "pgrp", "session", "tty_nr", "tpgid", "flags",
                        "minflt", "cminflt", "majflt", "cmajflt", "utime", "stime", "cutime", "cstime",
                        "priority", "nice", "num_threads", "itrealvalue", "starttime", "vsize",
                        "rss", "rsslim", "startcode", "endcode", "startstack", "kstkesp", "kstkeip",
                        "signal", "blocked", "sigignore", "sigcatch", "wchan", "nswap", "cnswap",
                        "exit_signal", "processor", "rt_priority", "policy", "delayacct_blkio_ticks",
                        "guest_time", "cguest_time", "start_data", "end_data", "start_brk",
                        "arg_start", "arg_end", "env_startr", "env_end", "exit_code",
                    ]
                    max_width = max(len(x) for x in tag)
                    lpos = data.find("(")
                    rpos = data.rfind(")") + 1
                    data = [data[:lpos].strip(), data[lpos:rpos]] + data[rpos:].split()
                    for i, elem in enumerate(data):
                        if i < len(tag):
                            elem_name = tag[i]
                        else:
                            elem_name = "???"
                        elem_name = Color.boldify("{:{:d}s}".format(elem_name, max_width))
                        if i + 1 in [25, 26, 27, 28, 29, 30, 45, 46, 47, 48, 49, 50, 51]:
                            address = int(elem)
                            sym = Symbol.get_symbol_string(address)
                            elem = "{!s}{:s}".format(ProcessMap.lookup_address(address), sym)
                        elif i + 1 in [23, 33, 34]:
                            elem = hex(int(elem))
                        self.out.append("{:2d} {:s}: {:s}".format(i + 1, elem_name, elem))
                    continue

                if f == "statm":
                    try:
                        data = String.bytes2str(open(path, "rb").read())
                        self.out.append(data.strip())
                    except OSError:
                        continue
                    tag = ["size", "resident", "shared", "text", "lib", "data", "dt"]
                    max_width = max(len(x) for x in tag)
                    for i, elem in enumerate(data.split()):
                        if i < len(tag):
                            elem_name = tag[i]
                        else:
                            elem_name = "???"
                        elem_name = Color.boldify("{:{:d}s}".format(elem_name, max_width))
                        self.out.append("{:2d} {:s}: {:s}".format(i + 1, elem_name, elem))
                    continue

                if f == "rt_acct":
                    try:
                        hexdump_command = GefUtil.which("hexdump")
                    except FileNotFoundError as e:
                        self.out.append("{}".format(e))
                        continue
                    ret = GefUtil.gef_execute_external([hexdump_command, "-C", path], as_list=True)
                    self.out.extend(ret)
                    continue

                if f == "status":
                    try:
                        column_command = GefUtil.which("column")
                    except FileNotFoundError as e:
                        self.out.append("{}".format(e))
                        continue
                    ret = GefUtil.gef_execute_external([column_command, "-s:", "-t", path], as_list=True)
                    for line in ret:
                        k, v = line.split(maxsplit=1)
                        k = k.strip() + ":"
                        v = v.replace("\\t", "").strip()
                        self.out.append("{:30s} {:s}".format(k, v))
                    continue

                if f in ["mounts", "mountinfo", "mountstats", "unix", "protocols"]:
                    try:
                        column_command = GefUtil.which("column")
                    except FileNotFoundError as e:
                        self.out.append("{}".format(e))
                        continue
                    ret = GefUtil.gef_execute_external([column_command, "-t", path], as_list=True)
                    self.out.extend(ret)
                    continue

                if f in ["raw", "tcp", "udp", "icmp", "raw6", "tcp6", "udp6", "icmp6", "udplite", "udplite6"]:
                    try:
                        column_command = GefUtil.which("column")
                    except FileNotFoundError as e:
                        self.out.append("{}".format(e))
                        continue
                    data = open(path, "rb").read()
                    data = data.replace(b"tx_queue ", b"tx_queue:")
                    data = data.replace(b" tr ", b" tr:")
                    tmp_fd, tmp_filename = tempfile.mkstemp(dir=GEF_TEMP_DIR, prefix="proc-dump-")
                    os.fdopen(tmp_fd, "wb").write(data)
                    ret = GefUtil.gef_execute_external([column_command, "-t", tmp_filename], as_list=True)
                    os.unlink(tmp_filename)
                    self.out.extend(ret)
                    continue

                if f == "dev":
                    try:
                        column_command = GefUtil.which("column")
                    except FileNotFoundError as e:
                        self.out.append("{}".format(e))
                        continue
                    data = open(path, "rb").read()
                    data = data.replace(b"|", b" |")
                    data = re.sub(rb"\|\s*Receive", b"|Receive", data)
                    data = re.sub(rb"\|\s*Transmit", b"|Transmit", data)
                    tmp_fd, tmp_filename = tempfile.mkstemp(dir=GEF_TEMP_DIR, prefix="proc-dump-")
                    os.fdopen(tmp_fd, "wb").write(data)
                    ret = GefUtil.gef_execute_external([column_command, "-t", tmp_filename], as_list=True)
                    os.unlink(tmp_filename)
                    wrong = ret[0].rfind("|")
                    rright = ret[1].rfind("|")
                    lright = ret[1].find("|")
                    ret[0] = (ret[0][:wrong] + " " * (rright - wrong) + ret[0][wrong:]).rstrip()
                    ret[0] = re.sub(r"\|(\S+)", "| \\1 ", ret[0])
                    ret[1] = re.sub(r"\|(\S+)", "| \\1 ", ret[1])
                    for i in range(2, len(ret)):
                        ret[i] = ret[i][:lright] + "  " + ret[i][lright:]
                        ret[i] = ret[i][:rright] + "  " + ret[i][rright:]
                    self.out.extend(ret)
                    continue

                if f in ["igmp", "fib_trie", "wireless"]:
                    fd = open(path, "rb")
                    for line in fd.readlines():
                        self.out.append(String.bytes2str(line.rstrip())) # no-lstrip
                    continue

                if f in ["netstat", "snmp"]:
                    try:
                        fd = open(path, "rb")
                        lines = String.bytes2str(fd.read()).splitlines()
                        table = [line.split() for line in lines]
                        for idx in range(0, len(table), 2):
                            for i, (k, v) in enumerate(zip(*table[idx:idx + 2])):
                                if i == 0:
                                    self.out.append("{:s}".format(k))
                                else:
                                    self.out.append("  {:30s} {:s}".format(k + ":", v))
                    except Exception:
                        pass
                    continue

                try:
                    fd = open(path, "rb")
                    for line in fd.readlines():
                        self.out.append(String.bytes2str(line).strip())
                except OSError:
                    continue

        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class CapabilityCommand(GenericCommand):
    """Display the capabilities of the debugging process."""
    _cmdline_ = "capability"
    _category_ = "02-f. Process Information - Security"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="also display detailed bit information other than cap_eff.")
    _syntax_ = parser.format_help()

    def get_thread_ids(self, pid):
        try:
            tids = os.listdir("/proc/{}/task".format(pid))
            return [int(x) for x in tids]
        except (FileNotFoundError, OSError):
            return []

    def print_cap_details(self, name, cap):
        bit_info = [
            [40, "CAP_CHECKPOINT_RESTORE", "Update /proc/sys/kernel/ns_last_pid; read /proc/[another_pid]/map_files; etc."],
            [39, "CAP_BPF", "Allow privileged BPF operations"],
            [38, "CAP_PERFMON", "Allow various performance-monitoring mechanisms; allow perf_event_open(2); allow some BPF operations"],
            [37, "CAP_AUDIT_READ", "Allow reading the audit log via a multicast netlink socket"],
            [36, "CAP_BLOCK_SUSPEND", "Allow features that can block system suspend"],
            [35, "CAP_WAKE_ALARM", "Trigger something that will wake up the system"],
            [34, "CAP_SYSLOG", "Allow privileged syslog(2) operations; View kernel addresses exposed via /proc even if kptr_restrict=1"],
            [33, "CAP_MAC_ADMIN", "Allow MAC configuration or state changes"],
            [32, "CAP_MAC_OVERRIDE", "Override MAC"],
            [31, "CAP_SETFCAP", "Set arbitrary capabilities on a file"],
            [30, "CAP_AUDIT_CONTROL", "Enable/disable kernel audit; change audit filter rules; retrieve audit status and filter rules"],
            [29, "CAP_AUDIT_WRITE", "Write records to kernel audit log"],
            [28, "CAP_LEASE", "Establish leases"],
            [27, "CAP_MKNOD", "Create special files using mknod(2)"],
            [26, "CAP_SYS_TTY_CONFIG", "Allow vhangup(2); allow various privileged ioctl(2) operations on virtual terminals"],
            [25, "CAP_SYS_TIME", "Set system cloc; set real-time (hardware) clock"],
            [24, "CAP_SYS_RESOURCE", "Override disk quota limits; override RLIMIT_NPROC resource limit; etc."],
            [23, "CAP_SYS_NICE", "Lower the process nice value and change the nice value for arbitrary processes; etc."],
            [22, "CAP_SYS_BOOT", "Allow reboot(2) and kexec_load(2)"],
            [21, "CAP_SYS_ADMIN", "Allow various privileges operations"],
            [20, "CAP_SYS_PACCT", "Allow acct(2)"],
            [19, "CAP_SYS_PTRACE", "Trace arbitrary processes using ptrace(2); etc."],
            [18, "CAP_SYS_CHROOT", "Allow chroot(2); change mount namespaces using setns(2)"],
            [17, "CAP_SYS_RAWIO", "Perform I/O port operations; etc."],
            [16, "CAP_SYS_MODULE", "Load and unload kernel modules"],
            [15, "CAP_IPC_OWNER", "Bypass permission checks for operations on SystemV IPC objects"],
            [14, "CAP_IPC_LOCK", "Lock memory; allocate memory using huge pages"],
            [13, "CAP_NET_RAW", "Use RAW and PACKET sockets; bind to any address for transparent proxying"],
            [12, "CAP_NET_ADMIN", "Perform various network-related operations"],
            [11, "CAP_NET_BROADCASTE", "(Unused) Make socket broadcasts, and listen to multicast"],
            [10, "CAP_NET_BIND_SERVICE", "Bind a socket to Internet domain privileged ports (less than 1024)"],
            [9, "CAP_LINUX_IMMUTABLE", "Set the FS_APPEND_FL and FS_IMMUTABLE_FL inode flags"],
            [8, "CAP_SETPCAP", "Add any capability from the calling thread's bounding set to its inheritable set; etc."],
            [7, "CAP_SETUID", "Make arbitrary manipulations of process UIDs; etc."],
            [6, "CAP_SETGID", "Make arbitrary manipulations of process GIDs and supplementary GID list; etc."],
            [5, "CAP_KILL", "Bypass permission checks for sending signals"],
            [4, "CAP_FSETID", "Don't clear SUID and SGID bits when a file is modified; etc."],
            [3, "CAP_FOWNER", "Bypass permission checks whether FSUID == file UID; set ACLs; etc."],
            [2, "CAP_DAC_READ_SEARCH", "Bypass permission checks of file read, dir read/exec; etc."],
            [1, "CAP_DAC_OVERRIDE", "Bypass permission checks of file read/write/exec"],
            [0, "CAP_CHOWN", "Make arbitrary changes to file UIDs and GIDs"],
        ]
        BitInfo(name, 64, bit_info).print(cap)
        return

    def print_capability_from_pid(self, verbose):
        pid = Pid.get_pid()
        if pid is None:
            return

        tids = self.get_thread_ids(pid)
        for tid in tids:
            gef_print(titlify("Thread capability set [PID={:d}, TID={:d}]".format(pid, tid)))
            try:
                status_path = "/proc/{:d}/task/{:d}/status".format(pid, tid)
                status = open(status_path, "r").read()
            except (FileNotFoundError, OSError):
                err("Failed to get the information of capability from {:s}".format(status_path))
                continue

            caps = {}
            m = re.search(r"CapInh:\s+(.+)", status)
            if m:
                caps["cap_inh"] = int(m.group(1), 16)
            m = re.search(r"CapPrm:\s+(.+)", status)
            if m:
                caps["cap_prm"] = int(m.group(1), 16)
            m = re.search(r"CapEff:\s+(.+)", status)
            if m:
                caps["cap_eff"] = int(m.group(1), 16)
            m = re.search(r"CapBnd:\s+(.+)", status)
            if m:
                caps["cap_bnd"] = int(m.group(1), 16)
            m = re.search(r"CapAmb:\s+(.+)", status)
            if m:
                caps["cap_amb"] = int(m.group(1), 16)

            if "cap_prm" in caps:
                msg = "Capability set that Effective and Inheritable are allowed to have"
                gef_print("Permitted  : {:#018x} - {:s}".format(caps["cap_prm"], msg))
                if verbose:
                    self.print_cap_details("cap_prm", caps["cap_prm"])
            if "cap_inh" in caps:
                msg = "Capability set that can be inherited when execve(2)"
                gef_print("Inheritable: {:#018x} - {:s}".format(caps["cap_inh"], msg))
                if verbose:
                    self.print_cap_details("cap_inh", caps["cap_inh"])
            if "cap_amb" in caps:
                msg = "Capability set that inherited when execve(2) not suid/sgid program"
                gef_print("Ambient    : {:#018x} - {:s}".format(caps["cap_amb"], msg))
                if verbose:
                    self.print_cap_details("cap_amb", caps["cap_amb"])
            if "cap_eff" in caps:
                msg = "Capability set that kernel actually uses to determine privileges"
                gef_print("Effective  : {:#018x} - {:s}".format(caps["cap_eff"], msg))
                self.print_cap_details("cap_eff", caps["cap_eff"])
            if "cap_bnd" in caps:
                msg = "Capability set that limits the capabilities set that can be acquired"
                gef_print("Bounding   : {:#018x} - {:s}".format(caps["cap_bnd"], msg))
                if verbose:
                    self.print_cap_details("cap_bnd", caps["cap_bnd"])
        return

    def print_capability_from_file(self, verbose):
        filepath = Path.get_filepath()
        if filepath is None:
            return

        gef_print(titlify("File capability set [{:s}]".format(filepath)))
        try:
            raw_caps = os.getxattr(filepath, "security.capability")
        except OSError:
            err("No data available")
            return

        caps = {}
        magic = struct.unpack("<I", raw_caps[:4])[0]
        caps["magic"] = magic & ~1
        caps["cap_eff"] = magic & 1
        if caps["magic"] == 0x01000000:
            cap_prm, cap_inh = struct.unpack("<II", raw_caps[4:12])
        elif caps["magic"] == 0x02000000:
            cap_prm_low, cap_inh_low, cap_prm_high, cap_inh_high = struct.unpack("<IIII", raw_caps[4:20])
            cap_prm = (cap_prm_high << 32) | cap_prm_low
            cap_inh = (cap_inh_high << 32) | cap_inh_low
        elif caps["magic"] == 0x03000000:
            cap_prm_low, cap_inh_low, cap_prm_high, cap_inh_high, rootid = struct.unpack("<IIIII", raw_caps[4:24])
            cap_prm = (cap_prm_high << 32) | cap_prm_low
            cap_inh = (cap_inh_high << 32) | cap_inh_low
            caps["rootid"] = rootid
        else:
            err("Invalid magic values: {:#x}".format(magic))
            return
        caps["cap_prm"] = cap_prm
        caps["cap_inh"] = cap_inh

        if "magic" in caps:
            msg = "Magic number: ver1: 0x01000000, ver2:0x02000000, ver3:0x03000000"
            gef_print("Magic      : {:#010x} - {:s}".format(caps["magic"], msg))
        if "cap_eff" in caps:
            msg = "If 1, new cap_prm are added to new cap_eff after execve(2)"
            gef_print("Effective  : {:#03x} - {:s}".format(caps["cap_eff"], msg))
        if "cap_prm" in caps:
            msg = "Capability set that permitted to the thread, regardless of the thread's cap_inh"
            gef_print("Permitted  : {:#018x} - {:s}".format(caps["cap_prm"], msg))
            if verbose:
                self.print_cap_details("cap_prm", caps["cap_prm"])
        if "cap_inh" in caps:
            msg = "Capability set that is ANDed with thread cap_inh to determine cap_inh after execve(2)"
            gef_print("Inheritable: {:#018x} - {:s}".format(caps["cap_inh"], msg))
            if verbose:
                self.print_cap_details("cap_inh", caps["cap_inh"])
        if "rootid" in caps:
            msg = "UID of root in user namespace"
            gef_print("Root ID    : {:#010x} - {:s}".format(caps["rootid"], msg))
        return

    @parse_args
    @only_if_gdb_target_local
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        self.print_capability_from_pid(args.verbose)
        self.print_capability_from_file(args.verbose)
        return


@register_command
class SmartMemoryDumpCommand(GenericCommand):
    """Dump the memory of the entire process smartly."""
    _cmdline_ = "smart-memory-dump"
    _category_ = "03-e. Memory - Dump"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-p", "--prefix", help="use this name for the dump destination file prefix. (default: PID)")
    parser.add_argument("-s", "--suffix", help="use this name for the dump destination file suffix. (default: None)")
    parser.add_argument("-f", "--filter", action="append", type=re.compile, default=[], help="REGEXP include filter.")
    parser.add_argument("-e", "--exclude", action="append", type=re.compile, default=[], help="REGEXP exclude filter.")
    parser.add_argument("-c", "--commit", action="store_true", help="actually perform the dump.")
    _syntax_ = parser.format_help()

    def smart_memory_dump(self):
        maps = ProcessMap.get_process_maps()
        if maps is None:
            err("Failed to get maps")
            return

        addr_len = current_arch.ptrsize * 2
        for entry in maps:
            start = entry.page_start
            end = entry.page_end
            perm = str(entry.permission)

            if entry.path in ["[vvar]", "[vsyscall]", "[vectors]", "[sigpage]"]:
                continue

            if not entry.path.startswith(("[", "<")):
                path = os.path.basename(entry.path)
            else:
                path = entry.path
                path = path.replace("[", "").replace("]", "") # consider [heap], [stack], [vdso]
                path = path.replace("<", "").replace(">", "") # consider <tls-th1>, <explored>
            path = path.replace(" ", "_") # consider deleted case. e.g.: /path/to/file (deleted)

            dumpfile_name = "{:s}{:0{}x}-{:0{}x}_{:s}_{:s}{:s}.raw".format(
                self.prefix, start, addr_len, end, addr_len, perm, path, self.suffix,
            )

            if self.filter and not any(filt.search(dumpfile_name) for filt in self.filter):
                continue

            if self.exclude and any(ex.search(dumpfile_name) for ex in self.exclude):
                continue

            filepath = os.path.join(GEF_TEMP_DIR, dumpfile_name)

            if self.commit:
                try:
                    data = read_memory(start, end - start)
                except gdb.MemoryError:
                    continue
                open(filepath, "wb").write(data)
                info("Saved to {:s}".format(filepath))
            else:
                info("It will be saved to {:s}".format(filepath))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        self.filter = args.filter
        self.exclude = args.exclude
        self.commit = args.commit

        if args.prefix is None:
            pid = Pid.get_pid(remote=True)
            if pid is None:
                self.prefix = "{:05d}_".format(0)
            else:
                self.prefix = "{:05d}_".format(pid)
        elif args.prefix == "":
            self.prefix = args.prefix
        else:
            self.prefix = "{:s}_".format(args.prefix)

        if args.suffix is None:
            self.suffix = ""
        else:
            self.suffix = "_{:s}".format(args.suffix)

        self.smart_memory_dump()

        if not self.commit:
            warn('This is dry run mode. No dump has been performed yet. To dump, please add "--commit".')
        return


@register_command
class HijackFdCommand(GenericCommand):
    """Redirect the file descriptor during runtime."""
    _cmdline_ = "hijack-fd"
    _category_ = "01-g. Debugging Support - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("old_fd", metavar="OLD_FD", type=int, help="file descriptor number to redirect.")
    parser.add_argument("new_output", metavar="NEW_OUTPUT", type=str, help="the location redirected data is stored.")
    parser.add_argument("--fd-adjust-connect", type=int, default=0,
                        help="use when syscall return value and the actually opened FD do not match (for qemu-user).")
    parser.add_argument("--fd-adjust-dup3", type=int, default=0,
                        help="use when syscall return value and the actually opened FD do not match (for qemu-user).")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 2 /tmp/stderr_output.txt\n".format(_cmdline_)
    _example_ += "{:s} 2 localhost:8000".format(_cmdline_)

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "rr", "wine"))
    @exclude_specific_arch(arch=("CRIS",))
    def do_invoke(self, args):
        # In one version of qemu, the fd was sometimes slightly off in case of i386
        # (fd returned by syscall == real opened fd + 80). I have been hard-coding it so far,
        # but it seems to be fixed, so please specify it with a command argument.
        self.fd_adjust_connect = args.fd_adjust_connect
        self.fd_adjust_dup3 = args.fd_adjust_dup3

        self.AF_INET = 2
        self.SOCK_STREAM = 1
        self.O_APPEND = 0o2000
        self.O_CREAT = 0o100
        self.O_RDWR = 0o2
        # some architecture use different consts.
        if is_mips32() or is_mips64() or is_mipsn32():
            # /usr/mipsel-linux-gnu/include/bits/socket_type.h
            # /usr/mips64el-linux-gnuabi64/include/bits/socket_type.h
            self.SOCK_STREAM = 2
            # /usr/mipsel-linux-gnu/include/bits/fcntl.h
            # /usr/mips64el-linux-gnuabi64/include/bits/fcntl.h
            self.O_APPEND = 0x0008
            self.O_CREAT = 0x0100
        elif is_sparc32() or is_sparc32plus() or is_sparc64():
            # sparcv8--uclibc--stable-2022.08-1/sparc-buildroot-linux-uclibc/sysroot/usr/include/bits/fcntl.h
            # sparc64--glibc--stable-2022.08-1/sparc64-buildroot-linux-gnu/sysroot/usr/include/bits/fcntl.h
            self.O_APPEND = 0x0008
            self.O_CREAT = 0x0200
        elif is_alpha():
            # /usr/alpha-linux-gnu/include/bits/fcntl.h
            self.O_APPEND = 0o0010
            self.O_CREAT = 0o1000
        elif is_hppa32() or is_hppa64():
            # /usr/hppa-linux-gnu/include/bits/fcntl.h
            self.O_APPEND = 0o0010
            self.O_CREAT = 0o0400

        self.hijack_fd(args)
        return

    def call_syscall(self, syscall_name, args):
        args = " ".join([hex(x) if x >= 0 else str(x) for x in args])
        cmd = "call-syscall {:s} {}".format(syscall_name, args)
        info(cmd)
        res = gdb.execute(cmd, to_string=True)
        output_line = res.splitlines()[-1]
        info(output_line)
        return int(output_line.split()[2], 0)

    def hijack_fd(self, args):
        if ":" in args.new_output:
            new_fd = self.get_fd_from_connect_server(args)
        else:
            new_fd = self.get_fd_from_file_open(args)
        if new_fd is None:
            return

        # call dup3
        # dup2 does not exist in aarch64. So use dup3 instead of dup2.
        dup3_result = self.call_syscall("dup3", [new_fd - self.fd_adjust_dup3, args.old_fd, 0])
        if dup3_result - self.fd_adjust_dup3 != args.old_fd:
            err("Failed to dup3 (result {:d} != fd #{:d})".format(dup3_result, args.old_fd))
            return
        info("Duplicated fd #{:d}{:s}#{:d}".format(new_fd, RIGHT_ARROW, args.old_fd))

        # call close
        close_result = self.call_syscall("close", [new_fd])
        if close_result == -1:
            err("Failed to close fd #{:d}".format(new_fd))
            return
        info("Closed extra fd #{:d}".format(new_fd))

        ok("Success")
        return

    def write_stack(self, data):
        data = String.str2bytes(data)

        # get stack address
        vmmap = ProcessMap.get_process_maps()
        stack_addrs = [entry.page_start for entry in vmmap if entry.path == "[stack]"]
        if len(stack_addrs) == 0:
            err("Not found stack")
            return None, None
        stack_addr = stack_addrs[0]

        # read original contents
        try:
            original_contents = read_memory(stack_addr, len(data))
        except gdb.MemoryError:
            err("Failed to read stack")
            return None, None

        info("Original contents: {} @ {:#x}".format(original_contents, stack_addr))
        info("Overwrite data: {}".format(data))

        # overwrite it
        try:
            write_memory(stack_addr, data)
        except Exception:
            err("Failed to write stack")
            return None, None

        # read again and check
        if read_memory(stack_addr, len(data)) != data:
            err("Failed to write stack")
            return None, None

        return stack_addr, original_contents

    def get_fd_from_file_open(self, args):
        # call open
        stack_addr, original_contents = self.write_stack(args.new_output + "\0")
        if stack_addr is None:
            return None

        info("Trying to open {}".format(args.new_output))

        AT_FDCWD = -100
        flags = self.O_APPEND | self.O_CREAT | self.O_RDWR
        mode = 0o666
        # open does not exist in aarch64. So use openat instead of open.
        open_fd = self.call_syscall("openat", [AT_FDCWD, stack_addr, flags, mode])
        write_memory(stack_addr, original_contents) # revert

        if open_fd == -1:
            err("Failed to open {}".format(args.new_output))
            return None

        info("Opened {} with 0o666 as fd #{:d}".format(args.new_output, open_fd))
        return open_fd

    def get_fd_from_connect_server(self, args):
        import socket
        address = socket.gethostbyname(args.new_output.split(":")[0])
        port = int(args.new_output.split(":")[1])

        # call socket
        sock_fd = self.call_syscall("socket", [self.AF_INET, self.SOCK_STREAM, 0])
        if sock_fd == -1:
            err("Failed to socket")
            return None
        info("Created socket fd #{:d}".format(sock_fd))

        # call connect (Also supports big endian)
        sockaddr_in = p16(self.AF_INET) + struct.pack("<H", socket.htons(port)) + socket.inet_aton(address)
        stack_addr, original_contents = self.write_stack(sockaddr_in)
        if stack_addr is None:
            return None

        info("Trying to connect to {}".format(args.new_output))
        connect_result = self.call_syscall("connect", [sock_fd - self.fd_adjust_connect, stack_addr, 16])
        write_memory(stack_addr, original_contents) # revert

        if connect_result == -1:
            err("Failed to connect to {}:{}".format(address, port))
            return

        info("Connected to {} as fd #{:d}".format(args.new_output, sock_fd))
        return sock_fd


@register_command
class ScanSectionCommand(GenericCommand):
    """Search for addresses located in a memory mapping (haystack) that belonging to another (needle)."""
    _cmdline_ = "scan-section"
    _category_ = "03-a. Memory - Search"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("haystack", metavar="HAYSTACK", help="where to search for the needle.")
    parser.add_argument("needle", metavar="NEEDLE", help="what to explore.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} stack binary # scan binary address from stack\n".format(_cmdline_)
    _example_ += "{:s} stack libc   # scan libc address from stack\n".format(_cmdline_)
    _example_ += "{:s} stack heap   # scan heap address from stack\n".format(_cmdline_)
    _example_ += "{:s} heap libc    # scan libc address from heap\n".format(_cmdline_)
    _example_ += "{:s} 0x0000555555772000-0x0000555555774000 libc".format(_cmdline_)

    def scan(self, haystack, needle):
        needle_sections = []
        haystack_sections = []

        if "0x" in haystack:
            try:
                start, end = AddressUtil.parse_string_range(haystack)
                haystack_sections.append((start, end, ""))
            except ValueError:
                pass

        if "0x" in needle:
            try:
                start, end = AddressUtil.parse_string_range(needle)
                needle_sections.append((start, end))
            except ValueError:
                pass

        for sect in ProcessMap.get_process_maps():
            if haystack in sect.path:
                haystack_sections.append((sect.page_start, sect.page_end, os.path.basename(sect.path)))
            if needle in sect.path:
                needle_sections.append((sect.page_start, sect.page_end))

        step = current_arch.ptrsize
        unpack = u32 if step == 4 else u64

        for hstart, hend, hname in haystack_sections:
            try:
                mem = read_memory(hstart, hend - hstart)
            except gdb.MemoryError:
                continue

            for i in range(0, len(mem), step):
                target = unpack(mem[i:i + step])
                for nstart, nend in needle_sections:
                    if not (nstart <= target < nend):
                        continue
                    deref = AddressUtil.recursive_dereference_to_string(hstart + i)
                    if hname != "":
                        name = Color.colorify(hname, "yellow")
                        gef_print("{:s}: {:s}".format(name, deref))
                    else:
                        gef_print(" {:s}".format(deref))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        haystack = args.haystack
        needle = args.needle

        info("Searching for addresses in '{:s}' that point to '{:s}'"
             .format(Color.yellowify(haystack), Color.yellowify(needle)))

        if haystack in ["binary", "bin"]:
            haystack = Path.get_filepath(append_proc_root_prefix=False)
        if is_qemu_user() and haystack is None:
            haystack = "[code]"

        if needle in ["binary", "bin"]:
            needle = Path.get_filepath(append_proc_root_prefix=False)
        if is_qemu_user() and needle is None:
            needle = "[code]"

        self.scan(haystack, needle)
        return


@register_command
class SearchPatternCommand(GenericCommand):
    """Search a pattern in memory."""
    _cmdline_ = "search-pattern"
    _category_ = "03-a. Memory - Search"
    _aliases_ = ["find", "grep"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--hex", action="store_true",
                        help="interpret PATTERN as hex. invalid character is ignored.")
    parser.add_argument("--big", action="store_true",
                        help="interpret PATTERN as big endian if PATTERN is 0xXXXXXXXX style.")
    parser.add_argument("--phys", action="store_true",
                        help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("-a", "--aligned", type=int, default=1,
                        help="alignment unit. (default: %(default)s)")
    parser.add_argument("-p", "--perm", default="r??",
                        help="the filter by permission. (default: %(default)s)")
    parser.add_argument("-i", "--interval", type=lambda x: int(x, 0),
                        help="the interval to skip searching from the last found position within the same section.")
    parser.add_argument("-l", "--limit", type=lambda x: int(x, 0),
                        help="the limit of the search result.")
    parser.add_argument("-s", "--max-region-size", type=lambda x: int(x, 0), default=0x10000000,
                        help="maximum size of search region when no range is specified. (default: %(default)#x)")
    parser.add_argument("-d", "--disable-utf16", action="store_true",
                        help="disable utf16 search if PATTERN is ascii string.")
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="shows the section currently searching.")
    parser.add_argument("pattern", metavar="PATTERN",
                        help='search target value. "double-escaped string" or 0xXXXXXXXX style.')
    parser.add_argument("section", metavar="SECTION_OR_START_ADDR", nargs="?", default="",
                        help="section name or starting address of search range.")
    parser.add_argument("size", metavar="SIZE", nargs="?",
                        help="search range size. valid only when a start address is specified.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} ABCD                      # search 'ABCD' from whole memory\n".format(_cmdline_)
    _example_ += '{:s} "\\\\x41\\\\x42\\\\x43\\\\x44"    # double-escaped string is also valid\n'.format(_cmdline_)
    _example_ += '{:s} --hex "41 42 43 44"       # another valid format\n'.format(_cmdline_)
    _example_ += "{:s} 0x41424344                # search 0x41424344 (='DCBA') from whole memory\n".format(_cmdline_)
    _example_ += "{:s} 0x555555554000 stack      # search 0x555555554000 (6byte) from stack\n".format(_cmdline_)
    _example_ += "{:s} 0x0000555555554000 stack  # search 0x0000555555554000 (8byte) from stack\n".format(_cmdline_)
    _example_ += "{:s} AAAA binary               # 'binary' means the area executable itself (only usermode)\n".format(_cmdline_)
    _example_ += "{:s} AAAA 0x400000-0x404000    # search 'AAAA' from specific range\n".format(_cmdline_)
    _example_ += "{:s} AAAA 0x400000 0x4000      # another valid format\n".format(_cmdline_)
    _example_ += "{:s} AAAA heap --aligned 16    # search with aligned\n".format(_cmdline_)
    _example_ += "{:s} AAAA -p r?-               # search from r-- or rw-, but not from r-x or rwx".format(_cmdline_)

    _note_ = "This command overwrites original \"find\" command."

    def print_section(self, section):
        if isinstance(section, Address):
            section = section.section

        if section is None:
            return

        title = "In "
        if section.path:
            title += "'{}' ".format(Color.blueify(section.path))
        title += "({:#x}-{:#x} [{}])".format(section.page_start, section.page_end, section.permission)

        ok(title)
        return

    def print_loc(self, loc):
        if self.args.aligned and loc[0] % self.args.aligned:
            return
        h = hexdump(loc[1], 0x10, base=loc[0])
        gef_print("  {:s}".format(h))
        return

    def search_pattern_by_address(self, pattern, start_address, end_address):
        """Search a pattern within a range defined by arguments."""
        pattern = String.str2bytes(pattern)
        if is_qemu_system():
            step = gef_getpagesize()
        else:
            step = 0x400 * gef_getpagesize()
        locations = []

        tqdm = GefUtil.get_tqdm(self.args.verbose)
        for chunk_addr in tqdm(range(start_address, end_address, step), leave=False):
            if chunk_addr + step > end_address:
                chunk_size = end_address - chunk_addr
            else:
                chunk_size = step

            try:
                if self.args.phys:
                    mem = read_physmem(chunk_addr, chunk_size)
                else:
                    mem = read_memory(chunk_addr, chunk_size)
            except (gdb.MemoryError, ValueError, OverflowError):
                # cannot access memory this range. It doesn't make sense to try any more
                break

            for match in re.finditer(pattern, mem):
                start = chunk_addr + match.start()
                if self.args.interval:
                    if len(locations) > 0:
                        if start < locations[-1][0] + self.args.interval:
                            continue

                data = mem[match.start():][:0x10]
                if len(data) < 0x10:
                    try:
                        data += read_memory(chunk_addr + chunk_size, 0x10 - len(data))
                    except gdb.MemoryError:
                        pass

                locations.append((start, data))

                self.found_count += 1
                if self.args.limit and self.args.limit <= self.found_count:
                    return locations
        return locations

    def get_process_maps_qemu_system(self):
        res = PageMap.get_page_maps_by_pagewalk("pagewalk --quiet --no-pager")
        res = sorted(set(res.splitlines()))
        res = list(filter(lambda line: line.endswith("]"), res))
        res = list(filter(lambda line: "[+]" not in line, res))
        res = list(filter(lambda line: "*" not in line, res))
        for line in res:
            if is_x86() and "ACCESSED" not in line:
                continue
            # extract
            lines = line.split()
            addr_start, addr_end = [int(x, 16) for x in lines[0].split("-")]
            # non valid addr
            if not is_valid_addr(addr_start):
                continue
            # parse
            if is_x86():
                perm = Permission.from_process_maps(lines[5][1:].lower())
            elif is_arm32():
                perm = line.split("/")[-1][:3]
                perm = Permission.from_process_maps(perm.lower())
            elif is_arm64():
                perm = line.split("/")[-1][:3]
                perm = Permission.from_process_maps(perm.lower())
            yield Section(page_start=addr_start, page_end=addr_end, permission=perm)

    def search_pattern_by_section(self, pattern, section_name=""):
        """Search a pattern within the whole userland memory."""
        if is_qemu_system():
            maps_generator = self.get_process_maps_qemu_system()
        else:
            maps_generator = ProcessMap.get_process_maps()

        for section in maps_generator:
            # too big
            if section_name == "":
                if section.size >= self.args.max_region_size:
                    info("{:#x}-{:#x} is skipped due to size ({:#x}) >= MAX_REGION_SIZE ({:#x})".format(
                        section.page_start, section.page_end,
                        section.size, self.args.max_region_size,
                    ))
                    continue

            # permission filter
            if not section.permission & Permission.READ:
                continue
            if self.args.perm[1] in "wW" and not section.permission & Permission.WRITE:
                continue
            if self.args.perm[1] in "-_" and section.permission & Permission.WRITE:
                continue
            if self.args.perm[2] in "xX" and not section.permission & Permission.EXECUTE:
                continue
            if self.args.perm[2] in "-_" and section.permission & Permission.EXECUTE:
                continue

            # specific section name filter
            if section.path in ["[vvar]", "[vsyscall]", "[vectors]", "[sigpage]"]:
                continue
            if section_name not in section.path:
                continue

            # verbose print
            if self.args.verbose:
                self.print_section(section) # verbose: always print section before search

            # search
            start = section.page_start
            end = section.page_end
            ret = self.search_pattern_by_address(pattern, start, end) # search

            if ret:
                if not self.args.verbose:
                    self.print_section(section) # default: print section if found

            for loc in ret:
                self.print_loc(loc)

            if not is_alive():
                err("The process is dead")
                break

            if self.args.limit and self.args.limit <= self.found_count:
                break
        return

    def create_patterns(self, args):
        # create normal pattern
        if args.hex: # "41414141" -> "\x41\x41\x41\x41"
            pattern = re.sub(r"[^0-9a-fA-F]", "", args.pattern)
            if len(pattern) % 2 != 0:
                err("hex pattern length is odd")
                return None
            pattern = "".join(["\\x" + x for x in slicer(pattern, 2)])
        elif String.is_hex(args.pattern): # "0x41414141" -> "\x41\x41\x41\x41"
            if args.big or Endian.is_big_endian():
                pattern = "".join(["\\x" + x for x in slicer(args.pattern[2:], 2)])
            else:
                pattern = "".join(["\\x" + x for x in slicer(args.pattern[2:], 2)[::-1]])
        else:
            pattern = args.pattern

        def isascii(string):
            val = codecs.escape_decode(string)[0]
            return all(0x20 <= c < 0x7f for c in val)

        # create utf16 pattern
        pattern_utf16 = None
        if not args.disable_utf16:
            if isascii(pattern) and "\\" not in pattern:
                pattern_utf16 = "".join([x + "\\x00" for x in pattern])
        return pattern, pattern_utf16

    def process_by_address(self, patterns, start, end):
        extra = " (phys)" if self.args.phys else ""

        # normal search and print
        info("Searching '{:s}' in {:#x}-{:#x}{:s}".format(Color.yellowify(patterns[0]), start, end, extra))
        ret = self.search_pattern_by_address(patterns[0], start, end)
        for found_loc in ret:
            self.print_loc(found_loc)

        # utf16 search and print
        if patterns[1] is not None:
            info("Searching '{:s}' in {:#x}-{:#x}{:s}".format(Color.yellowify(patterns[1]), start, end, extra))
            ret = self.search_pattern_by_address(patterns[1], start, end)
            for found_loc in ret:
                self.print_loc(found_loc)
        return

    def process_by_section(self, patterns, section_name):
        extra = " (phys)" if self.args.phys else ""

        # normal search and print
        if section_name == "":
            info("Searching '{:s}' in {:s}{:s}".format(Color.yellowify(patterns[0]), "whole memory", extra))
        else:
            info("Searching '{:s}' in {:s}{:s}".format(Color.yellowify(patterns[0]), section_name, extra))
        self.search_pattern_by_section(patterns[0], section_name)

        # utf16 search and print
        if patterns[1] is not None:
            if section_name == "":
                info("Searching '{:s}' in {:s}{:s}".format(Color.yellowify(patterns[1]), "whole memory", extra))
            else:
                info("Searching '{:s}' in {:s}{:s}".format(Color.yellowify(patterns[1]), section_name, extra))
            self.search_pattern_by_section(patterns[1], section_name)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        self.args = args
        self.found_count = 0

        # permission check
        if len(args.perm) != 3:
            err("Invalid permission length")
            return
        if args.perm[0] not in "rR":
            err("Permission needs to start by `r`")
            return
        if args.perm[1] not in "wW-_?" or args.perm[2] not in "xX-_?":
            err("Invalid permission")
            return
        if args.phys:
            info("Permission is ignored")
            # fall through

        patterns = self.create_patterns(args) # (pattern, pattern_utf16)
        if patterns is None:
            return

        # the case `find AAAA 0x400000 0x4000`
        if args.section and args.size:
            try:
                start = int(args.section, 16)
                end = start + int(args.size, 16)
            except ValueError:
                self.usage()
                return
            self.process_by_address(patterns, start, end)

        # the case `find AAAA 0x400000-0x404000`
        elif args.section and re.match(r"(0x)?[0-9a-fA-F]+-(0x)?[0-9a-fA-F]+", args.section):
            try:
                start, end = AddressUtil.parse_string_range(args.section)
            except ValueError:
                self.usage()
                return
            self.process_by_address(patterns, start, end)

        # search from specific section or whole memory
        else:
            if args.phys:
                err("--phys mode needs address information")
                return

            if args.section:
                if is_qemu_system() or is_kgdb() or is_vmware():
                    err("Unsupported")
                    return
                if args.section in ["binary", "bin"]:
                    section_name = Path.get_filepath(append_proc_root_prefix=False)
                else:
                    section_name = args.section
            else:
                section_name = args.section
            self.process_by_section(patterns, section_name)

        return


@register_command
class PtrDemangleCommand(GenericCommand):
    """Demangle a mangled value by PTR_MANGLE."""
    _cmdline_ = "ptr-demangle"
    _category_ = "02-f. Process Information - Security"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("value", metavar="VALUE", nargs="?", type=lambda x: int(x, 0),
                       help="the value to demangle.")
    group.add_argument("--source", action="store_true",
                       help="shows the source instead of displaying demangled value.")
    _syntax_ = parser.format_help()

    @staticmethod
    @Cache.cache_until_next
    def get_cookie():
        if is_qiling():
            return None

        try:
            if is_x86_64():
                tls = current_arch.get_tls()
                cookie = read_int_from_memory(tls + 0x30)
                return cookie
            elif is_x86_32():
                tls = current_arch.get_tls()
                cookie = read_int_from_memory(tls + 0x18)
                return cookie
            elif is_arm32() or is_arm64():
                cookie_ptr = AddressUtil.parse_address("&__pointer_chk_guard_local")
                cookie = read_int_from_memory(cookie_ptr)
                return cookie
        except (gdb.error, OverflowError):
            pass

        # generic
        try:
            auxv = Auxv.get_auxiliary_values()
            if auxv is None:
                Cache.reset_gef_caches(function=Auxv.get_auxiliary_values)
                auxv = Auxv.get_auxiliary_values()
            if auxv and "AT_RANDOM" in auxv:
                if is_s390x():
                    cookie = read_int_from_memory(auxv["AT_RANDOM"]) & 0x00ffffffffffffff
                else:
                    cookie = read_int_from_memory(auxv["AT_RANDOM"] + current_arch.ptrsize)
                if cookie != 0:
                    return cookie
        except gdb.error:
            pass
        return None

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    @exclude_specific_arch(arch=("SPARC32", "XTENSA", "CRIS"))
    def do_invoke(self, args):
        if args.source:
            s = GefUtil.get_source(current_arch.decode_cookie)
            gef_print(s)
            return

        cookie = self.get_cookie()
        if cookie is None:
            return
        info("Cookie is {:s}".format(Color.boldify("{:#x}".format(cookie))))

        decoded = current_arch.decode_cookie(args.value, cookie)
        decoded_sym = Symbol.get_symbol_string(decoded)
        if is_valid_addr(decoded):
            valid_msg = Color.colorify("valid", "bold green")
        else:
            valid_msg = Color.colorify("invalid", "bold red")
        decoded = Color.boldify("{:#x}".format(decoded))
        info("Decoded value is {:s}{:s} [{:s}]".format(decoded, decoded_sym, valid_msg))
        return


@register_command
class PtrMangleCommand(GenericCommand):
    """Mangle a mangled value by PTR_MANGLE."""
    _cmdline_ = "ptr-mangle"
    _category_ = "02-f. Process Information - Security"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("value", metavar="VALUE", nargs="?", type=lambda x: int(x, 0),
                       help="the value to mangle.")
    group.add_argument("--source", action="store_true",
                       help="shows the source instead of displaying mangled value.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    @exclude_specific_arch(arch=("SPARC32", "XTENSA", "CRIS"))
    def do_invoke(self, args):
        if args.source:
            s = GefUtil.get_source(current_arch.encode_cookie)
            gef_print(s)
            return

        cookie = PtrDemangleCommand.get_cookie()
        if cookie is None:
            return
        info("Cookie is {:s}".format(Color.boldify("{:#x}".format(cookie))))

        encoded = current_arch.encode_cookie(args.value, cookie)
        info("Encoded value is {:#x}".format(encoded))
        return


@register_command
class SearchMangledPtrCommand(GenericCommand):
    """Search mangled values from RW memory."""
    _cmdline_ = "search-mangled-ptr"
    _category_ = "02-f. Process Information - Security"
    _aliases_ = ["cookie"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="shows the section you are currently searching.")
    _syntax_ = parser.format_help()

    def print_section(self, section):
        if isinstance(section, Address):
            section = section.section

        if section is None:
            return

        title = "In "
        if section.path:
            title += "'{}' ".format(Color.blueify(section.path))

        title += "({:#x}-{:#x} [{}])".format(section.page_start, section.page_end, section.permission)
        ok(title)
        return

    def print_loc(self, loc):
        addr, value, decoded = loc[0], loc[1], loc[2]
        addr_sym = Symbol.get_symbol_string(addr)
        decoded_sym = Symbol.get_symbol_string(decoded)
        try:
            read_memory(decoded, 1)
            valid_msg = Color.colorify("valid", "bold green")
        except gdb.MemoryError:
            valid_msg = Color.colorify("invalid", "bold red")
        decoded = Color.boldify("{:#x}".format(decoded))

        base_address_color = Config.get_gef_setting("theme.dereference_base_address")
        width = AddressUtil.get_format_address_width()
        addr = Color.colorify("{:#0{:d}x}".format(addr, width), base_address_color)

        gef_print("  {:s}{:s}: {:#x} (={:s}{:s}) [{:s}]".format(addr, addr_sym, value, decoded, decoded_sym, valid_msg))
        return

    def search_mangled_ptr(self, start_address, end_address):
        """Search a mangled pointer within a range defined by arguments."""
        if is_qemu_system():
            step = gef_getpagesize()
        else:
            step = 0x400 * gef_getpagesize()
        locations = []

        for chunk_addr in range(start_address, end_address, step):
            if chunk_addr + step > end_address:
                chunk_size = end_address - chunk_addr
            else:
                chunk_size = step

            try:
                mem = read_memory(chunk_addr, chunk_size)
            except gdb.MemoryError:
                # cannot access memory this range. It doesn't make sense to try any more
                break

            for i, value in enumerate(slice_unpack(mem, current_arch.ptrsize)):
                decoded = current_arch.decode_cookie(value, self.cookie)
                try:
                    read_memory(decoded, 1)
                except gdb.MemoryError:
                    continue
                addr = chunk_addr + i * current_arch.ptrsize
                locations.append((addr, value, decoded))
            del mem
        return locations

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @exclude_specific_arch(arch=("SPARC32", "XTENSA", "CRIS"))
    def do_invoke(self, args):
        # init
        self.cookie = PtrDemangleCommand.get_cookie()
        if self.cookie is None:
            return
        info("Cookie is {:s}".format(Color.boldify("{:#x}".format(self.cookie))))

        # check
        if current_arch.decode_cookie(0, 1) == 0:
            err("In this architecture, the value is not encrypted with cookies.")
            return

        # search
        maps_generator = ProcessMap.get_process_maps()
        for section in maps_generator:
            if not section.permission & Permission.READ:
                continue
            if not section.permission & Permission.WRITE:
                continue
            if args.verbose:
                self.print_section(section) # verbose: always print section before search

            start = section.page_start
            end = section.page_end
            ret = self.search_mangled_ptr(start, end)

            if ret:
                if not args.verbose:
                    self.print_section(section) # default: print section if found

            for loc in ret:
                self.print_loc(loc)

            if not is_alive():
                err("The process is dead")
                break
        return


@register_command
class SearchCfiGadgetsCommand(GenericCommand):
    """Search CFI-valid and controllable generally gadgets from executable area."""
    _cmdline_ = "search-cfi-gadgets"
    _category_ = "03-a. Memory - Search"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def find_endbr(self, start, end):
        if is_x86_32():
            endbr = b"\xf3\x0f\x1e\xfb" # endbr32
        else:
            endbr = b"\xf3\x0f\x1e\xfa" # endbr64

        data = read_memory(start, end - start)

        pos = -1
        addrs = []
        while True:
            pos = data.find(endbr, pos + 1)
            if pos == -1:
                break
            addrs.append(start + pos)
        return addrs

    def filter_gadgets(self, endbr_addrs):
        filtered_addrs = []

        for addr in endbr_addrs:
            start = addr
            inscount = 0
            valid = True

            while True:
                insn = get_insn(addr)
                inscount += 1
                length = len(insn.opcodes)
                addr += length

                if current_arch.is_ret(insn):
                    break

                if current_arch.is_call(insn):
                    if insn.operands[0].startswith("0x"):
                        valid = False
                    break

                if current_arch.is_jump(insn):
                    if insn.operands[0].startswith("0x"):
                        valid = False

                    # If the GOT cannot be modified, you can jump directly to the jump destination,
                    # so there is no need to consider it in practice.
                    elif inscount == 2 and "[rip" in insn.operands[0]:
                        # 0x555555558630 f30f1efa     <free@plt+0x0> endbr64
                        # 0x555555558634 ff2536e90100 <free@plt+0x4> jmp QWORD PTR [rip+0x1e936] # 0x555555576f70
                        r = re.search(r"# (0x\w+)", insn.operands[0])
                        if r:
                            v = ProcessMap.lookup_address(int(r.group(1), 16))
                            if not v.section.is_writable():
                                valid = False
                    break

                if "XMMWORD" in "".join(insn.operands):
                    valid = False
                    break

            if valid:
                filtered_addrs.append([start, inscount])
        return filtered_addrs

    def disasm_addrs(self, candidates):
        try:
            __import__("capstone")
            for start, inscount in candidates:
                res = gdb.execute("capstone-disassemble {:#x} --length {:d}".format(start, inscount), to_string=True)
                self.out.append(res)
        except ImportError:
            for start, inscount in candidates:
                self.out.extend([str(x) for x in Disasm.gdb_disassemble(start, nb_insn=inscount)])
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        # get map entry
        maps = ProcessMap.get_process_maps()
        if maps is None:
            err("Failed to get maps")
            return

        self.out = []
        for entry in maps:
            if not entry.is_executable():
                continue
            if entry.path in ["[vsyscall]"]:
                continue

            info("search from {:s}".format(entry.path))
            self.out.append(titlify(entry.path))
            addrs = self.find_endbr(entry.page_start, entry.page_end)
            filtered_addrs = self.filter_gadgets(addrs)
            self.disasm_addrs(filtered_addrs)

        if self.out:
            gef_print("\n".join(self.out).rstrip(), less=not args.no_pager)
        return


@register_command
class EditFlagsCommand(GenericCommand):
    """Edit flags in a human friendly way."""
    _cmdline_ = "edit-flags"
    _category_ = "04-b. Register - Modify"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("flagname", metavar="[FLAGNAME(+|-|~) ...]", nargs="*", help="the flag name to edit.")
    parser.add_argument("-v", "--verbose", action="store_true", help="show the bit information of the flag register.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}            # show the flag register\n".format(_cmdline_)
    _example_ += "{:s} zero+      # set ZERO flag\n".format(_cmdline_)
    _example_ += "{:s} direction- # unset DIRECTION flag\n".format(_cmdline_)
    _example_ += "{:s} sign~      # toggle SIGN flag\n".format(_cmdline_)
    _example_ += "{:s} -v         # verbose output".format(_cmdline_)

    def edit_flags(self, flag_names):
        for flag in flag_names:
            if len(flag) < 2:
                err("Too short length of the name")
                return

            if flag[-1] not in ("+", "-", "~"):
                err("Invalid action for flag '{:s}'".format(flag))
                return

        for flag in flag_names:
            action = flag[-1]
            name = flag[:-1].lower()

            if is_x86():
                dic = {
                    "id": "identification",
                    "ac": "align",
                    "vm": "virtualx86",
                    "rf": "resume",
                    "nt": "nested",
                    "of": "overflow",
                    "df": "direction",
                    "if": "interrupt",
                    "tf": "trap",
                    "sf": "sign",
                    "zf": "zero",
                    "af": "adjust",
                    "pf": "parity",
                    "cf": "carry",
                }
                if name in dic:
                    name = dic[name]

            if name not in current_arch.flags_table.values():
                err("Invalid flag name '{:s}'".format(flag[:-1]))
                continue

            for off in current_arch.flags_table:
                if current_arch.flags_table[off] != name:
                    continue

                old_flag = get_register(current_arch.flag_register)
                if action == "+":
                    new_flags = old_flag | (1 << off)
                elif action == "-":
                    new_flags = old_flag & ~(1 << off)
                else:
                    new_flags = old_flag ^ (1 << off)

                gdb.execute("set ({:s}) = {:#x}".format(current_arch.flag_register, new_flags))
        return

    def verbose_x86(self):
        eflags = get_register("$eflags")
        gef_print("{:s}  {:s}".format(BitInfo.bits_split(eflags, 32), Color.colorify("MASK", "bold")))

        def c(msg):
            mask = int(msg.split()[0], 16)
            if eflags & mask:
                color = "bold"
            else:
                color = ""
            return Color.colorify(msg, color)

        elements = [
            "|| |||| |||| |||| |||| |||+- " + c("0x000001 [CF]   Carry flag"),
            "|| |||| |||| |||| |||| ||+-- " + c("0x000002        Reserved (always 1)"),
            "|| |||| |||| |||| |||| |+--- " + c("0x000004 [PF]   Parity flag"),
            "|| |||| |||| |||| |||| +---- " + c("0x000008        Reserved (always 0)"),
            "|| |||| |||| |||| ||||",
            "|| |||| |||| |||| |||+------ " + c("0x000010 [AF]   Adjust flag (for BCD calc)"),
            "|| |||| |||| |||| ||+------- " + c("0x000020        Reserved (always 0)"),
            "|| |||| |||| |||| |+-------- " + c("0x000040 [ZF]   Zero flag"),
            "|| |||| |||| |||| +--------- " + c("0x000080 [SF]   Sign flag"),
            "|| |||| |||| ||||",
            "|| |||| |||| |||+----------- " + c("0x000100 [TF]   Trap flag (single step)"),
            "|| |||| |||| ||+------------ " + c("0x000200 [IF]   Interrupt enable flag"),
            "|| |||| |||| |+------------- " + c("0x000400 [DF]   Direction flag"),
            "|| |||| |||| +-------------- " + c("0x000800 [OF]   Overflow flag"),
            "|| |||| ||||",
            "|| |||| ||++---------------- " + c("0x003000 [IOPL] I/O privilege level (2bit)"),
            "|| |||| |+------------------ " + c("0x004000 [NT]   Nested task flag"),
            "|| |||| +------------------- " + c("0x008000        Reserved (always 0)"),
            "|| ||||",
            "|| |||+--------------------- " + c("0x010000 [RF]   Resume flag"),
            "|| ||+---------------------- " + c("0x020000 [VM]   Virtual 8086 mode flag"),
            "|| |+----------------------- " + c("0x040000 [AC]   Alignment check flag"),
            "|| +------------------------ " + c("0x080000 [VIF]  Virtual interrupt flag"),
            "||",
            "|+-------------------------- " + c("0x100000 [VIP]  Virtual interrupt pending"),
            "+--------------------------- " + c("0x200000 [ID]   Able to use CPUID instruction"),
        ]
        gef_print("\n".join([" " * 14 + e for e in elements]))
        return

    def verbose_arm32(self):
        cpsr = get_register("$cpsr")
        gef_print("{:s}  {:s}".format(BitInfo.bits_split(cpsr, 32), Color.colorify("MASK", "bold")))

        def c(msg):
            mask = int(msg.split()[0], 16)
            if cpsr & mask:
                color = "bold"
            else:
                color = ""
            return Color.colorify(msg, color)

        elements = [
            "|||| |||| |||| |||| |||| |||| |||+-++++- " + c("0x0000001f [M]  Mode field (5bit)"),
            "|||| |||| |||| |||| |||| |||| |||        " + "  User:0b10000 FIQ:0b10001 IRQ:0b10010",
            "|||| |||| |||| |||| |||| |||| |||        " + "  Supervisor:0b10011 Monitor:0b10110 Abort:0b10111",
            "|||| |||| |||| |||| |||| |||| |||        " + "  Hyp:0b11010 Undefined:0b11011 System:0b11111",
            "|||| |||| |||| |||| |||| |||| |||",
            "|||| |||| |||| |||| |||| |||| ||+------- " + c("0x00000020 [T]  Thumb execution state bit"),
            "|||| |||| |||| |||| |||| |||| |+-------- " + c("0x00000040 [F]  FIQ mask bit"),
            "|||| |||| |||| |||| |||| |||| +--------- " + c("0x00000080 [I]  IRQ mask bit"),
            "|||| |||| |||| |||| |||| ||||",
            "|||| |||| |||| |||| |||| |||+----------- " + c("0x00000100 [A]  Asynchronous abort mask bit"),
            "|||| |||| |||| |||| |||| ||+------------ " + c("0x00000200 [E]  Endianness execution state bit"),
            "|||| |++------------++++-++------------- " + c("0x0600fc00 [IT] If-Then execution state bits for Thumb IT instruction"),
            "|||| |  | |||| ||||",
            "|||| |  | |||| ++++--------------------- " + c("0x000f0000 [GE] Greater than or Equal flags for SIMD instruction"),
            "|||| |  | ||||",
            "|||| |  | ++++-------------------------- " + c("0x00f00000      Reserved"),
            "|||| |  |",
            "|||| |  +------------------------------- " + c("0x01000000 [J]  Jazelle bit"),
            "|||| +---------------------------------- " + c("0x08000000 [Q]  Cumulative saturation bit"),
            "||||",
            "|||+------------------------------------ " + c("0x10000000 [V]  Overflow condition flag"),
            "||+------------------------------------- " + c("0x20000000 [C]  Carry condition flag"),
            "|+-------------------------------------- " + c("0x40000000 [Z]  Zero condition flag"),
            "+--------------------------------------- " + c("0x80000000 [N]  Negative condition flag"),
        ]
        gef_print("\n".join([" " * 2 + e for e in elements]))
        return

    def verbose_arm64(self):
        cpsr = get_register("$cpsr")
        gef_print("{:s}  {:s}".format(BitInfo.bits_split(cpsr, 32), Color.colorify("MASK", "bold")))

        def c(msg):
            mask = int(msg.split()[0], 16)
            if cpsr & mask:
                color = "bold"
            else:
                color = ""
            return Color.colorify(msg, color)

        if ((cpsr >> 4) & 1) == 0: # AArch64 state
            elements = [
                "|||| |||| |||| |||| |||| |||| |||| ||++- " + c("0x00000003 [M.SP]  Selected stack pointer (2bit)"),
                "|||| |||| |||| |||| |||| |||| |||| ++--- " + c("0x0000000c [M.EL]  Exception level (2bit)"),
                "|||| |||| |||| |||| |||| |||| ||||",
                "|||| |||| |||| |||| |||| |||| |||+------ " + c("0x00000010 [M.S]   Execution state (AArch64:0, AArch32:1)"),
                "|||| |||| |||| |||| |||| |||| ||+------- " + c("0x00000020         Reserved (always 0)"),
                "|||| |||| |||| |||| |||| |||| |+-------- " + c("0x00000040 [F]     FIQ interrupt mask bit"),
                "|||| |||| |||| |||| |||| |||| +--------- " + c("0x00000080 [I]     IRQ interrupt mask bit"),
                "|||| |||| |||| |||| |||| ||||",
                "|||| |||| |||| |||| |||| |||+----------- " + c("0x00000100 [A]     SError interrupt mask bit"),
                "|||| |||| |||| |||| |||| ||+------------ " + c("0x00000200 [D]     Debug exception mask bit"),
                "|||| |||| |||| |||| |||| ++------------- " + c("0x00000c00 [BTYPE] Branch Type Indicator when FEAT_BTI is implemented"),
                "|||| |||| |||| |||| ||||",
                "|||| |||| |||| |||| |||+---------------- " + c("0x00001000 [SSBS]  Speculative Store Bypass when FEAT_SSBS is implemented"),
                "|||| |||| |||| ++++-+++----------------- " + c("0x000fe000         Reserved"),
                "|||| |||| ||||",
                "|||| |||| |||+-------------------------- " + c("0x00100000 [IL]    Illegal execution state"),
                "|||| |||| ||+--------------------------- " + c("0x00200000 [SS]    Software step flag"),
                "|||| |||| |+---------------------------- " + c("0x00400000 [PAN]   Privileged Access Never when FEAT_PAN is implemented"),
                "|||| |||| +----------------------------- " + c("0x00800000 [UAO]   User Access Override when FEAT_UAO is implemented"),
                "|||| ||||",
                "|||| |||+------------------------------- " + c("0x01000000 [DIT]   Data Independent Timing when FEAT_DIT is implemented"),
                "|||| ||+-------------------------------- " + c("0x02000000 [TCO]   Tag Check Override when FEAT_MTE is implemented"),
                "|||| ++--------------------------------- " + c("0x0c000000         Reserved"),
                "||||",
                "|||+------------------------------------ " + c("0x10000000 [V]     Overflow condition flag"),
                "||+------------------------------------- " + c("0x20000000 [C]     Carry condition flag"),
                "|+-------------------------------------- " + c("0x40000000 [Z]     Zero condition flag"),
                "+--------------------------------------- " + c("0x80000000 [N]     Negative condition flag"),
            ]
        else: # AArch32 state
            elements = [
                "|||| |||| |||| |||| |||| |||| |||| ++++- " + c("0x0000000f [M.A32] AArch32 mode (4bit)"),
                "|||| |||| |||| |||| |||| |||| ||||       " + "   User:0b0000 FIQ:0b0001 IRQ:0b0010",
                "|||| |||| |||| |||| |||| |||| ||||       " + "   Supervisor:0b0011 Monitor:0b0110 Abort:0b0111",
                "|||| |||| |||| |||| |||| |||| ||||       " + "   Hyp:0b1010 Undefined:0b1011 System:0b1111",
                "|||| |||| |||| |||| |||| |||| ||||",
                "|||| |||| |||| |||| |||| |||| |||+------ " + c("0x00000010 [M.S]   Execution state (AAch64:0, AArch32:1)"),
                "|||| |||| |||| |||| |||| |||| ||+------- " + c("0x00000020 [T]     T32 instruction set (Thumb) state bit"),
                "|||| |||| |||| |||| |||| |||| |+-------- " + c("0x00000040 [F]     FIQ interrupt mask bit"),
                "|||| |||| |||| |||| |||| |||| +--------- " + c("0x00000080 [I]     IRQ interrupt mask bit"),
                "|||| |||| |||| |||| |||| ||||",
                "|||| |||| |||| |||| |||| |||+----------- " + c("0x00000100 [A]     SError interrupt mask bit"),
                "|||| |||| |||| |||| |||| ||+------------ " + c("0x00000200 [E]     Endianness execution state bit"),
                "|||| |++------------++++-++------------- " + c("0x0600fc00 [IT]    If-Then execution state bits for Thumb IT instruction"),
                "|||| |  | |||| ||||",
                "|||| |  | |||| ++++--------------------- " + c("0x000f0000 [GE]    Greater than or Equal flags for SIMD instruction"),
                "|||| |  | ||||",
                "|||| |  | |||+-------------------------- " + c("0x00100000 [IL]    Illegal execution state"),
                "|||| |  | ||+--------------------------- " + c("0x00200000 [SS]    Software step flag"),
                "|||| |  | |+---------------------------- " + c("0x00400000 [PAN]   Privileged Access Never when FEAT_PAN is implemented"),
                "|||| |  | +----------------------------- " + c("0x00800000 [SSBS]  Speculative Store Bypass when FEAT_SBSS is implemented"),
                "|||| |  |",
                "|||| |  +------------------------------- " + c("0x01000000 [DIT]   Data Independent Timing when FEAT_DIT is implemented"),
                "|||| +---------------------------------- " + c("0x08000000 [Q]     Overflow or saturation flag"),
                "||||",
                "|||+------------------------------------ " + c("0x10000000 [V]     Overflow condition flag"),
                "||+------------------------------------- " + c("0x20000000 [C]     Carry condition flag"),
                "|+-------------------------------------- " + c("0x40000000 [Z]     Zero condition flag"),
                "+--------------------------------------- " + c("0x80000000 [N]     Negative condition flag"),
            ]
        gef_print("\n".join([" " * 2 + e for e in elements]))
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if current_arch.flag_register is None:
            warn("This command cannot work under this architecture.")
            return

        self.edit_flags(args.flagname)

        gef_print(current_arch.flag_register_to_human())
        if args.verbose:
            if is_x86():
                self.verbose_x86()
            elif is_arm32():
                self.verbose_arm32()
            elif is_arm64():
                self.verbose_arm64()
        return


class MprotectBreakpoint(gdb.Breakpoint):
    """When hit, this temporary breakpoint will restore the original code, and position $pc correctly."""
    def __init__(self, loc, code, pc, regs):
        super().__init__(loc, gdb.BP_BREAKPOINT, internal=True, temporary=True)
        self.original_code = code
        self.original_pc = pc
        self.original_regs = regs
        return

    def stop(self):
        EventHandler.__gef_check_disabled_bp__ = True
        self.enabled = False

        info("Restoring original context")
        write_memory(self.original_pc, self.original_code)
        info("Restoring registers")
        for k, v in self.original_regs.items():
            try:
                gdb.execute("set {:s} = {:#x}".format(k, v))
            except gdb.error:
                pass
        return True


@register_command
class MprotectCommand(GenericCommand):
    """Change a page permission (default: RWX)."""
    _cmdline_ = "mprotect"
    _category_ = "05-a. Syscall - Invoke"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the address to change the permission.")
    parser.add_argument("permission", metavar="PERMISSION", nargs="?", default="rwx",
                        help="the permission you set to the LOCATION. (default: %(default)s)")
    parser.add_argument("--patch-only", action="store_true", help="do not execute after patch.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $sp rwx\n".format(_cmdline_)
    _example_ += "{:s} 0x7ffff7e1b000 ___ # '_' means '-'.".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def do_mprotect(self, location, perm, patch_only):
        sect = ProcessMap.process_lookup_address(location)
        if sect is None:
            err("Unmapped address")
            return

        size = sect.page_end - sect.page_start
        original_pc = current_arch.pc
        if is_arm32() and current_arch.is_thumb():
            original_pc -= 1

        info("Generating sys_mprotect({:#x}, {:#x}, '{!s}') stub for arch {:s}".format(
            sect.page_start, size, Permission(value=perm), get_arch(),
        ))
        stub = current_arch.mprotect_asm(sect.page_start, size, perm)
        if stub is None:
            err("Failed to generate mprotect opcodes")
            return

        info("Saving original code")
        try:
            original_code = read_memory(original_pc, len(stub))
        except gdb.MemoryError:
            err("Failed to read memory")
            return

        info("Saving original registers value")
        original_regs = {}
        for r in current_arch.all_registers:
            v = get_register(r)
            if v is not None:
                original_regs[r] = v

        bp_loc = "*{:#x}".format(original_pc + len(stub))
        info("Setting a restore breakpoint at {:s}".format(bp_loc))
        MprotectBreakpoint(bp_loc, original_code, original_pc, original_regs)

        info("Overwriting current memory at {:#x} ({:d} bytes)".format(location, len(stub)))
        write_memory(original_pc, stub)
        after_data = read_memory(original_pc, len(stub))
        if stub != after_data:
            err("Failed to write memory (qemu doesn't support writing to code area?)")
            return

        if patch_only:
            return

        info("Resuming execution")
        gdb.execute("continue")
        return

    # On the CRIS architecture, setting a value to a register using the gdb `set` command will cause strange behavior.
    # So even if the shellcode is correct, it should not use this `mprotect` command.

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "rr", "wine"))
    @exclude_specific_arch(arch=("CRIS",))
    @load_keystone
    def do_invoke(self, args):
        if re.match(r"[rwx_-]{3}", args.permission):
            perm = Permission.NONE
            if args.permission[0] == "r":
                perm |= Permission.READ
            if args.permission[1] == "w":
                perm |= Permission.WRITE
            if args.permission[2] == "x":
                perm |= Permission.EXECUTE
        else:
            err("Invalid permission")
            return

        self.do_mprotect(args.location, perm, args.patch_only)
        return


@register_command
class KillThreadsCommand(GenericCommand):
    """Invoke pthread_exit(0) for specific THREAD_ID."""
    _cmdline_ = "killthreads"
    _category_ = "05-a. Syscall - Invoke"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("thread_id", metavar="THREAD_ID", nargs="*", type=int, help="the thread id (not TID) to kill.")
    parser.add_argument("-a", "--all", action="store_true", help="kill all threads except current thread.")
    parser.add_argument("-c", "--commit", action="store_true", help="commit to kill.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @exclude_specific_arch(arch=("CRIS",))
    def do_invoke(self, args):
        # print tid list and exit
        if not args.all and not args.thread_id:
            info("Among the threads shown below, `Thread Id` that is not the current thread can be used.")
            # back up
            nb_lines_threads = Config.get_gef_setting("context.nb_lines_threads")
            # change temporarily
            Config.set_gef_setting("context.nb_lines_threads", 0x100)
            # print
            gdb.execute("context threads")
            # restore
            Config.set_gef_setting("context.nb_lines_threads", nb_lines_threads)
            return

        # list up target thread id
        orig_thread = gdb.selected_thread()
        target_threads = []
        for th in gdb.selected_inferior().threads():
            if th.num == orig_thread.num:
                continue
            if args.all or (th.num in args.thread_id):
                target_threads.append(th)
        target_threads = sorted(target_threads, key=lambda x: x.num)
        gef_print("target Thread Id(s) to kill: {}".format([th.num for th in target_threads]))

        # kill
        if args.commit:
            # backup
            sched_lock = gdb.parameter("scheduler-locking")
            # change temporarily
            gdb.execute("set scheduler-locking on", to_string=True)
            # kill
            for th in target_threads:
                th.switch()
                try:
                    gdb.execute("call pthread_exit(0)")
                except gdb.error:
                    pass
            # restore
            orig_thread.switch()
            gdb.execute("set scheduler-locking {:s}".format(sched_lock), to_string=True)
        else:
            warn('This is dry run mode. Thread is not killed yet. To kill, please add "--commit".')
        return


@register_command
class CallSyscallCommand(GenericCommand):
    """A wrapper for calling syscall easily."""
    _cmdline_ = "call-syscall"
    _category_ = "05-a. Syscall - Invoke"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("syscall_name", metavar="SYSCALL_NAME", help="system call name to invoke.")
    parser.add_argument("syscall_args", metavar="SYSCALL_ARG", nargs="*", type=AddressUtil.parse_address,
                        help="arguments of system call.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} write 1 "*(void**)($rsp+0x18)" 15'.format(_cmdline_)

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "rr", "wine"))
    @exclude_specific_arch(arch=("CRIS",))
    def do_invoke(self, args):
        if current_arch is None:
            err("current_arch is not set.")
            return

        try:
            syscall_table = get_syscall_table()
        except Exception:
            err("syscall table does not exist")
            return

        # get syscall entry
        for nr, entry in syscall_table.table.items():
            if is_x86_64() and nr >= 0x40000000:
                continue
            if args.syscall_name == entry.name:
                break
        else:
            err("System call `{:s}` is not found.".format(args.syscall_name))
            return

        # length check
        if len(args.syscall_args) != len(entry.args_full):
            err("Argument count mismatch.")
            params = "(" + ", ".join(entry.args_full) + ");"
            gef_print("Prototype: {:s}{:s}".format(Color.boldify(args.syscall_name), params))
            return

        # title
        title = "{:s}({:s})".format(args.syscall_name, ", ".join(["{:#x}".format(x) for x in args.syscall_args]))
        gef_print(titlify(title))

        ret = ExecSyscall(nr, args.syscall_args).exec_code()

        if isinstance(current_arch.return_register, list):
            for ret_regs in current_arch.return_register:
                gef_print("{:s} = {:#x}".format(ret_regs, ret["reg"][ret_regs]))
        else:
            gef_print("{:s} = {:#x}".format(current_arch.return_register, ret["reg"][current_arch.return_register]))
        return


@register_command
class MmapMemoryCommand(GenericCommand):
    """Allocate a new memory."""
    _cmdline_ = "mmap"
    _category_ = "05-a. Syscall - Invoke"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address, default=0,
                        help="the address to allocate. (default: %(default)s)")
    parser.add_argument("size", metavar="SIZE", nargs="?", type=AddressUtil.parse_address, default=gef_getpagesize(),
                        help="the size to allocate. (default: %(default)s)")
    parser.add_argument("permission", metavar="PERMISSION", nargs="?", default="rwx",
                        help="the permission to allocate. `_` is interpreted as `-`. (default: %(default)s)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0x10000 0x1000 r-x\n".format(_cmdline_)
    _example_ += "{:s} 0 0x1000 _wx".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "rr", "wine"))
    @exclude_specific_arch(arch=("CRIS",))
    def do_invoke(self, args):
        # syscall name (mmap or mmap2 or arch-specific)
        try:
            syscall_table = get_syscall_table()
        except Exception:
            err("syscall table does not exist")
            return

        mmap_syscall_name = None
        for entry in syscall_table.table.values():
            if "mmap" not in entry.name:
                continue
            if len(entry.arg_regs) != 6:
                continue
            mmap_syscall_name = entry.name
            break
        if mmap_syscall_name is None:
            err("Not found mmap syscall")
            return

        # location
        if args.location % gef_getpagesize():
            err("Address is not a multiple of {:#x}".format(gef_getpagesize()))
            return

        # size
        if args.size % gef_getpagesize():
            err("Size is not a multiple of {:#x}".format(gef_getpagesize()))
            return

        # permission
        if re.match(r"[-_r][-_w][-_x]", args.permission):
            perm = Permission.NONE
            if args.permission[0] == "r":
                perm |= Permission.READ
            if args.permission[1] == "w":
                perm |= Permission.WRITE
            if args.permission[2] == "x":
                perm |= Permission.EXECUTE
        else:
            err("Invalid permission")
            return

        # flags
        flags = 0x22 # MAP_ANONYMOUS | MAP_PRIVATE
        if args.location != 0:
            flags |= 0x10 # MAP_FIXED
        if is_mips32() or is_mips64() or is_mipsn32():
            flags |= 0x800 # MAP_DENYWRITE (why?)

        # doit
        cmd = "call-syscall {:s} {:#x} {:#x} {:#x} {:#x} -1 0".format(mmap_syscall_name, args.location, args.size, perm, flags)
        gdb.execute(cmd)
        Cache.reset_gef_caches()
        return


@register_command
class ReadControlRegisterCommand(GenericCommand):
    """Read control register for kgdb."""
    _cmdline_ = "read-control-register"
    _category_ = "04-a. Register - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("reg_name", metavar="REGISTER_NAME", choices=["cr0", "cr2", "cr3", "cr4"],
                        help="register name to read a value.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} cr0".format(_cmdline_)

    def get_getter_address(self, reg_name):
        symbol = {
            "cr0": "native_read_cr0",
            "cr2": "pv_native_read_cr2",
            "cr3": "__native_read_cr3",
            "cr4": "cr4_init",
        }[reg_name]

        byte_code = {
            "cr0": b"\x0f\x20\xc0",
            "cr2": b"\x0f\x20\xd0",
            "cr3": b"\x0f\x20\xd8",
            "cr4": b"\x0f\x20\xe0",
        }[reg_name]

        # resolve symbol
        ret = gdb.execute("monitor {:s}".format(symbol), to_string=True)
        r = re.search(r"(0x\S+)", ret)
        if not r:
            return None
        address = int(r.group(1), 16)

        # adjust offset
        data = read_memory(address, 20)
        index = data.find(byte_code)
        if index >= 0:
            return address + index
        return None

    def execute_getter(self, getter_address):
        codes = []
        regs = {"$rip": getter_address}
        ret = ExecAsm(codes, regs=regs, step=1).exec_code()
        return ret["reg"][current_arch.return_register]

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("kgdb",))
    @only_if_specific_arch(arch=("x86_64",))
    def do_invoke(self, args):
        if current_arch is None:
            err("current_arch is not set.")
            return

        getter_address = self.get_getter_address(args.reg_name)
        if getter_address is None:
            err("Failed to get")
            return

        ret = self.execute_getter(getter_address)
        if ret is not None:
            gef_print("{:s} = {:#x}".format(args.reg_name, ret))
        return


@register_command
class ReadSystemRegisterCommand(GenericCommand):
    """Read system register for old qemu-system-arm."""
    _cmdline_ = "read-system-register"
    _category_ = "04-a. Register - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("reg_name", metavar="REGISTER_NAME", help="register name to read a value.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} TTBR0".format(_cmdline_)

    _note_ = "Attempting to read a non-existing register raises an undefined exception."

    # thanks to https://github.com/gdelugre/ida-arm-system-highlight
    # Extracted from the XML specifications for v8.7-A (2021-06).
    AARCH32_COPROC_REGISTERS = {
        ("p15", "c0", 0, "c0", 0): ("MIDR", "Main ID Register"),
        ("p15", "c0", 0, "c0", 1): ("CTR", "Cache Type Register"),
        ("p15", "c0", 0, "c0", 2): ("TCMTR", "TCM Type Register"),
        ("p15", "c0", 0, "c0", 3): ("TLBTR", "TLB Type Register"),
        ("p15", "c0", 0, "c0", 5): ("MPIDR", "Multiprocessor Affinity Register"),
        ("p15", "c0", 0, "c0", 6): ("REVIDR", "Revision ID Register"),

        # Aliases
        ("p15", "c0", 0, "c0", 4): ("MIDR", "Main ID Register"),
        ("p15", "c0", 0, "c0", 7): ("MIDR", "Main ID Register"),

        # CPUID registers
        ("p15", "c0", 0, "c1", 0): ("ID_PFR0", "Processor Feature Register 0"),
        ("p15", "c0", 0, "c1", 1): ("ID_PFR1", "Processor Feature Register 1"),
        ("p15", "c0", 0, "c3", 4): ("ID_PFR2", "Processor Feature Register 2"),
        ("p15", "c0", 0, "c1", 2): ("ID_DFR0", "Debug Feature Register 0"),
        ("p15", "c0", 0, "c1", 3): ("ID_AFR0", "Auxiliary Feature Register 0"),
        ("p15", "c0", 0, "c1", 4): ("ID_MMFR0", "Memory Model Feature Register 0"),
        ("p15", "c0", 0, "c1", 5): ("ID_MMFR1", "Memory Model Feature Register 1"),
        ("p15", "c0", 0, "c1", 6): ("ID_MMFR2", "Memory Model Feature Register 2"),
        ("p15", "c0", 0, "c1", 7): ("ID_MMFR3", "Memory Model Feature Register 3"),
        ("p15", "c0", 0, "c2", 6): ("ID_MMFR4", "Memory Model Feature Register 4"),
        ("p15", "c0", 0, "c3", 6): ("ID_MMFR5", "Memory Model Feature Register 5"),
        ("p15", "c0", 0, "c2", 0): ("ID_ISAR0", "Instruction Set Attribute Register 0"),
        ("p15", "c0", 0, "c2", 1): ("ID_ISAR1", "Instruction Set Attribute Register 1"),
        ("p15", "c0", 0, "c2", 2): ("ID_ISAR2", "Instruction Set Attribute Register 2"),
        ("p15", "c0", 0, "c2", 3): ("ID_ISAR3", "Instruction Set Attribute Register 3"),
        ("p15", "c0", 0, "c2", 4): ("ID_ISAR4", "Instruction Set Attribute Register 4"),
        ("p15", "c0", 0, "c2", 5): ("ID_ISAR5", "Instruction Set Attribute Register 5"),
        ("p15", "c0", 0, "c2", 7): ("ID_ISAR6", "Instruction Set Attribute Register 6"),

        ("p15", "c0", 1, "c0", 0): ("CCSIDR", "Current Cache Size ID Register"),
        ("p15", "c0", 1, "c0", 2): ("CCSIDR2", "Current Cache Size ID Register 2"),
        ("p15", "c0", 1, "c0", 1): ("CLIDR", "Cache Level ID Register"),
        ("p15", "c0", 1, "c0", 7): ("AIDR", "Auxiliary ID Register"),
        ("p15", "c0", 2, "c0", 0): ("CSSELR", "Cache Size Selection Register"),
        ("p15", "c0", 4, "c0", 0): ("VPIDR", "Virtualization Processor ID Register"),
        ("p15", "c0", 4, "c0", 5): ("VMPIDR", "Virtualization Multiprocessor ID Register"),

        # System control registers
        ("p15", "c1", 0, "c0", 0): ("SCTLR", "System Control Register"),
        ("p15", "c1", 0, "c0", 1): ("ACTLR", "Auxiliary Control Register"),
        ("p15", "c1", 0, "c0", 3): ("ACTLR2", "Auxiliary Control Register 2"),
        ("p15", "c1", 0, "c0", 2): ("CPACR", "Architectural Feature Access Control Register"),
        ("p15", "c1", 0, "c1", 0): ("SCR", "Secure Configuration Register"),
        ("p15", "c1", 0, "c1", 1): ("SDER", "Secure Debug Enable Register"),
        ("p15", "c1", 0, "c3", 1): ("SDCR", "Secure Debug Control Register"),
        ("p15", "c1", 0, "c1", 2): ("NSACR", "Non-Secure Access Control Register"),
        ("p15", "c1", 4, "c0", 0): ("HSCTLR", "Hyp System Control Register"),
        ("p15", "c1", 4, "c0", 1): ("HACTLR", "Hyp Auxiliary Control Register"),
        ("p15", "c1", 4, "c0", 3): ("HACTLR2", "Hyp Auxiliary Control Register 2"),
        ("p15", "c1", 4, "c1", 0): ("HCR", "Hyp Configuration Register"),
        ("p15", "c1", 4, "c1", 4): ("HCR2", "Hyp Configuration Register 2"),
        ("p15", "c1", 4, "c1", 1): ("HDCR", "Hyp Debug Control Register"),
        ("p15", "c1", 4, "c1", 2): ("HCPTR", "Hyp Architectural Feature Trap Register"),
        ("p15", "c1", 4, "c1", 3): ("HSTR", "Hyp System Trap Register"),
        ("p15", "c1", 4, "c1", 7): ("HACR", "Hyp Auxiliary Configuration Register"),

        # Translation Table Base Registers
        ("p15", "c2", 0, "c0", 0): ("TTBR0", "Translation Table Base Register 0"),
        ("p15", "c2", 0, "c0", 1): ("TTBR1", "Translation Table Base Register 1"),
        ("p15", "c2", 4, "c0", 2): ("HTCR", "Hyp Translation Control Register"),
        ("p15", "c2", 4, "c1", 2): ("VTCR", "Virtualization Translation Control Register"),
        ("p15", "c2", 0, "c0", 2): ("TTBCR", "Translation Table Base Control Register"),
        ("p15", "c2", 0, "c0", 3): ("TTBCR2", "Translation Table Base Control Register 2"),

        # Domain Access Control registers
        ("p15", "c3", 0, "c0", 0): ("DACR", "Domain Access Control Register"),

        # Fault Status registers
        ("p15", "c5", 0, "c0", 0): ("DFSR", "Data Fault Status Register"),
        ("p15", "c5", 0, "c0", 1): ("IFSR", "Instruction Fault Status Register"),
        ("p15", "c5", 0, "c1", 0): ("ADFSR", "Auxiliary Data Fault Status Register"),
        ("p15", "c5", 0, "c1", 1): ("AIFSR", "Auxiliary Instruction Fault Status Register"),
        ("p15", "c5", 4, "c1", 0): ("HADFSR", "Hyp Auxiliary Data Fault Status Register"),
        ("p15", "c5", 4, "c1", 1): ("HAIFSR", "Hyp Auxiliary Instruction Fault Status Register"),
        ("p15", "c5", 4, "c2", 0): ("HSR", "Hyp Syndrome Register"),

        # Fault Address registers
        ("p15", "c6", 0, "c0", 0): ("DFAR", "Data Fault Address Register"),
        ("p15", "c6", 0, "c0", 1): ("N/A", "Watchpoint Fault Address"), # ARM11
        ("p15", "c6", 0, "c0", 2): ("IFAR", "Instruction Fault Address Register"),
        ("p15", "c6", 4, "c0", 0): ("HDFAR", "Hyp Data Fault Address Register"),
        ("p15", "c6", 4, "c0", 2): ("HIFAR", "Hyp Instruction Fault Address Register"),
        ("p15", "c6", 4, "c0", 4): ("HPFAR", "Hyp IPA Fault Address Register"),

        # Cache maintenance registers
        ("p15", "c7", 0, "c0", 4): ("NOP", "No Operation / Wait For Interrupt"),
        ("p15", "c7", 0, "c1", 0): ("ICIALLUIS", "Instruction Cache Invalidate All to PoU, Inner Shareable"),
        ("p15", "c7", 0, "c1", 6): ("BPIALLIS", "Branch Predictor Invalidate All, Inner Shareable"),
        ("p15", "c7", 0, "c4", 0): ("PAR", "Physical Address Register"),
        ("p15", "c7", 0, "c5", 0): ("ICIALLU", "Instruction Cache Invalidate All to PoU"),
        ("p15", "c7", 0, "c5", 1): ("ICIMVAU", "Instruction Cache line Invalidate by VA to PoU"),
        ("p15", "c7", 0, "c5", 2): ("N/A", "Invalidate all instruction caches by set/way"), # ARM11
        ("p15", "c7", 0, "c5", 4): ("CP15ISB", "Instruction Synchronization Barrier System instruction"),
        ("p15", "c7", 0, "c5", 6): ("BPIALL", "Branch Predictor Invalidate All"),
        ("p15", "c7", 0, "c5", 7): ("BPIMVA", "Branch Predictor Invalidate by VA"),
        ("p15", "c7", 0, "c6", 0): ("N/A", "Invalidate entire data cache"),
        ("p15", "c7", 0, "c6", 1): ("DCIMVAC", "Data Cache line Invalidate by VA to PoC"),
        ("p15", "c7", 0, "c6", 2): ("DCISW", "Data Cache line Invalidate by Set/Way"),
        ("p15", "c7", 0, "c7", 0): ("N/A", "Invalidate instruction cache and data cache"), # ARM11
        ("p15", "c7", 0, "c8", 0): ("ATS1CPR", "Address Translate Stage 1 Current state PL1 Read"),
        ("p15", "c7", 0, "c8", 1): ("ATS1CPW", "Address Translate Stage 1 Current state PL1 Write"),
        ("p15", "c7", 0, "c8", 2): ("ATS1CUR", "Address Translate Stage 1 Current state Unprivileged Read"),
        ("p15", "c7", 0, "c8", 3): ("ATS1CUW", "Address Translate Stage 1 Current state Unprivileged Write"),
        ("p15", "c7", 0, "c8", 4): ("ATS12NSOPR", "Address Translate Stages 1 and 2 Non-secure Only PL1 Read"),
        ("p15", "c7", 0, "c8", 5): ("ATS12NSOPW", "Address Translate Stages 1 and 2 Non-secure Only PL1 Write"),
        ("p15", "c7", 0, "c8", 6): ("ATS12NSOUR", "Address Translate Stages 1 and 2 Non-secure Only Unprivileged Read"),
        ("p15", "c7", 0, "c8", 7): ("ATS12NSOUW", "Address Translate Stages 1 and 2 Non-secure Only Unprivileged Write"),
        ("p15", "c7", 0, "c9", 0): ("ATS1CPRP", "Address Translate Stage 1 Current state PL1 Read PAN"),
        ("p15", "c7", 0, "c9", 1): ("ATS1CPWP", "Address Translate Stage 1 Current state PL1 Write PAN"),
        ("p15", "c7", 0, "c10", 0): ("N/A", "Clean entire data cache"), # ARM11
        ("p15", "c7", 0, "c10", 1): ("DCCMVAC", "Data Cache line Clean by VA to PoC"),
        ("p15", "c7", 0, "c10", 2): ("DCCSW", "Data Cache line Clean by Set/Way"),
        ("p15", "c7", 0, "c10", 3): ("N/A", "Test and clean data cache"), # ARM9
        ("p15", "c7", 0, "c10", 4): ("CP15DSB", "Data Synchronization Barrier System instruction"),
        ("p15", "c7", 0, "c10", 5): ("CP15DMB", "Data Memory Barrier System instruction"),
        ("p15", "c7", 0, "c10", 6): ("N/A", "Read Cache Dirty Status Register"), # ARM11
        ("p15", "c7", 0, "c11", 1): ("DCCMVAU", "Data Cache line Clean by VA to PoU"),
        ("p15", "c7", 0, "c12", 4): ("N/A", "Read Block Transfer Status Register"), # ARM11
        ("p15", "c7", 0, "c12", 5): ("N/A", "Stop Prefetch Range"), # ARM11
        ("p15", "c7", 0, "c13", 1): ("NOP", "No Operation / Prefetch Instruction Cache Line"),
        ("p15", "c7", 0, "c14", 0): ("N/A", "Clean and invalidate entire data cache"), # ARM11
        ("p15", "c7", 0, "c14", 1): ("DCCIMVAC", "Data Cache line Clean and Invalidate by VA to PoC"),
        ("p15", "c7", 0, "c14", 2): ("DCCISW", "Data Cache line Clean and Invalidate by Set/Way"),
        ("p15", "c7", 0, "c14", 3): ("N/A", "Test, clean, and invalidate data cache"), # ARM9
        ("p15", "c7", 4, "c8", 0): ("ATS1HR", "Address Translate Stage 1 Hyp mode Read"),
        ("p15", "c7", 4, "c8", 1): ("ATS1HW", "Stage 1 Hyp mode write"),

        # TLB maintenance operations
        ("p15", "c8", 0, "c3", 0): ("TLBIALLIS", "TLB Invalidate All, Inner Shareable"),
        ("p15", "c8", 0, "c3", 1): ("TLBIMVAIS", "TLB Invalidate by VA, Inner Shareable"),
        ("p15", "c8", 0, "c3", 2): ("TLBIASIDIS", "TLB Invalidate by ASID match, Inner Shareable"),
        ("p15", "c8", 0, "c3", 3): ("TLBIMVAAIS", "TLB Invalidate by VA, All ASID, Inner Shareable"),
        ("p15", "c8", 0, "c3", 5): ("TLBIMVALIS", "TLB Invalidate by VA, Last level, Inner Shareable"),
        ("p15", "c8", 0, "c3", 7): ("TLBIMVAALIS", "TLB Invalidate by VA, All ASID, Last level, Inner Shareable"),
        ("p15", "c8", 0, "c5", 0): ("ITLBIALL", "Instruction TLB Invalidate All"),
        ("p15", "c8", 0, "c5", 1): ("ITLBIMVA", "Instruction TLB Invalidate by VA"),
        ("p15", "c8", 0, "c5", 2): ("ITLBIASID", "Instruction TLB Invalidate by ASID match"),
        ("p15", "c8", 0, "c6", 0): ("DTLBIALL", "Data TLB Invalidate All"),
        ("p15", "c8", 0, "c6", 1): ("DTLBIMVA", "Data TLB Invalidate by VA"),
        ("p15", "c8", 0, "c6", 2): ("DTLBIASID", "Data TLB Invalidate by ASID match"),
        ("p15", "c8", 0, "c7", 0): ("TLBIALL", "TLB Invalidate All"),
        ("p15", "c8", 0, "c7", 1): ("TLBIMVA", "TLB Invalidate by VA"),
        ("p15", "c8", 0, "c7", 2): ("TLBIASID", "TLB Invalidate by ASID match"),
        ("p15", "c8", 0, "c7", 3): ("TLBIMVAA", "TLB Invalidate by VA, All ASID"),
        ("p15", "c8", 0, "c7", 5): ("TLBIMVAL", "TLB Invalidate by VA, Last level"),
        ("p15", "c8", 0, "c7", 7): ("TLBIMVAAL", "TLB Invalidate by VA, All ASID, Last level"),
        ("p15", "c8", 4, "c0", 1): ("TLBIIPAS2IS", "TLB Invalidate by Intermediate Physical Address, Stage 2, Inner Shareable"),
        ("p15", "c8", 4, "c0", 5): ("TLBIIPAS2LIS", "TLB Invalidate by Intermediate Physical Address, Stage 2, Last level, Inner Shareable"),
        ("p15", "c8", 4, "c3", 0): ("TLBIALLHIS", "TLB Invalidate All, Hyp mode, Inner Shareable"),
        ("p15", "c8", 4, "c3", 1): ("TLBIMVAHIS", "TLB Invalidate by VA, Hyp mode, Inner Shareable"),
        ("p15", "c8", 4, "c3", 4): ("TLBIALLNSNHIS", "TLB Invalidate All, Non-Secure Non-Hyp, Inner Shareable"),
        ("p15", "c8", 4, "c3", 5): ("TLBIMVALHIS", "TLB Invalidate by VA, Last level, Hyp mode, Inner Shareable"),
        ("p15", "c8", 4, "c4", 1): ("TLBIIPAS2", "TLB Invalidate by Intermediate Physical Address, Stage 2"),
        ("p15", "c8", 4, "c4", 5): ("TLBIIPAS2L", "TLB Invalidate by Intermediate Physical Address, Stage 2, Last level"),
        ("p15", "c8", 4, "c7", 0): ("TLBIALLH", "TLB Invalidate All, Hyp mode"),
        ("p15", "c8", 4, "c7", 1): ("TLBIMVAH", "TLB Invalidate by VA, Hyp mode"),
        ("p15", "c8", 4, "c7", 4): ("TLBIALLNSNH", "TLB Invalidate All, Non-Secure Non-Hyp"),
        ("p15", "c8", 4, "c7", 5): ("TLBIMVALH", "TLB Invalidate by VA, Last level, Hyp mode"),

        ("p15", "c9", 0, "c0", 0): ("N/A", "Data Cache Lockdown"), # ARM11
        ("p15", "c9", 0, "c0", 1): ("N/A", "Instruction Cache Lockdown"), # ARM11
        ("p15", "c9", 0, "c1", 0): ("N/A", "Data TCM Region"), # ARM11
        ("p15", "c9", 0, "c1", 1): ("N/A", "Instruction TCM Region"), # ARM11
        ("p15", "c9", 1, "c0", 2): ("L2CTLR", "L2 Control Register"),
        ("p15", "c9", 1, "c0", 3): ("L2ECTLR", "L2 Extended Control Register"),

        # Performance monitor registers
        ("p15", "c9", 0, "c12", 0): ("PMCR", "Performance Monitors Control Register"),
        ("p15", "c9", 0, "c12", 1): ("PMCNTENSET", "Performance Monitor Count Enable Set Register"),
        ("p15", "c9", 0, "c12", 2): ("PMCNTENCLR", "Performance Monitor Control Enable Clear Register"),
        ("p15", "c9", 0, "c12", 3): ("PMOVSR", "Performance Monitors Overflow Flag Status Register"),
        ("p15", "c9", 0, "c12", 4): ("PMSWINC", "Performance Monitors Software Increment register"),
        ("p15", "c9", 0, "c12", 5): ("PMSELR", "Performance Monitors Event Counter Selection Register"),
        ("p15", "c9", 0, "c12", 6): ("PMCEID0", "Performance Monitors Common Event Identification register 0"),
        ("p15", "c9", 0, "c12", 7): ("PMCEID1", "Performance Monitors Common Event Identification register 1"),
        ("p15", "c9", 0, "c13", 0): ("PMCCNTR", "Performance Monitors Cycle Count Register"),
        ("p15", "c9", 0, "c13", 1): ("PMXEVTYPER", "Performance Monitors Selected Event Type Register"),
        ("p15", "c9", 0, "c13", 2): ("PMXEVCNTR", "Performance Monitors Selected Event Count Register"),
        ("p15", "c9", 0, "c14", 0): ("PMUSERENR", "Performance Monitors User Enable Register"),
        ("p15", "c9", 0, "c14", 1): ("PMINTENSET", "Performance Monitors Interrupt Enable Set register"),
        ("p15", "c9", 0, "c14", 2): ("PMINTENCLR", "Performance Monitors Interrupt Enable Clear register"),
        ("p15", "c9", 0, "c14", 3): ("PMOVSSET", "Performance Monitors Overflow Flag Status Set register"),
        ("p15", "c9", 0, "c14", 4): ("PMCEID2", "Performance Monitors Common Event Identification register 2"),
        ("p15", "c9", 0, "c14", 5): ("PMCEID3", "Performance Monitors Common Event Identification register 3"),
        ("p15", "c9", 0, "c14", 6): ("PMMIR", "Performance Monitors Machine Identification Register"),
        ("p15", "c14", 0, "c8", 0): ("PMEVCNTR0", "Performance Monitors Event Count Register 0"),
        ("p15", "c14", 0, "c8", 1): ("PMEVCNTR1", "Performance Monitors Event Count Register 1"),
        ("p15", "c14", 0, "c8", 2): ("PMEVCNTR2", "Performance Monitors Event Count Register 2"),
        ("p15", "c14", 0, "c8", 3): ("PMEVCNTR3", "Performance Monitors Event Count Register 3"),
        ("p15", "c14", 0, "c8", 4): ("PMEVCNTR4", "Performance Monitors Event Count Register 4"),
        ("p15", "c14", 0, "c8", 5): ("PMEVCNTR5", "Performance Monitors Event Count Register 5"),
        ("p15", "c14", 0, "c8", 6): ("PMEVCNTR6", "Performance Monitors Event Count Register 6"),
        ("p15", "c14", 0, "c8", 7): ("PMEVCNTR7", "Performance Monitors Event Count Register 7"),
        ("p15", "c14", 0, "c9", 0): ("PMEVCNTR8", "Performance Monitors Event Count Register 8"),
        ("p15", "c14", 0, "c9", 1): ("PMEVCNTR9", "Performance Monitors Event Count Register 9"),
        ("p15", "c14", 0, "c9", 2): ("PMEVCNTR10", "Performance Monitors Event Count Register 10"),
        ("p15", "c14", 0, "c9", 3): ("PMEVCNTR11", "Performance Monitors Event Count Register 11"),
        ("p15", "c14", 0, "c9", 4): ("PMEVCNTR12", "Performance Monitors Event Count Register 12"),
        ("p15", "c14", 0, "c9", 5): ("PMEVCNTR13", "Performance Monitors Event Count Register 13"),
        ("p15", "c14", 0, "c9", 6): ("PMEVCNTR14", "Performance Monitors Event Count Register 14"),
        ("p15", "c14", 0, "c9", 7): ("PMEVCNTR15", "Performance Monitors Event Count Register 15"),
        ("p15", "c14", 0, "c10", 0): ("PMEVCNTR16", "Performance Monitors Event Count Register 16"),
        ("p15", "c14", 0, "c10", 1): ("PMEVCNTR17", "Performance Monitors Event Count Register 17"),
        ("p15", "c14", 0, "c10", 2): ("PMEVCNTR18", "Performance Monitors Event Count Register 18"),
        ("p15", "c14", 0, "c10", 3): ("PMEVCNTR19", "Performance Monitors Event Count Register 19"),
        ("p15", "c14", 0, "c10", 4): ("PMEVCNTR20", "Performance Monitors Event Count Register 20"),
        ("p15", "c14", 0, "c10", 5): ("PMEVCNTR21", "Performance Monitors Event Count Register 21"),
        ("p15", "c14", 0, "c10", 6): ("PMEVCNTR22", "Performance Monitors Event Count Register 22"),
        ("p15", "c14", 0, "c10", 7): ("PMEVCNTR23", "Performance Monitors Event Count Register 23"),
        ("p15", "c14", 0, "c11", 0): ("PMEVCNTR24", "Performance Monitors Event Count Register 24"),
        ("p15", "c14", 0, "c11", 1): ("PMEVCNTR25", "Performance Monitors Event Count Register 25"),
        ("p15", "c14", 0, "c11", 2): ("PMEVCNTR26", "Performance Monitors Event Count Register 26"),
        ("p15", "c14", 0, "c11", 3): ("PMEVCNTR27", "Performance Monitors Event Count Register 27"),
        ("p15", "c14", 0, "c11", 4): ("PMEVCNTR28", "Performance Monitors Event Count Register 28"),
        ("p15", "c14", 0, "c11", 5): ("PMEVCNTR29", "Performance Monitors Event Count Register 29"),
        ("p15", "c14", 0, "c11", 6): ("PMEVCNTR30", "Performance Monitors Event Count Register 30"),
        ("p15", "c14", 0, "c12", 0): ("PMEVTYPER0", "Performance Monitors Event Type Register 0"),
        ("p15", "c14", 0, "c12", 1): ("PMEVTYPER1", "Performance Monitors Event Type Register 1"),
        ("p15", "c14", 0, "c12", 2): ("PMEVTYPER2", "Performance Monitors Event Type Register 2"),
        ("p15", "c14", 0, "c12", 3): ("PMEVTYPER3", "Performance Monitors Event Type Register 3"),
        ("p15", "c14", 0, "c12", 4): ("PMEVTYPER4", "Performance Monitors Event Type Register 4"),
        ("p15", "c14", 0, "c12", 5): ("PMEVTYPER5", "Performance Monitors Event Type Register 5"),
        ("p15", "c14", 0, "c12", 6): ("PMEVTYPER6", "Performance Monitors Event Type Register 6"),
        ("p15", "c14", 0, "c12", 7): ("PMEVTYPER7", "Performance Monitors Event Type Register 7"),
        ("p15", "c14", 0, "c13", 0): ("PMEVTYPER8", "Performance Monitors Event Type Register 8"),
        ("p15", "c14", 0, "c13", 1): ("PMEVTYPER9", "Performance Monitors Event Type Register 9"),
        ("p15", "c14", 0, "c13", 2): ("PMEVTYPER10", "Performance Monitors Event Type Register 10"),
        ("p15", "c14", 0, "c13", 3): ("PMEVTYPER11", "Performance Monitors Event Type Register 11"),
        ("p15", "c14", 0, "c13", 4): ("PMEVTYPER12", "Performance Monitors Event Type Register 12"),
        ("p15", "c14", 0, "c13", 5): ("PMEVTYPER13", "Performance Monitors Event Type Register 13"),
        ("p15", "c14", 0, "c13", 6): ("PMEVTYPER14", "Performance Monitors Event Type Register 14"),
        ("p15", "c14", 0, "c13", 7): ("PMEVTYPER15", "Performance Monitors Event Type Register 15"),
        ("p15", "c14", 0, "c14", 0): ("PMEVTYPER16", "Performance Monitors Event Type Register 16"),
        ("p15", "c14", 0, "c14", 1): ("PMEVTYPER17", "Performance Monitors Event Type Register 17"),
        ("p15", "c14", 0, "c14", 2): ("PMEVTYPER18", "Performance Monitors Event Type Register 18"),
        ("p15", "c14", 0, "c14", 3): ("PMEVTYPER19", "Performance Monitors Event Type Register 19"),
        ("p15", "c14", 0, "c14", 4): ("PMEVTYPER20", "Performance Monitors Event Type Register 20"),
        ("p15", "c14", 0, "c14", 5): ("PMEVTYPER21", "Performance Monitors Event Type Register 21"),
        ("p15", "c14", 0, "c14", 6): ("PMEVTYPER22", "Performance Monitors Event Type Register 22"),
        ("p15", "c14", 0, "c14", 7): ("PMEVTYPER23", "Performance Monitors Event Type Register 23"),
        ("p15", "c14", 0, "c15", 0): ("PMEVTYPER24", "Performance Monitors Event Type Register 24"),
        ("p15", "c14", 0, "c15", 1): ("PMEVTYPER25", "Performance Monitors Event Type Register 25"),
        ("p15", "c14", 0, "c15", 2): ("PMEVTYPER26", "Performance Monitors Event Type Register 26"),
        ("p15", "c14", 0, "c15", 3): ("PMEVTYPER27", "Performance Monitors Event Type Register 27"),
        ("p15", "c14", 0, "c15", 4): ("PMEVTYPER28", "Performance Monitors Event Type Register 28"),
        ("p15", "c14", 0, "c15", 5): ("PMEVTYPER29", "Performance Monitors Event Type Register 29"),
        ("p15", "c14", 0, "c15", 6): ("PMEVTYPER30", "Performance Monitors Event Type Register 30"),
        ("p15", "c14", 0, "c15", 7): ("PMCCFILTR", "Performance Monitors Cycle Count Filter Register"),

        # Activity Monitors
        ("p15", "c13", 0, "c2", 1): ("AMCFGR", "Activity Monitors Configuration Register"),
        ("p15", "c13", 0, "c2", 2): ("AMCGCR", "Activity Monitors Counter Group Configuration Register"),
        ("p15", "c13", 0, "c2", 4): ("AMCNTENCLR0", "Activity Monitors Count Enable Clear Register 0"),
        ("p15", "c13", 0, "c3", 0): ("AMCNTENCLR1", "Activity Monitors Count Enable Clear Register 1"),
        ("p15", "c13", 0, "c2", 5): ("AMCNTENSET0", "Activity Monitors Count Enable Set Register 0"),
        ("p15", "c13", 0, "c3", 1): ("AMCNTENSET1", "Activity Monitors Count Enable Set Register 1"),
        ("p15", "c13", 0, "c2", 0): ("AMCR", "Activity Monitors Control Register"),
        ("p15", "c13", 0, "c6", 0): ("AMEVTYPER00", "Activity Monitors Event Type Registers 0"),
        ("p15", "c13", 0, "c6", 1): ("AMEVTYPER01", "Activity Monitors Event Type Registers 0"),
        ("p15", "c13", 0, "c6", 2): ("AMEVTYPER02", "Activity Monitors Event Type Registers 0"),
        ("p15", "c13", 0, "c14", 0): ("AMEVTYPER10", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c14", 1): ("AMEVTYPER11", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c14", 2): ("AMEVTYPER12", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c14", 3): ("AMEVTYPER13", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c14", 4): ("AMEVTYPER14", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c14", 5): ("AMEVTYPER15", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c14", 6): ("AMEVTYPER16", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c14", 7): ("AMEVTYPER17", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c15", 0): ("AMEVTYPER18", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c15", 1): ("AMEVTYPER19", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c15", 2): ("AMEVTYPER110", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c15", 3): ("AMEVTYPER111", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c15", 4): ("AMEVTYPER112", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c15", 5): ("AMEVTYPER113", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c15", 6): ("AMEVTYPER114", "Activity Monitors Event Type Registers 1"),
        ("p15", "c13", 0, "c2", 3): ("AMUSERENR", "Activity Monitors User Enable Register"),

        # Reliability
        ("p15", "c12", 0, "c1", 1): ("DISR", "Deferred Interrupt Status Register"),
        ("p15", "c5", 0, "c3", 0): ("ERRIDR", "Error Record ID Register"),
        ("p15", "c5", 0, "c3", 1): ("ERRSELR", "Error Record Select Register"),
        ("p15", "c5", 0, "c4", 3): ("ERXADDR", "Selected Error Record Address Register"),
        ("p15", "c5", 0, "c4", 7): ("ERXADDR2", "Selected Error Record Address Register 2"),
        ("p15", "c5", 0, "c4", 1): ("ERXCTLR", "Selected Error Record Control Register"),
        ("p15", "c5", 0, "c4", 5): ("ERXCTLR2", "Selected Error Record Control Register 2"),
        ("p15", "c5", 0, "c4", 0): ("ERXFR", "Selected Error Record Feature Register"),
        ("p15", "c5", 0, "c4", 4): ("ERXFR2", "Selected Error Record Feature Register 2"),
        ("p15", "c5", 0, "c5", 0): ("ERXMISC0", "Selected Error Record Miscellaneous Register 0"),
        ("p15", "c5", 0, "c5", 1): ("ERXMISC1", "Selected Error Record Miscellaneous Register 1"),
        ("p15", "c5", 0, "c5", 4): ("ERXMISC2", "Selected Error Record Miscellaneous Register 2"),
        ("p15", "c5", 0, "c5", 5): ("ERXMISC3", "Selected Error Record Miscellaneous Register 3"),
        ("p15", "c5", 0, "c5", 2): ("ERXMISC4", "Selected Error Record Miscellaneous Register 4"),
        ("p15", "c5", 0, "c5", 3): ("ERXMISC5", "Selected Error Record Miscellaneous Register 5"),
        ("p15", "c5", 0, "c5", 6): ("ERXMISC6", "Selected Error Record Miscellaneous Register 6"),
        ("p15", "c5", 0, "c5", 7): ("ERXMISC7", "Selected Error Record Miscellaneous Register 7"),
        ("p15", "c5", 0, "c4", 2): ("ERXSTATUS", "Selected Error Record Primary Status Register"),
        ("p15", "c5", 4, "c2", 3): ("VDFSR", "Virtual SError Exception Syndrome Register"),
        ("p15", "c12", 4, "c1", 1): ("VDISR", "Virtual Deferred Interrupt Status Register"),

        # Memory attribute registers
        ("p15", "c10", 0, "c0", 0): ("N/A", "TLB Lockdown"), # ARM11
        ("p15", "c10", 0, "c2", 0): ("MAIR0", "Memory Attribute Indirection Register 0",
                                     "PRRR", "Primary Region Remap Register"),
        ("p15", "c10", 0, "c2", 1): ("MAIR1", "Memory Attribute Indirection Register 1",
                                     "NMRR", "Normal Memory Remap Register"),
        ("p15", "c10", 0, "c3", 0): ("AMAIR0", "Auxiliary Memory Attribute Indirection Register 0"),
        ("p15", "c10", 0, "c3", 1): ("AMAIR1", "Auxiliary Memory Attribute Indirection Register 1"),
        ("p15", "c10", 4, "c2", 0): ("HMAIR0", "Hyp Memory Attribute Indirection Register 0"),
        ("p15", "c10", 4, "c2", 1): ("HMAIR1", "Hyp Memory Attribute Indirection Register 1"),
        ("p15", "c10", 4, "c3", 0): ("HAMAIR0", "Hyp Auxiliary Memory Attribute Indirection Register 0"),
        ("p15", "c10", 4, "c3", 1): ("HAMAIR1", "Hyp Auxiliary Memory Attribute Indirection Register 1"),

        # DMA registers (ARM11)
        # This definition conflicts with other coprocessor definitions.
        # ARM v6 architecture (ARM11 core) is old and will be abandoned.
        #("p15", "c11", 0, "c0", 0): ("N/A", "DMA Identification and Status (Present)"),
        #("p15", "c11", 0, "c0", 1): ("N/A", "DMA Identification and Status (Queued)"),
        #("p15", "c11", 0, "c0", 2): ("N/A", "DMA Identification and Status (Running)"),
        #("p15", "c11", 0, "c0", 3): ("N/A", "DMA Identification and Status (Interrupting)"),
        #("p15", "c11", 0, "c1", 0): ("N/A", "DMA User Accessibility"),
        #("p15", "c11", 0, "c2", 0): ("N/A", "DMA Channel Number"),
        #("p15", "c11", 0, "c3", 0): ("N/A", "DMA Enable (Stop)"),
        #("p15", "c11", 0, "c3", 1): ("N/A", "DMA Enable (Start)"),
        #("p15", "c11", 0, "c3", 2): ("N/A", "DMA Enable (Clear)"),
        #("p15", "c11", 0, "c4", 0): ("N/A", "DMA Control"),
        #("p15", "c11", 0, "c5", 0): ("N/A", "DMA Internal Start Address"),
        #("p15", "c11", 0, "c6", 0): ("N/A", "DMA External Start Address"),
        #("p15", "c11", 0, "c7", 0): ("N/A", "DMA Internal End Address"),
        #("p15", "c11", 0, "c8", 0): ("N/A", "DMA Channel Status"),
        #("p15", "c11", 0, "c15", 0): ("N/A", "DMA Context ID"),

        # Reset management registers.
        ("p15", "c12", 0, "c0", 0): ("VBAR", "Vector Base Address Register"),
        ("p15", "c12", 0, "c0", 1): ("RVBAR", "Reset Vector Base Address Register" ,
                                     "MVBAR", "Monitor Vector Base Address Register"),
        ("p15", "c12", 0, "c0", 2): ("RMR", "Reset Management Register"),
        ("p15", "c12", 4, "c0", 2): ("HRMR", "Hyp Reset Management Register"),

        ("p15", "c12", 0, "c1", 0): ("ISR", "Interrupt Status Register"),
        ("p15", "c12", 4, "c0", 0): ("HVBAR", "Hyp Vector Base Address Register"),

        ("p15", "c13", 0, "c0", 0): ("FCSEIDR", "FCSE Process ID register"),
        ("p15", "c13", 0, "c0", 1): ("CONTEXTIDR", "Context ID Register"),
        ("p15", "c13", 0, "c0", 2): ("TPIDRURW", "PL0 Read/Write Software Thread ID Register"),
        ("p15", "c13", 0, "c0", 3): ("TPIDRURO", "PL0 Read-Only Software Thread ID Register"),
        ("p15", "c13", 0, "c0", 4): ("TPIDRPRW", "PL1 Software Thread ID Register"),
        ("p15", "c13", 4, "c0", 2): ("HTPIDR", "Hyp Software Thread ID Register"),

        # Generic timer registers.
        ("p15", "c14", 0, "c0", 0): ("CNTFRQ", "Counter-timer Frequency register"),
        ("p15", "c14", 0, "c1", 0): ("CNTKCTL", "Counter-timer Kernel Control register"),
        ("p15", "c14", 0, "c2", 0): ("CNTP_TVAL", "Counter-timer Physical Timer TimerValue register",
                                     "CNTHP_TVAL", "Counter-timer Hyp Physical Timer TimerValue register",
                                     "CNTHPS_TVAL", "Counter-timer Secure Physical Timer TimerValue Register (EL2)"),
        ("p15", "c14", 0, "c2", 1): ("CNTP_CTL", "Counter-timer Physical Timer Control register",
                                     "CNTHP_CTL", "Counter-timer Hyp Physical Timer Control register",
                                     "CNTHPS_CTL", "Counter-timer Secure Physical Timer Control Register (EL2)"),
        ("p15", "c14", 0, "c3", 0): ("CNTV_TVAL", "Counter-timer Virtual Timer TimerValue register",
                                     "CNTHV_TVAL", "Counter-timer Virtual Timer TimerValue register (EL2)",
                                     "CNTHVS_TVAL", "Counter-timer Secure Virtual Timer TimerValue Register (EL2)"),
        ("p15", "c14", 0, "c3", 1): ("CNTV_CTL", "Counter-timer Virtual Timer Control register",
                                     "CNTHV_CTL", "Counter-timer Virtual Timer Control register (EL2)",
                                     "CNTHVS_CTL", "Counter-timer Secure Virtual Timer Control Register (EL2)"),
        ("p15", "c14", 4, "c1", 0): ("CNTHCTL", "Counter-timer Hyp Control register"),
        ("p15", "c14", 4, "c2", 0): ("CNTHP_TVAL", "Counter-timer Hyp Physical Timer TimerValue register"),
        ("p15", "c14", 4, "c2", 1): ("CNTHP_CTL", "Counter-timer Hyp Physical Timer Control register"),

        # Generic interrupt controller registers.
        ("p15", "c4", 0, "c6", 0): ("ICC_PMR", "Interrupt Controller Interrupt Priority Mask Register",
                                    "ICV_PMR", "Interrupt Controller Virtual Interrupt Priority Mask Register"),
        ("p15", "c12", 0, "c8", 0): ("ICC_IAR0", "Interrupt Controller Interrupt Acknowledge Register 0",
                                     "ICV_IAR0", "Interrupt Controller Virtual Interrupt Acknowledge Register 0"),
        ("p15", "c12", 0, "c8", 1): ("ICC_EOIR0", "Interrupt Controller End Of Interrupt Register 0",
                                     "ICV_EOIR0", "Interrupt Controller Virtual End Of Interrupt Register 0"),
        ("p15", "c12", 0, "c8", 2): ("ICC_HPPIR0", "Interrupt Controller Highest Priority Pending Interrupt Register 0",
                                     "ICV_HPPIR0", "Interrupt Controller Virtual Highest Priority Pending Interrupt Register 0"),
        ("p15", "c12", 0, "c8", 3): ("ICC_BPR0", "Interrupt Controller Binary Point Register 0",
                                     "ICV_BPR0", "Interrupt Controller Virtual Binary Point Register 0"),
        ("p15", "c12", 0, "c8", 4): ("ICC_AP0R0", "Interrupt Controller Active Priorities Group 0 Register 0",
                                     "ICV_AP0R0", "Interrupt Controller Virtual Active Priorities Group 0 Register 0"),
        ("p15", "c12", 0, "c8", 5): ("ICC_AP0R1", "Interrupt Controller Active Priorities Group 0 Register 1",
                                     "ICV_AP0R1", "Interrupt Controller Virtual Active Priorities Group 0 Register 1"),
        ("p15", "c12", 0, "c8", 6): ("ICC_AP0R2", "Interrupt Controller Active Priorities Group 0 Register 2",
                                     "ICV_AP0R2", "Interrupt Controller Virtual Active Priorities Group 0 Register 2"),
        ("p15", "c12", 0, "c8", 7): ("ICC_AP0R3", "Interrupt Controller Active Priorities Group 0 Register 3",
                                     "ICV_AP0R3", "Interrupt Controller Virtual Active Priorities Group 0 Register 3"),
        ("p15", "c12", 0, "c9", 0): ("ICC_AP1R0", "Interrupt Controller Active Priorities Group 1 Register 0",
                                     "ICV_AP1R0", "Interrupt Controller Virtual Active Priorities Group 1 Register 0"),
        ("p15", "c12", 0, "c9", 1): ("ICC_AP1R1", "Interrupt Controller Active Priorities Group 1 Register 1",
                                     "ICV_AP1R1", "Interrupt Controller Virtual Active Priorities Group 1 Register 1"),
        ("p15", "c12", 0, "c9", 2): ("ICC_AP1R2", "Interrupt Controller Active Priorities Group 1 Register 2",
                                     "ICV_AP1R2", "Interrupt Controller Virtual Active Priorities Group 1 Register 2"),
        ("p15", "c12", 0, "c9", 3): ("ICC_AP1R3", "Interrupt Controller Active Priorities Group 1 Register 3",
                                     "ICV_AP1R3", "Interrupt Controller Virtual Active Priorities Group 1 Register 3"),
        ("p15", "c12", 0, "c11", 1): ("ICC_DIR", "Interrupt Controller Deactivate Interrupt Register",
                                      "ICV_DIR", "Interrupt Controller Deactivate Virtual Interrupt Register"),
        ("p15", "c12", 0, "c11", 3): ("ICC_RPR", "Interrupt Controller Running Priority Register",
                                      "ICV_RPR", "Interrupt Controller Virtual Running Priority Register"),
        ("p15", "c12", 0, "c12", 0): ("ICC_IAR1", "Interrupt Controller Interrupt Acknowledge Register 1",
                                      "ICV_IAR1", "Interrupt Controller Virtual Interrupt Acknowledge Register 1"),
        ("p15", "c12", 0, "c12", 1): ("ICC_EOIR1", "Interrupt Controller End Of Interrupt Register 1",
                                      "ICV_EOIR1", "Interrupt Controller Virtual End Of Interrupt Register 1"),
        ("p15", "c12", 0, "c12", 2): ("ICC_HPPIR1", "Interrupt Controller Highest Priority Pending Interrupt Register 1",
                                      "ICV_HPPIR1", "Interrupt Controller Virtual Highest Priority Pending Interrupt Register 1"),
        ("p15", "c12", 0, "c12", 3): ("ICC_BPR1", "Interrupt Controller Binary Point Register 1",
                                      "ICV_BPR1", "Interrupt Controller Virtual Binary Point Register 1"),
        ("p15", "c12", 0, "c12", 4): ("ICC_CTLR", "Interrupt Controller Control Register",
                                      "ICV_CTLR", "Interrupt Controller Virtual Control Register"),
        ("p15", "c12", 0, "c12", 5): ("ICC_SRE", "Interrupt Controller System Register Enable register"),
        ("p15", "c12", 0, "c12", 6): ("ICC_IGRPEN0", "Interrupt Controller Interrupt Group 0 Enable register",
                                      "ICV_IGRPEN0", "Interrupt Controller Virtual Interrupt Group 0 Enable register"),
        ("p15", "c12", 0, "c12", 7): ("ICC_IGRPEN1", "Interrupt Controller Interrupt Group 1 Enable register",
                                      "ICV_IGRPEN1", "Interrupt Controller Virtual Interrupt Group 1 Enable register"),
        ("p15", "c12", 4, "c8", 0): ("ICH_AP0R0", "Interrupt Controller Hyp Active Priorities Group 0 Register 0"),
        ("p15", "c12", 4, "c8", 1): ("ICH_AP0R1", "Interrupt Controller Hyp Active Priorities Group 0 Register 1"),
        ("p15", "c12", 4, "c8", 2): ("ICH_AP0R2", "Interrupt Controller Hyp Active Priorities Group 0 Register 2"),
        ("p15", "c12", 4, "c8", 3): ("ICH_AP0R3", "Interrupt Controller Hyp Active Priorities Group 0 Register 3"),
        ("p15", "c12", 4, "c9", 0): ("ICH_AP1R0", "Interrupt Controller Hyp Active Priorities Group 1 Register 0"),
        ("p15", "c12", 4, "c9", 1): ("ICH_AP1R1", "Interrupt Controller Hyp Active Priorities Group 1 Register 1"),
        ("p15", "c12", 4, "c9", 2): ("ICH_AP1R2", "Interrupt Controller Hyp Active Priorities Group 1 Register 2"),
        ("p15", "c12", 4, "c9", 3): ("ICH_AP1R3", "Interrupt Controller Hyp Active Priorities Group 1 Register 3"),
        ("p15", "c12", 4, "c9", 5): ("ICC_HSRE", "Interrupt Controller Hyp System Register Enable register"),
        ("p15", "c12", 4, "c11", 0): ("ICH_HCR", "Interrupt Controller Hyp Control Register"),
        ("p15", "c12", 4, "c11", 1): ("ICH_VTR", "Interrupt Controller VGIC Type Register"),
        ("p15", "c12", 4, "c11", 2): ("ICH_MISR", "Interrupt Controller Maintenance Interrupt State Register"),
        ("p15", "c12", 4, "c11", 3): ("ICH_EISR", "Interrupt Controller End of Interrupt Status Register"),
        ("p15", "c12", 4, "c11", 5): ("ICH_ELRSR", "Interrupt Controller Empty List Register Status Register"),
        ("p15", "c12", 4, "c11", 7): ("ICH_VMCR", "Interrupt Controller Virtual Machine Control Register"),
        ("p15", "c12", 4, "c12", 0): ("ICH_LR0", "Interrupt Controller List Register 0"),
        ("p15", "c12", 4, "c12", 1): ("ICH_LR1", "Interrupt Controller List Register 1"),
        ("p15", "c12", 4, "c12", 2): ("ICH_LR2", "Interrupt Controller List Register 2"),
        ("p15", "c12", 4, "c12", 3): ("ICH_LR3", "Interrupt Controller List Register 3"),
        ("p15", "c12", 4, "c12", 4): ("ICH_LR4", "Interrupt Controller List Register 4"),
        ("p15", "c12", 4, "c12", 5): ("ICH_LR5", "Interrupt Controller List Register 5"),
        ("p15", "c12", 4, "c12", 6): ("ICH_LR6", "Interrupt Controller List Register 6"),
        ("p15", "c12", 4, "c12", 7): ("ICH_LR7", "Interrupt Controller List Register 7"),
        ("p15", "c12", 4, "c13", 0): ("ICH_LR8", "Interrupt Controller List Register 8"),
        ("p15", "c12", 4, "c13", 1): ("ICH_LR9", "Interrupt Controller List Register 9"),
        ("p15", "c12", 4, "c13", 2): ("ICH_LR10", "Interrupt Controller List Register 10"),
        ("p15", "c12", 4, "c13", 3): ("ICH_LR11", "Interrupt Controller List Register 11"),
        ("p15", "c12", 4, "c13", 4): ("ICH_LR12", "Interrupt Controller List Register 12"),
        ("p15", "c12", 4, "c13", 5): ("ICH_LR13", "Interrupt Controller List Register 13"),
        ("p15", "c12", 4, "c13", 6): ("ICH_LR14", "Interrupt Controller List Register 14"),
        ("p15", "c12", 4, "c13", 7): ("ICH_LR15", "Interrupt Controller List Register 15"),
        ("p15", "c12", 4, "c14", 0): ("ICH_LRC0", "Interrupt Controller List Register 0"),
        ("p15", "c12", 4, "c14", 1): ("ICH_LRC1", "Interrupt Controller List Register 1"),
        ("p15", "c12", 4, "c14", 2): ("ICH_LRC2", "Interrupt Controller List Register 2"),
        ("p15", "c12", 4, "c14", 3): ("ICH_LRC3", "Interrupt Controller List Register 3"),
        ("p15", "c12", 4, "c14", 4): ("ICH_LRC4", "Interrupt Controller List Register 4"),
        ("p15", "c12", 4, "c14", 5): ("ICH_LRC5", "Interrupt Controller List Register 5"),
        ("p15", "c12", 4, "c14", 6): ("ICH_LRC6", "Interrupt Controller List Register 6"),
        ("p15", "c12", 4, "c14", 7): ("ICH_LRC7", "Interrupt Controller List Register 7"),
        ("p15", "c12", 4, "c15", 0): ("ICH_LRC8", "Interrupt Controller List Register 8"),
        ("p15", "c12", 4, "c15", 1): ("ICH_LRC9", "Interrupt Controller List Register 9"),
        ("p15", "c12", 4, "c15", 2): ("ICH_LRC10", "Interrupt Controller List Register 10"),
        ("p15", "c12", 4, "c15", 3): ("ICH_LRC11", "Interrupt Controller List Register 11"),
        ("p15", "c12", 4, "c15", 4): ("ICH_LRC12", "Interrupt Controller List Register 12"),
        ("p15", "c12", 4, "c15", 5): ("ICH_LRC13", "Interrupt Controller List Register 13"),
        ("p15", "c12", 4, "c15", 6): ("ICH_LRC14", "Interrupt Controller List Register 14"),
        ("p15", "c12", 4, "c15", 7): ("ICH_LRC15", "Interrupt Controller List Register 15"),
        ("p15", "c12", 6, "c12", 4): ("ICC_MCTLR", "Interrupt Controller Monitor Control Register"),
        ("p15", "c12", 6, "c12", 5): ("ICC_MSRE", "Interrupt Controller Monitor System Register Enable register"),
        ("p15", "c12", 6, "c12", 7): ("ICC_MGRPEN1", "Interrupt Controller Monitor Interrupt Group 1 Enable register"),

        ("p15", "c15", 0, "c0", 0): ("IL1Data0", "Instruction L1 Data n Register"),
        ("p15", "c15", 0, "c0", 1): ("IL1Data1", "Instruction L1 Data n Register"),
        ("p15", "c15", 0, "c0", 2): ("IL1Data2", "Instruction L1 Data n Register"),
        ("p15", "c15", 0, "c1", 0): ("DL1Data0", "Data L1 Data n Register"),
        ("p15", "c15", 0, "c1", 1): ("DL1Data1", "Data L1 Data n Register"),
        ("p15", "c15", 0, "c1", 2): ("DL1Data2", "Data L1 Data n Register"),
        ("p15", "c15", 0, "c2", 0): ("N/A", "Data Memory Remap"), # ARM11
        ("p15", "c15", 0, "c2", 1): ("N/A", "Instruction Memory Remap"), # ARM11
        ("p15", "c15", 0, "c2", 2): ("N/A", "DMA Memory Remap"), # ARM11
        ("p15", "c15", 0, "c2", 3): ("N/A", "Peripheral Port Memory Remap"), # ARM11
        ("p15", "c15", 0, "c4", 0): ("RAMINDEX", "RAM Index Register"),
        ("p15", "c15", 0, "c12", 0): ("N/A", "Performance Monitor Control"), # ARM11
        ("p15", "c15", 0, "c12", 1): ("CCNT", "Cycle Counter"), # ARM11
        ("p15", "c15", 0, "c12", 2): ("PMN0", "Count 0"), # ARM11
        ("p15", "c15", 0, "c12", 3): ("PMN1", "Count 1"), # ARM11
        ("p15", "c15", 1, "c0", 0): ("L2ACTLR", "L2 Auxiliary Control Register"),
        ("p15", "c15", 1, "c0", 3): ("L2FPR", "L2 Prefetch Control Register"),
        ("p15", "c15", 3, "c0", 0): ("N/A", "Data Debug Cache"), # ARM11
        ("p15", "c15", 3, "c0", 1): ("N/A", "Instruction Debug Cache"), # ARM11
        ("p15", "c15", 3, "c2", 0): ("N/A", "Data Tag RAM Read Operation"), # ARM11
        ("p15", "c15", 3, "c2", 1): ("N/A", "Instruction Tag RAM Read Operation"), # ARM11
        ("p15", "c15", 4, "c0", 0): ("CBAR", "Configuration Base Address Register"),
        ("p15", "c15", 5, "c4", 0): ("N/A", "Data MicroTLB Index"), # ARM11
        ("p15", "c15", 5, "c4", 1): ("N/A", "Instruction MicroTLB Index"), # ARM11
        ("p15", "c15", 5, "c4", 2): ("N/A", "Read Main TLB Entry"), # ARM11
        ("p15", "c15", 5, "c4", 4): ("N/A", "Write Main TLB Entry"), # ARM11
        ("p15", "c15", 5, "c5", 0): ("N/A", "Data MicroTLB VA"), # ARM11
        ("p15", "c15", 5, "c5", 1): ("N/A", "Instruction MicroTLB VA"), # ARM11
        ("p15", "c15", 5, "c5", 2): ("N/A", "Main TLB VA"), # ARM11
        ("p15", "c15", 5, "c7", 0): ("N/A", "Data MicroTLB Attribute"), # ARM11
        ("p15", "c15", 5, "c7", 1): ("N/A", "Instruction MicroTLB Attribute"), # ARM11
        ("p15", "c15", 5, "c7", 2): ("N/A", "Main TLB Attribute"), # ARM11
        ("p15", "c15", 7, "c0", 0): ("N/A", "Cache Debug Control"), # ARM11
        ("p15", "c15", 7, "c1", 0): ("N/A", "TLB Debug Control"), # ARM11

        # Preload Engine control registers
        ("p15", "c11", 0, "c0", 0): ("PLEIDR", "Preload Engine ID Register"),
        ("p15", "c11", 0, "c0", 2): ("PLEASR", "Preload Engine Activity Status Register"),
        ("p15", "c11", 0, "c0", 4): ("PLEFSR", "Preload Engine FIFO Status Register"),
        ("p15", "c11", 0, "c1", 0): ("PLEUAR", "Preload Engine User Accessibility Register"),
        ("p15", "c11", 0, "c1", 1): ("PLEPCR", "Preload Engine Parameters Control Register"),

        # Preload Engine operations
        ("p15", "c11", 0, "c2", 1): ("PLEFF", "Preload Engine FIFO flush operation"),
        ("p15", "c11", 0, "c3", 0): ("PLEPC", "Preload Engine pause channel operation"),
        ("p15", "c11", 0, "c3", 1): ("PLERC", "Preload Engine resume channel operation"),
        ("p15", "c11", 0, "c3", 2): ("PLEKC", "Preload Engine kill channel operation"),

        # Jazelle registers
        ("p14", "c0", 7, "c0", 0): ("JIDR", "Jazelle ID Register"),
        ("p14", "c1", 7, "c0", 0): ("JOSCR", "Jazelle OS Control Register"),
        ("p14", "c2", 7, "c0", 0): ("JMCR", "Jazelle Main Configuration Register"),

        # Debug registers
        ("p15", "c4", 3, "c5", 0): ("DSPSR", "Debug Saved Program Status Register"),
        ("p15", "c4", 3, "c5", 1): ("DLR", "Debug Link Register"),
        ("p15", "c0", 0, "c3", 5): ("ID_DFR1", "Debug Feature Register 1"),
        ("p14", "c0", 0, "c0", 0): ("DBGDIDR", "Debug ID Register"),
        ("p14", "c0", 0, "c6", 0): ("DBGWFAR", "Debug Watchpoint Fault Address Register"),
        ("p14", "c0", 0, "c6", 2): ("DBGOSECCR", "Debug OS Lock Exception Catch Control Register"),
        ("p14", "c0", 0, "c7", 0): ("DBGVCR", "Debug Vector Catch Register"),
        ("p14", "c0", 0, "c0", 2): ("DBGDTRRXext", "Debug OS Lock Data Transfer Register, Receive, External View"),
        ("p14", "c0", 0, "c2", 0): ("DBGDCCINT", "DCC Interrupt Enable Register"),
        ("p14", "c0", 0, "c2", 2): ("DBGDSCRext", "Debug Status and Control Register, External View"),
        ("p14", "c0", 0, "c3", 2): ("DBGDTRTXext", "Debug OS Lock Data Transfer Register, Transmit"),
        ("p14", "c0", 0, "c0", 4): ("DBGBVR0", "Debug Breakpoint Value Register 0"),
        ("p14", "c0", 0, "c1", 4): ("DBGBVR1", "Debug Breakpoint Value Register 1"),
        ("p14", "c0", 0, "c2", 4): ("DBGBVR2", "Debug Breakpoint Value Register 2"),
        ("p14", "c0", 0, "c3", 4): ("DBGBVR3", "Debug Breakpoint Value Register 3"),
        ("p14", "c0", 0, "c4", 4): ("DBGBVR4", "Debug Breakpoint Value Register 4"),
        ("p14", "c0", 0, "c5", 4): ("DBGBVR5", "Debug Breakpoint Value Register 5"),
        ("p14", "c0", 0, "c6", 4): ("DBGBVR6", "Debug Breakpoint Value Register 6"),
        ("p14", "c0", 0, "c7", 4): ("DBGBVR7", "Debug Breakpoint Value Register 7"),
        ("p14", "c0", 0, "c8", 4): ("DBGBVR8", "Debug Breakpoint Value Register 8"),
        ("p14", "c0", 0, "c9", 4): ("DBGBVR9", "Debug Breakpoint Value Register 9"),
        ("p14", "c0", 0, "c10", 4): ("DBGBVR10", "Debug Breakpoint Value Register 10"),
        ("p14", "c0", 0, "c11", 4): ("DBGBVR11", "Debug Breakpoint Value Register 11"),
        ("p14", "c0", 0, "c12", 4): ("DBGBVR12", "Debug Breakpoint Value Register 12"),
        ("p14", "c0", 0, "c13", 4): ("DBGBVR13", "Debug Breakpoint Value Register 13"),
        ("p14", "c0", 0, "c14", 4): ("DBGBVR14", "Debug Breakpoint Value Register 14"),
        ("p14", "c0", 0, "c15", 4): ("DBGBVR15", "Debug Breakpoint Value Register 15"),
        ("p14", "c0", 0, "c0", 5): ("DBGBCR0", "Debug Breakpoint Control Register 0"),
        ("p14", "c0", 0, "c1", 5): ("DBGBCR1", "Debug Breakpoint Control Register 1"),
        ("p14", "c0", 0, "c2", 5): ("DBGBCR2", "Debug Breakpoint Control Register 2"),
        ("p14", "c0", 0, "c3", 5): ("DBGBCR3", "Debug Breakpoint Control Register 3"),
        ("p14", "c0", 0, "c4", 5): ("DBGBCR4", "Debug Breakpoint Control Register 4"),
        ("p14", "c0", 0, "c5", 5): ("DBGBCR5", "Debug Breakpoint Control Register 5"),
        ("p14", "c0", 0, "c6", 5): ("DBGBCR6", "Debug Breakpoint Control Register 6"),
        ("p14", "c0", 0, "c7", 5): ("DBGBCR7", "Debug Breakpoint Control Register 7"),
        ("p14", "c0", 0, "c8", 5): ("DBGBCR8", "Debug Breakpoint Control Register 8"),
        ("p14", "c0", 0, "c9", 5): ("DBGBCR9", "Debug Breakpoint Control Register 9"),
        ("p14", "c0", 0, "c10", 5): ("DBGBCR10", "Debug Breakpoint Control Register 10"),
        ("p14", "c0", 0, "c11", 5): ("DBGBCR11", "Debug Breakpoint Control Register 11"),
        ("p14", "c0", 0, "c12", 5): ("DBGBCR12", "Debug Breakpoint Control Register 12"),
        ("p14", "c0", 0, "c13", 5): ("DBGBCR13", "Debug Breakpoint Control Register 13"),
        ("p14", "c0", 0, "c14", 5): ("DBGBCR14", "Debug Breakpoint Control Register 14"),
        ("p14", "c0", 0, "c15", 5): ("DBGBCR15", "Debug Breakpoint Control Register 15"),
        ("p14", "c0", 0, "c0", 6): ("DBGWVR0", "Debug Watchpoint Value Register 0"),
        ("p14", "c0", 0, "c1", 6): ("DBGWVR1", "Debug Watchpoint Value Register 1"),
        ("p14", "c0", 0, "c2", 6): ("DBGWVR2", "Debug Watchpoint Value Register 2"),
        ("p14", "c0", 0, "c3", 6): ("DBGWVR3", "Debug Watchpoint Value Register 3"),
        ("p14", "c0", 0, "c4", 6): ("DBGWVR4", "Debug Watchpoint Value Register 4"),
        ("p14", "c0", 0, "c5", 6): ("DBGWVR5", "Debug Watchpoint Value Register 5"),
        ("p14", "c0", 0, "c6", 6): ("DBGWVR6", "Debug Watchpoint Value Register 6"),
        ("p14", "c0", 0, "c7", 6): ("DBGWVR7", "Debug Watchpoint Value Register 7"),
        ("p14", "c0", 0, "c8", 6): ("DBGWVR8", "Debug Watchpoint Value Register 8"),
        ("p14", "c0", 0, "c9", 6): ("DBGWVR9", "Debug Watchpoint Value Register 9"),
        ("p14", "c0", 0, "c10", 6): ("DBGWVR10", "Debug Watchpoint Value Register 10"),
        ("p14", "c0", 0, "c11", 6): ("DBGWVR11", "Debug Watchpoint Value Register 11"),
        ("p14", "c0", 0, "c12", 6): ("DBGWVR12", "Debug Watchpoint Value Register 12"),
        ("p14", "c0", 0, "c13", 6): ("DBGWVR13", "Debug Watchpoint Value Register 13"),
        ("p14", "c0", 0, "c14", 6): ("DBGWVR14", "Debug Watchpoint Value Register 14"),
        ("p14", "c0", 0, "c15", 6): ("DBGWVR15", "Debug Watchpoint Value Register 15"),
        ("p14", "c0", 0, "c0", 7): ("DBGWCR0", "Debug Watchpoint Control Register 0"),
        ("p14", "c0", 0, "c1", 7): ("DBGWCR1", "Debug Watchpoint Control Register 1"),
        ("p14", "c0", 0, "c2", 7): ("DBGWCR2", "Debug Watchpoint Control Register 2"),
        ("p14", "c0", 0, "c3", 7): ("DBGWCR3", "Debug Watchpoint Control Register 3"),
        ("p14", "c0", 0, "c4", 7): ("DBGWCR4", "Debug Watchpoint Control Register 4"),
        ("p14", "c0", 0, "c5", 7): ("DBGWCR5", "Debug Watchpoint Control Register 5"),
        ("p14", "c0", 0, "c6", 7): ("DBGWCR6", "Debug Watchpoint Control Register 6"),
        ("p14", "c0", 0, "c7", 7): ("DBGWCR7", "Debug Watchpoint Control Register 7"),
        ("p14", "c0", 0, "c8", 7): ("DBGWCR8", "Debug Watchpoint Control Register 8"),
        ("p14", "c0", 0, "c9", 7): ("DBGWCR9", "Debug Watchpoint Control Register 9"),
        ("p14", "c0", 0, "c10", 7): ("DBGWCR10", "Debug Watchpoint Control Register 10"),
        ("p14", "c0", 0, "c11", 7): ("DBGWCR11", "Debug Watchpoint Control Register 11"),
        ("p14", "c0", 0, "c12", 7): ("DBGWCR12", "Debug Watchpoint Control Register 12"),
        ("p14", "c0", 0, "c13", 7): ("DBGWCR13", "Debug Watchpoint Control Register 13"),
        ("p14", "c0", 0, "c14", 7): ("DBGWCR14", "Debug Watchpoint Control Register 14"),
        ("p14", "c0", 0, "c15", 7): ("DBGWCR15", "Debug Watchpoint Control Register 15"),
        ("p14", "c1", 0, "c0", 1): ("DBGBXVR0", "Debug Breakpoint Extended Value Register 0"),
        ("p14", "c1", 0, "c1", 1): ("DBGBXVR1", "Debug Breakpoint Extended Value Register 1"),
        ("p14", "c1", 0, "c2", 1): ("DBGBXVR2", "Debug Breakpoint Extended Value Register 2"),
        ("p14", "c1", 0, "c3", 1): ("DBGBXVR3", "Debug Breakpoint Extended Value Register 3"),
        ("p14", "c1", 0, "c4", 1): ("DBGBXVR4", "Debug Breakpoint Extended Value Register 4"),
        ("p14", "c1", 0, "c5", 1): ("DBGBXVR5", "Debug Breakpoint Extended Value Register 5"),
        ("p14", "c1", 0, "c6", 1): ("DBGBXVR6", "Debug Breakpoint Extended Value Register 6"),
        ("p14", "c1", 0, "c7", 1): ("DBGBXVR7", "Debug Breakpoint Extended Value Register 7"),
        ("p14", "c1", 0, "c8", 1): ("DBGBXVR8", "Debug Breakpoint Extended Value Register 8"),
        ("p14", "c1", 0, "c9", 1): ("DBGBXVR9", "Debug Breakpoint Extended Value Register 9"),
        ("p14", "c1", 0, "c10", 1): ("DBGBXVR10", "Debug Breakpoint Extended Value Register 10"),
        ("p14", "c1", 0, "c11", 1): ("DBGBXVR11", "Debug Breakpoint Extended Value Register 11"),
        ("p14", "c1", 0, "c12", 1): ("DBGBXVR12", "Debug Breakpoint Extended Value Register 12"),
        ("p14", "c1", 0, "c13", 1): ("DBGBXVR13", "Debug Breakpoint Extended Value Register 13"),
        ("p14", "c1", 0, "c14", 1): ("DBGBXVR14", "Debug Breakpoint Extended Value Register 14"),
        ("p14", "c1", 0, "c15", 1): ("DBGBXVR15", "Debug Breakpoint Extended Value Register 15"),
        ("p14", "c1", 0, "c0", 4): ("DBGOSLAR", "Debug OS Lock Access Register"),
        ("p14", "c1", 0, "c1", 4): ("DBGOSLSR", "Debug OS Lock Status Register"),
        ("p14", "c1", 0, "c4", 4): ("DBGPRCR", "Debug Power Control Register"),
        ("p14", "c7", 0, "c14", 6): ("DBGAUTHSTATUS", "Debug Authentication Status register"),
        ("p14", "c7", 0, "c0", 7): ("DBGDEVID2", "Debug Device ID register 2"),
        ("p14", "c7", 0, "c1", 7): ("DBGDEVID1", "Debug Device ID register 1"),
        ("p14", "c7", 0, "c2", 7): ("DBGDEVID", "Debug Device ID register 0"),
        ("p14", "c7", 0, "c8", 6): ("DBGCLAIMSET", "Debug Claim Tag Set register"),
        ("p14", "c7", 0, "c9", 6): ("DBGCLAIMCLR", "Debug Claim Tag Clear register"),
        ("p14", "c0", 0, "c1", 0): ("DBGDSCRint", "Debug Status and Control Register, Internal View"),
        ("p14", "c0", 0, "c5", 0): ("DBGDTRRXint", "Debug Data Transfer Register, Receive",
                                    "DBGDTRTXint", "Debug Data Transfer Register, Transmit"),
        ("p14", "c1", 0, "c0", 0): ("DBGDRAR", "Debug ROM Address Register"),
        ("p14", "c1", 0, "c3", 4): ("DBGOSDLR", "Debug OS Double Lock Register"),
        ("p14", "c2", 0, "c0", 0): ("DBGDSAR", "Debug Self Address Register"),
        ("p15", "c1", 4, "c2", 1): ("HTRFCR", "Hyp Trace Filter Control Register"),
        ("p15", "c1", 0, "c2", 1): ("TRFCR", "Trace Filter Control Register"),
    }

    def get_coproc_info(self, target_reg_name):
        for k, v in self.AARCH32_COPROC_REGISTERS.items():
            for reg_name, _desc in slicer(v, 2):
                if target_reg_name == reg_name:
                    return k
        return None

    def get_mrc_code(self, cp_info):
        code = "mrc {:s}, {:d}, r0, {:s}, {:s}, {:d}".format(cp_info[0], cp_info[2], cp_info[1], cp_info[3], cp_info[4])
        arch, mode = UnicornKeystoneCapstone.get_keystone_arch()
        raw_insns = UnicornKeystoneCapstone.keystone_assemble(code, arch, mode, raw=True)
        return raw_insns

    def mrc_execute(self, reg_name):
        cp_info = self.get_coproc_info(reg_name)
        if cp_info is None:
            return None
        codes = [self.get_mrc_code(cp_info)]

        before_pc = current_arch.pc
        ret = ExecAsm(codes).exec_code()
        after_pc = ret["reg"]["$pc"]

        # It jumps to the undefined exception vector if an attempt is made to a register that does not exist.
        # Even though I just stepped through it, the PC register values are very different.
        if abs(after_pc - before_pc) > 0x10:
            err("Undefined register. It probably crashes the kernel.")
            return None
        return ret["reg"][current_arch.return_register]

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM32",))
    def do_invoke(self, args):
        if current_arch is None:
            err("current_arch is not set.")
            return

        reg_name = args.reg_name.upper()
        if reg_name.startswith("$"):
            reg_name = reg_name[1:]

        ret = self.mrc_execute(reg_name)
        if ret is not None:
            gef_print("{:s} = {:#x}".format(reg_name, ret))
        return


@register_command
class UnicornEmulateCommand(GenericCommand):
    """Use Unicorn-Engine to emulate the behavior of the binary."""
    _cmdline_ = "unicorn-emulate"
    _category_ = "01-d. Debugging Support - Execution"
    _aliases_ = ["emulate"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--from-location", type=AddressUtil.parse_address,
                        help="specifies the start address of the emulated run. (default: current_arch.pc)")
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-g", "--nb-gadget", type=AddressUtil.parse_address,
                        help="the number of gadgets to execute. (default mode, NB_GADGET: 10)")
    group.add_argument("-t", "--to-location", type=AddressUtil.parse_address,
                        help="the end address of the emulated run.")
    group.add_argument("-n", "--nb-insn", type=AddressUtil.parse_address,
                        help="the number of instructions from `FROM_LOCATION`.")
    parser.add_argument("-i", "--only-insns", action="store_true",
                        help="show only instructions (no registers, memories, etc).")
    parser.add_argument("-o", "--output-path",
                        help="writes the persistent Unicorn script into this file.")
    parser.add_argument("-s", "--skip-emulation", action="store_true",
                        help="do not run, just save the script.")
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="displays the register values for each instruction is executed.")
    parser.add_argument("--add-sse", action="store_true",
                        help="initialization and display XMM registers (only x64/x86).")
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet execution.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -g 10                        # from $pc to the point where 4 instructions are executed\n".format(_cmdline_)
    _example_ += "{:s} -n 5                         # from $pc to 5 later instructions (assume it is no branch)\n".format(_cmdline_)
    _example_ += "{:s} -t 0x805678a4 -o /tmp/emu.py # from $pc to specified address with saving script".format(_cmdline_)

    _note_ = "unicorn does not support emulating syscall.\n"
    _note_ += "unicorn does not support some instructions. (e.g.: xsavec, xrstor, vpbroadcastb, etc.)\n"
    _note_ += "unicorn does not emulate ARM kernel-provided-user-helpers like $pc=0xffff0fe0, 0xffff0fc0, etc.\n"
    _note_ += "see: https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt"

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def get_unicorn_end_addr(self, start_addr, nb):
        dis = list(Disasm.gef_disassemble(start_addr, nb + 1))
        last_insn = dis[-1]
        return last_insn.address

    def run_unicorn(self, start_insn_addr, end_insn_addr, *args, **kwargs):
        arch, mode = UnicornKeystoneCapstone.get_unicorn_arch(to_string=True)
        unicorn_registers = UnicornKeystoneCapstone.get_unicorn_registers(to_string=True, add_sse=kwargs["add_sse"])
        cs_arch, cs_mode = UnicornKeystoneCapstone.get_capstone_arch(to_string=True)

        pythonbin = GefUtil.which("python3")
        if is_remote_debug():
            filepath = gdb.current_progspace().filename
            if filepath.startswith("target:"):
                filepath = filepath[7:]
            filename = os.path.basename(filepath)
        else:
            filename = Path.get_filename()

        content = "#!{:s} -i\n".format(pythonbin)
        content += "#\n"
        content += "# Emulation script for '{:s}'".format(filename)
        if kwargs["nb_gadget"]:
            content += " from {:#x} to after {:#x} gadgets\n".format(start_insn_addr, kwargs["nb_gadget"])
        else:
            content += " from {:#x} to {:#x}\n".format(start_insn_addr, end_insn_addr)
        content += "#\n"
        content += "# Powered by gef, unicorn-engine, and capstone-engine\n"
        content += "#\n"
        content += "# original:  by @_hugsy_\n"
        content += "# improvement: by @bata_24\n"
        content += "#\n"
        content += "from __future__ import print_function\n"
        content += "import sys\n"
        content += "import traceback\n"
        content += "import collections\n"
        content += "import capstone\n"
        content += "import unicorn\n"
        if is_ppc64() or is_ppc32():
            content += "import unicorn.ppc_const\n"
        elif is_riscv32() or is_riscv64():
            content += "import unicorn.riscv_const\n"
        elif is_s390x():
            content += "import unicorn.s390x_const\n"
        content += "\n"

        content += "registers = collections.OrderedDict({\n"
        for r in unicorn_registers:
            content += "    '{:s}': {:s},\n".format(r.strip(), unicorn_registers[r])
        content += "})\n"
        content += "uc = None\n"
        content += "verbose = {!s}\n".format(kwargs["verbose"])
        content += "quiet = {!s}\n".format(kwargs["quiet"])
        content += "only_insns = {!s}\n".format(kwargs["only_insns"])
        content += "syscall_register = '{:s}'\n".format(current_arch.syscall_register)
        content += "count = 0\n"
        content += "changed_mem = {}\n"
        if is_arm32():
            content += "enable_thumb = {:d}\n".format(int(kwargs["thumb_mode"]))
            content += "\n"
            content += "\n"
            content += "def thumb_check(emu, insn):\n"
            content += "    global enable_thumb\n"
            content += "    if insn.mnemonic in ['blx', 'bx']:\n"
            content += "        enable_thumb = emu.reg_read(registers['$' + insn.op_str]) & 1\n"
            content += "    return\n"

            # hack: unicorn can handle if thumb or not, but capstone can't.
            # we have to handle it manually for capstone.
            # since CS_MODE_ARM is 0x0, it can be ignored. we represent
            # status of thumb: CS_MODE_THUMB * (0 or 1).
            endian = cs_mode.split(" + ")[-1]
            cs_mode = "capstone.CS_MODE_THUMB * enable_thumb + " + endian

        content += "\n"
        content += "\n"
        content += "cs = capstone.Cs({:s}, {:s})\n".format(cs_arch, cs_mode)
        content += "\n"
        content += "\n"
        content += "def disassemble(code, addr):\n"
        content += "    for i in cs.disasm(code, addr):\n"
        content += "        return i\n"
        content += "\n"
        content += "\n"
        content += "def code_hook(emu, address, size, user_data):\n"
        content += "    global count\n"
        content += "    if not quiet:\n"
        # min() is the workaround since unicorn passes 0xf1f1f1f1 as size if opcode is unsupported.
        # The execution will be failed, but the information of the error message increases.
        content += "        code = emu.mem_read(address, min(size, 0x10))\n"
        content += "        insn = disassemble(code, address)\n"
        content += "        code_hex = code[:insn.size].hex()\n"
        content += "        if verbose:\n"
        content += "            print_regs(emu, registers)\n"
        content += "        fmt = '>>> {:d} {:#x}: {:24s} {:s} {:s}'\n"
        content += "        print(fmt.format(count, insn.address, code_hex, insn.mnemonic, insn.op_str))\n"
        if is_arm32():
            content += "        thumb_check(emu, insn)\n"
        content += "    count += 1\n"
        content += "    return\n"
        content += "\n"
        content += "\n"
        content += "def mem_invalid_hook(emu, access, address, size, value, user_data):\n"
        content += "    if access == unicorn.UC_MEM_WRITE_INVALID:\n"
        content += "        fmt = '  --> Invalid memory access; addr:{:#x}, size:{:#x}, value:{:#x}'\n"
        content += "        print(fmt.format(address, size, value))\n"
        content += "    elif access == unicorn.UC_MEM_READ_INVALID:\n"
        content += "        fmt = '  --> Invalid memory access; addr:{:#x}, size:{:#x}'\n"
        content += "        print(fmt.format(address, size))\n"
        content += "    return\n"
        content += "\n"
        content += "\n"
        content += "def mem_write_hook(emu, access, address, size, value, user_data):\n"
        content += "    if only_insns:\n"
        content += "        return\n"
        content += "    before = emu.mem_read(address, size)\n"
        content += "    for i in range(size):\n"
        content += "        accessed_address = address + i\n"
        content += "        if accessed_address not in changed_mem:\n"
        content += "            changed_mem[accessed_address] = {}\n"
        content += "            changed_mem[accessed_address]['before'] = before[i]\n"
        content += "        changed_mem[accessed_address]['after'] = (value >> (8 * i)) & 0xff\n"
        content += "        changed_mem[accessed_address]['type'] = 'modified'\n"
        content += "    return\n"
        content += "\n"
        content += "\n"
        content += "def intr_hook(emu, intno, data):\n"
        content += "    print('  --> interrupt={:d}'.format(intno))\n"
        content += "    raise\n"
        content += "\n"
        content += "\n"
        content += "def syscall_hook(emu, user_data):\n"
        content += "    sysno = emu.reg_read(registers[syscall_register])\n"
        content += "    print('  --> syscall={:d} (not emulated)'.format(sysno))\n"
        content += "    return\n"
        content += "\n"
        content += "\n"
        content += "def print_regs(emu, regs):\n"
        content += "    if only_insns:\n"
        content += "        return\n"
        content += "    for i, r in enumerate(regs):\n"
        content += "        if r.startswith('$xmm'):\n"
        content += "          fmt = '{{:7s}} = {{:#0{:d}x}}  '\n".format(32 + 2)
        content += "          print(fmt.format(r, emu.reg_read(regs[r])), end='')\n"
        content += "          if (i % 2 == 1) or (i == len(regs) - 1):\n"
        content += "              print('')\n"
        content += "        else:\n"
        content += "          fmt = '{{:7s}} = {{:#0{:d}x}}  '\n".format(current_arch.ptrsize * 2 + 2)
        content += "          print(fmt.format(r, emu.reg_read(regs[r])), end='')\n"
        content += "          if (i % 4 == 3) or (i == len(regs) - 1):\n"
        content += "              print('')\n"
        content += "    return\n"
        content += "\n"
        content += "\n"
        content += "def print_mems(emu):\n"
        content += "    if only_insns:\n"
        content += "        return\n"
        content += "    aligned_addrs = set([x & ~0xf for x in changed_mem.keys()])\n"
        content += "    for aligned_addr in aligned_addrs:\n"
        content += "        for pad_addr in range(aligned_addr, aligned_addr + 0x10):\n"
        content += "            if pad_addr in changed_mem:\n"
        content += "                pass\n"
        content += "            else:\n"
        content += "                changed_mem[pad_addr] = {}\n"
        content += "                changed_mem[pad_addr]['before'] = emu.mem_read(pad_addr, 1)[0]\n"
        content += "                changed_mem[pad_addr]['after'] = emu.mem_read(pad_addr, 1)[0]\n"
        content += "                changed_mem[pad_addr]['type'] = None\n"
        content += "    sorted_data = sorted(changed_mem.items())\n"
        content += "    sliced = [sorted_data[i:i + 16] for i in range(0, len(sorted_data), 16)]\n"
        content += "    prev_address = None\n"
        content += "    for chunk in sliced:\n"
        content += "        address = chunk[0][0]\n"
        content += "        prefix = '{:#018x}'.format(address)\n"
        content += "        before = ''\n"
        content += "        after = ''\n"
        content += "        for i in range(16):\n"
        content += "            a = chunk[i][1]['after']\n"
        content += "            b = chunk[i][1]['before']\n"
        content += "            if a == b:\n"
        content += "                if chunk[i][1]['type'] is None:\n"
        content += "                    before += '{:02x} '.format(b)\n"
        content += "                    after += '{:02x} '.format(a)\n"
        content += "                else:\n"
        content += "                    before += '\033[2m{:02x}\033[0m '.format(b)\n"
        content += "                    after += '\033[2m{:02x}\033[0m '.format(a)\n"
        content += "            else:\n"
        content += "                before += '\033[2m\033[1m{:02x}\033[0m '.format(b)\n"
        content += "                after += '\033[2m\033[1m{:02x}\033[0m '.format(a)\n"
        content += "        line = '{:s} | {:s}| {:s}|'.format(prefix, before, after)\n"
        content += "        if prev_address is not None and prev_address + 0x10 != address:\n"
        content += "            print('*')\n"
        content += "        print(line)\n"
        content += "        prev_address = address\n"
        content += "    print('\033[2m00\033[0m: write accessed, ', end='')\n"
        content += "    print('\033[2m\033[1m00\033[0m: value changes')\n"
        content += "    return\n"

        if is_x86():
            # need to handle segmentation (and pagination) via MSR
            content += "\n"
            content += "\n"
            content += "# from https://github.com/unicorn-engine/unicorn/blob/master/tests/regress/x86_64_msr.py\n"
            content += "SCRATCH_ADDR = 0xf000\n"
            if is_x86_64():
                content += "FS_GS_MSR = 0xC0000100\n"
            else:
                content += "FS_GS_MSR = 0xC0000101\n"
            content += "\n"
            content += "\n"
            content += "def set_msr(uc, msr, value, scratch=SCRATCH_ADDR):\n"
            content += "    buf = b'\\x0f\\x30' # x86: wrmsr\n"
            content += "    uc.mem_map(scratch, 0x1000)\n"
            content += "    uc.mem_write(scratch, buf)\n"
            if is_x86_64():
                content += "    uc.reg_write(unicorn.x86_const.UC_X86_REG_RAX, value & 0xFFFFFFFF)\n"
                content += "    uc.reg_write(unicorn.x86_const.UC_X86_REG_RDX, (value >> 32) & 0xFFFFFFFF)\n"
                content += "    uc.reg_write(unicorn.x86_const.UC_X86_REG_RCX, msr & 0xFFFFFFFF)\n"
            else:
                content += "    uc.reg_write(unicorn.x86_const.UC_X86_REG_EAX, value & 0xFFFFFFFF)\n"
                content += "    uc.reg_write(unicorn.x86_const.UC_X86_REG_EDX, (value >> 32) & 0xFFFFFFFF)\n"
                content += "    uc.reg_write(unicorn.x86_const.UC_X86_REG_ECX, msr & 0xFFFFFFFF)\n"
            content += "    uc.emu_start(scratch, scratch + len(buf), count=1)\n"
            content += "    uc.mem_unmap(scratch, 0x1000)\n"
            content += "    return\n"
            content += "\n"
            content += "\n"
            content += "def set_tls(uc, addr):\n"
            content += "    return set_msr(uc, FS_GS_MSR, addr)\n"

        content += "\n"
        content += "\n"
        content += "def reset():\n"
        content += "    emu = unicorn.Uc({arch}, {mode})\n".format(arch=arch, mode=mode)

        if is_x86():
            content += "\n"
            content += "\n"
            content += "    set_tls(emu, {:#x})\n".format(current_arch.get_tls())

        if kwargs["verbose"]:
            info("Duplicating registers")

        if is_arm32() or is_arm64():
            # need first. because other register values may be broken when $cpsr is set.
            gregval = get_register("$cpsr")
            content += "    emu.reg_write({:s}, {:#x})\n".format(unicorn_registers["$cpsr"], gregval)
        for reg in current_arch.all_registers:
            if is_x86_64() and reg == "$fs":
                continue
            # On x86, writing to the segment register somehow fails, so skip it.
            if is_x86_32() and reg in X86.special_registers:
                continue
            if (is_arm32() or is_arm64()) and reg == "$cpsr":
                continue
            gregval = get_register(reg)
            content += "    emu.reg_write({:s}, {:#x})\n".format(unicorn_registers[reg], gregval)

        if kwargs["add_sse"]:
            lines = Color.remove_color(gdb.execute("xmm", to_string=True))
            for reg in ["$xmm{:d}".format(i) for i in range(16)]:
                r = re.findall("\\" + reg + r" +: (0x\S+)", lines)
                if r:
                    gregval = int(r[0], 16)
                    content += "    emu.reg_write({:s}, {:#x})\n".format(unicorn_registers[reg], gregval)
        content += "\n"

        Cache.reset_gef_caches(all=True)

        vmmap = ProcessMap.get_process_maps()
        if not vmmap:
            warn("An error occurred when reading memory map.")
            return

        if kwargs["verbose"]:
            info("Duplicating memory map")

        for sect in vmmap:
            if sect.path in ["[vvar]", "[vectors]", "[sigpage]"]:
                continue

            content += "    # Mapping {:s}: {:#x}-{:#x}\n".format(sect.path, sect.page_start, sect.page_end)
            content += "    emu.mem_map({:#x}, {:#x}, {})\n".format(sect.page_start, sect.size, oct(sect.permission.value))

            if sect.permission & Permission.READ:
                code = read_memory(sect.page_start, sect.size)
                loc = os.path.join(GEF_TEMP_DIR, "unicorn-emulate-{:s}-{:#x}.raw".format(filename, sect.page_start))
                open(loc, "wb").write(bytes(code))
                content += "    emu.mem_write({:#x}, open('{:s}', 'rb').read())\n".format(sect.page_start, loc)
                content += "\n"

        content += "    emu.hook_add(unicorn.UC_HOOK_CODE, code_hook)\n"
        content += "    emu.hook_add(unicorn.UC_HOOK_INTR, intr_hook)\n"
        if is_x86_64():
            content += "    emu.hook_add(unicorn.UC_HOOK_INSN, syscall_hook, None, 1, 0, unicorn.x86_const.UC_X86_INS_SYSCALL)\n"
        content += "    emu.hook_add(unicorn.UC_HOOK_MEM_READ_INVALID | unicorn.UC_HOOK_MEM_WRITE_INVALID, mem_invalid_hook)\n"
        content += "    emu.hook_add(unicorn.UC_HOOK_MEM_WRITE, mem_write_hook)\n"
        content += "    return emu\n"

        content += "\n"
        content += "\n"
        content += "def emulate(emu, start_addr, end_addr, count):\n"
        content += "    if not only_insns:\n"
        content += "        print('========================= Initial registers =========================')\n"
        content += "        print_regs(emu, registers)\n"
        content += "\n"
        content += "    if not only_insns:\n"
        content += "        print('========================= Starting emulation =========================')\n"
        content += "    try:\n"
        content += "        emu.emu_start(start_addr, end_addr, count=count)\n"
        content += "    except Exception:\n"
        content += "        emu.emu_stop()\n"
        content += "        print('========================= Emulation failed =========================')\n"
        content += "        traceback.print_exc(file=sys.stdout)\n"
        content += "\n"
        content += "    if not only_insns:\n"
        content += "        print('========================= Final registers =========================')\n"
        content += "        print_regs(emu, registers)\n"
        content += "        print('========================= Modified memories (before | after) =========================')\n"
        content += "        print_mems(emu)\n"
        content += "    return\n"
        content += "\n"
        content += "\n"
        content += "uc = reset()\n"
        content += "emulate(uc, {:#x}, {:#x}, {:#x})\n".format(start_insn_addr, end_insn_addr, kwargs["nb_gadget"] or -1)
        content += "\n"
        content += "\n"
        content += "# unicorn-engine script generated by gef\n"

        if kwargs["to_file"]:
            tmp_filename = kwargs["to_file"]
            tmp_fd_ = open(kwargs["to_file"], "w")
            tmp_fd = tmp_fd_.fileno()
        else:
            tmp_fd, tmp_filename = tempfile.mkstemp(dir=GEF_TEMP_DIR, suffix=".py", prefix="gef-uc-")
        os.fdopen(tmp_fd, "w").write(content)
        if kwargs["to_file"] or kwargs["skip_emulation"]:
            info("Unicorn script generated as '{:s}'".format(tmp_filename))
            os.chmod(tmp_filename, 0o700)

        if kwargs["skip_emulation"]:
            return

        if kwargs["nb_gadget"] is None:
            ok("Starting emulation: {:#x} {:s} {:#x}".format(
                start_insn_addr, RIGHT_ARROW, end_insn_addr,
            ))
        else:
            ok("Starting emulation: {:#x} {:s} after {:d} instructions are executed".format(
                start_insn_addr, RIGHT_ARROW, kwargs["nb_gadget"],
            ))

        try:
            res = GefUtil.gef_execute_external([pythonbin, tmp_filename], as_list=True)
            gef_print("\n".join(res))
        except subprocess.CalledProcessError as e:
            gef_print(e.output.decode("utf-8").rstrip())

        if not kwargs["to_file"]:
            os.unlink(tmp_filename)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @load_capstone
    @load_unicorn
    def do_invoke(self, args):
        if current_arch.unicorn_support is False:
            warn("This command cannot work under this architecture.")
            return

        start_insn = args.from_location
        if start_insn is None:
            start_insn = current_arch.pc

        if (args.to_location, args.nb_insn, args.nb_gadget) == (None, None, None):
            nb_gadget = 10
        else:
            nb_gadget = args.nb_gadget

        end_insn = args.to_location
        if args.nb_insn is not None:
            end_insn = self.get_unicorn_end_addr(start_insn, args.nb_insn)

        kwargs = {
            "skip_emulation": args.skip_emulation,
            "to_file": args.output_path,
            "verbose": args.verbose,
            "nb_gadget": nb_gadget,
            "quiet": args.quiet,
            "thumb_mode": is_arm32() and (start_insn & 1),
            "add_sse": is_x86() and args.add_sse,
            "only_insns": args.only_insns,
        }

        if end_insn is not None:
            self.run_unicorn(start_insn, end_insn, **kwargs)
        elif nb_gadget is not None:
            self.run_unicorn(start_insn, 0, **kwargs)
        else:
            err("Invalid arguments")
        return


class StubBreakpoint(gdb.Breakpoint):
    """Create a breakpoint to permanently disable a call (fork/alarm/signal/etc.)."""
    def __init__(self, func, retval):
        super().__init__(func, gdb.BP_BREAKPOINT, internal=False)
        self.func = func
        self.retval = retval

        m = "All calls to '{:s}' will be skipped".format(self.func)
        if self.retval is not None:
            m += " (with return value set to {:#x})".format(self.retval)
        info(m)
        return

    def stop(self):
        m = "Ignoring call to '{:s}' ".format(self.func)
        m += "(setting return value to {:#x})".format(self.retval)
        gdb.execute("return (unsigned int){:#x}".format(self.retval))
        ok(m)
        return False


@register_command
class StubCommand(GenericCommand):
    """Stub out the specified function to skip it. (e.g.: fork)"""
    _cmdline_ = "stub"
    _category_ = "03-c. Memory - Patch"
    _aliases_ = ["deactivate"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-r", "--retval", type=int, default=0,
                        help="the return value from stub. (default: %(default)s)")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="address/symbol to stub out.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -r 0 fork".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        loc = "*{:#x}".format(args.location)
        StubBreakpoint(loc, args.retval)
        return


@register_command
class CapstoneDisassembleCommand(GenericCommand):
    """Use capstone disassembly framework to disassemble code."""
    _cmdline_ = "capstone-disassemble"
    _category_ = "01-e. Debugging Support - Assemble"
    _repeat_ = True
    _aliases_ = ["cs-dis", "pdisas", "nearpc"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the address to disassemble. (default: current_arch.pc)")
    parser.add_argument("-l", "--length", type=AddressUtil.parse_address,
                        help="the length to disassemble. (default: context.nb_lines_code)")
    parser.add_argument("args", metavar="ARGS", nargs="*", help="arguments for capstone. see following example.")
    _syntax_ = parser.format_help()

    valid_arch_modes = {
        "ARM" : ["ARM", "THUMB"],
        "ARM64" : ["ARM"],
        "MIPS" : ["32", "64"],
        "PPC" : ["32", "64"],
        "SPARC" : ["32", "32PLUS", "64"],
        "X86" : ["16", "32", "64"],
    }

    _example_ = "{:s} -l 50 $pc                            # dump from $pc up to 50 lines later\n".format(_cmdline_)
    _example_ += "{:s} -l 50 $pc arch=ARM mode=ARM endian=1 # specify arch, mode and endian (1:big endian)".format(_cmdline_)

    _note_ = "Available architectures and modes:\n"
    for arch in valid_arch_modes:
        _note_ += " - {:8s} {}\n".format(arch, " / ".join(valid_arch_modes[arch]))
    _note_ = _note_.rstrip()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        self.add_setting("nb_lines_code_default", 50, "Number of instruction if no length is specified.")
        return

    @parse_args
    @only_if_gdb_running
    @load_capstone
    def do_invoke(self, args):
        kwargs = {}
        for arg in args.args:
            if "=" in arg:
                key, value = arg.split("=", 1)
                kwargs[key] = value
            else:
                err("ARGS must be KEY=VALUE style")
                return

        length = args.length or Config.get_gef_setting("capstone_disassemble.nb_lines_code_default")
        location = args.location or current_arch.pc

        try:
            skip = length * self.repeat_count
            for insn in Disasm.capstone_disassemble(location, length, skip=skip, **kwargs):
                if insn.address == current_arch.pc:
                    text_insn = "{:12O}".format(insn)
                    msg = "{}  {}".format(RIGHT_ARROW, text_insn)
                else:
                    text_insn = "{:12o}".format(insn)
                    msg = "{} {}".format(" " * 5, text_insn)
                gef_print(msg)
        except AttributeError:
            err("Maybe unsupported architecture")
        except gdb.error:
            pass
        return


@register_command
class GlibcHeapCommand(GenericCommand):
    """The base command to get information about the Glibc heap structure."""
    _cmdline_ = "heap"
    _category_ = "06-a. Heap - Glibc"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("arena")
    subparsers.add_parser("arenas")
    subparsers.add_parser("bins")
    subparsers.add_parser("chunk")
    subparsers.add_parser("chunks")
    subparsers.add_parser("top")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=True)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        self.usage()
        return


@register_command
class GlibcHeapTopCommand(GenericCommand):
    """Display heap top chunk."""
    _cmdline_ = "heap top"
    _category_ = "06-a. Heap - Glibc"
    _aliases_ = ["top-chunk"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", "--arena-addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        if arena is None:
            err("No valid arena")
            return

        if arena.heap_base is None or not is_valid_addr(arena.heap_base):
            err("Heap is not initialized")
            return

        # get top
        if args.arena_addr:
            res = gdb.execute("heap arena --no-pager --arena-addr {:#x}".format(args.arena_addr), to_string=True)
        else:
            res = gdb.execute("heap arena --no-pager", to_string=True)

        m = re.search(r"top = (0x\S+),", Color.remove_color(res))
        if not m:
            err("Not found top address")
            return

        top = int(m.group(1), 16)
        info("arena.top: {:#x}".format(top))
        top += current_arch.ptrsize * 2
        gef_print(GlibcHeap.GlibcChunk(top).psprint(arena))
        return


@register_command
class GlibcHeapArenasCommand(GenericCommand):
    """List up heap arenas."""
    _cmdline_ = "heap arenas"
    _category_ = "06-a. Heap - Glibc"
    _aliases_ = ["arenas"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # main_arena
        arena = GlibcHeap.get_main_arena()
        if arena is None:
            err("Could not find Glibc main arena")
            return

        gef_print(titlify("main_arena"))
        gef_print("{}".format(arena))

        # thread arena
        gef_print(titlify("thread_arena"))
        arena = arena.get_next()
        if arena is None:
            gef_print("Not found")
        while arena:
            gef_print("{}".format(arena))
            arena = arena.get_next()
        return


@register_command
class GlibcHeapArenaCommand(GenericCommand, BufferingOutput):
    """Display information on a heap arena."""
    _cmdline_ = "heap arena"
    _category_ = "06-a. Heap - Glibc"
    _aliases_ = ["arena"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", "--arena-addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def parse_arena(self, arena):
        if arena is None:
            return

        try:
            cmd = "p ((struct malloc_state*) {:#x})[0]".format(arena.addr)
            title = titlify("[arena] ----- {:s}".format(cmd))
            result = gdb.execute(cmd, to_string=True)
            self.out.append(title)
            self.out.extend(result.splitlines())
        except gdb.error:
            title = titlify("[arena] ----- {:#x}".format(arena.addr))
            self.out.append(title)
            self.out.append("$1 = {")
            self.out.append("  mutex = {:#x},".format(int(arena.mutex)))
            self.out.append("  flags = {:#x},".format(int(arena.flags)))
            if get_libc_version() >= (2, 27):
                self.out.append("  have_fastchunks = {:#x},".format(int(arena.have_fastchunks)))
            self.out.append("  fastbinsY = {")
            for i in range(int(arena.num_fastbins)):
                self.out.append("    [{:#x}] = {:#x},".format(i, int(arena.fastbinsY[i])))
            self.out.append("  },")
            self.out.append("  top = {:#x},".format(int(arena.top)))
            self.out.append("  last_remainder = {:#x},".format(int(arena.last_remainder)))
            self.out.append("  bins = {")
            for i in range(int(arena.num_bins)):
                self.out.append("    [{:#x}] = {:#x},".format(i, int(arena.bins[i])))
            self.out.append("  },")
            self.out.append("  binmap = {")
            for i in range(int(arena.num_binmap)):
                self.out.append("    [{:#x}] = {:#x},".format(i, int(arena.binmap[i])))
            self.out.append("  },")
            self.out.append("  next = {:#x},".format(int(arena.next)))
            self.out.append("  next_free = {:#x},".format(int(arena.next_free)))
            self.out.append("  attached_threads = {:#x},".format(int(arena.attached_threads)))
            self.out.append("  system_mem = {:#x},".format(int(arena.system_mem)))
            self.out.append("  max_system_mem = {:#x},".format(int(arena.max_system_mem)))
            self.out.append("}")
        return

    def parse_mp(self):
        try:
            mp = AddressUtil.parse_address("&mp_")
        except gdb.error:
            mp = GlibcHeap.search_for_mp_()
            if mp is None:
                self.out.append(titlify("[mp_]"))
                self.out.append("Not found &mp_")
                return

        try:
            cmd = "p ((struct malloc_par*) {:#x})[0]".format(mp)
            title = titlify("[mp_] ----- {:s}".format(cmd))
            result = gdb.execute(cmd, to_string=True)
            self.out.append(title)
            self.out.extend(result.splitlines())
        except gdb.error:
            mp = GlibcHeap.MallocPar(mp)
            self.out.append(titlify("[mp_] ----- {:#x}".format(mp.addr)))
            self.out.append("$1 = {")
            self.out.append("  trim_threshold = {:#x},".format(int(mp.trim_threshold)))
            self.out.append("  top_pad = {:#x},".format(int(mp.top_pad)))
            self.out.append("  mmap_threshold = {:#x},".format(int(mp.mmap_threshold)))
            self.out.append("  arena_test = {:#x},".format(int(mp.arena_test)))
            self.out.append("  arena_max = {:#x},".format(int(mp.arena_max)))
            if get_libc_version() >= (2, 35):
                self.out.append("  thp_pagesize = {:#x},".format(int(mp.thp_pagesize)))
                self.out.append("  hp_pagesize = {:#x},".format(int(mp.hp_pagesize)))
                self.out.append("  hp_flags = {:#x},".format(int(mp.hp_flags)))
            self.out.append("  n_mmaps = {:#x},".format(int(mp.n_mmaps)))
            self.out.append("  n_mmaps_max = {:#x},".format(int(mp.n_mmaps_max)))
            self.out.append("  max_n_mmaps = {:#x},".format(int(mp.max_n_mmaps)))
            self.out.append("  no_dyn_threshold = {:#x},".format(int(mp.no_dyn_threshold)))
            if get_libc_version() < (2, 15):
                self.out.append("  pagesize = {:#x},".format(int(mp.pagesize)))
            self.out.append("  mmapped_mem = {:#x},".format(int(mp.mmapped_mem)))
            self.out.append("  max_mmapped_mem = {:#x},".format(int(mp.max_mmapped_mem)))
            if get_libc_version() < (2, 24):
                self.out.append("  max_total_mem = {:#x},".format(int(mp.max_total_mem)))
            self.out.append("  sbrk_base = {:#x},".format(int(mp.sbrk_base)))
            if get_libc_version() >= (2, 26):
                self.out.append("  tcache_bins = {:#x},".format(int(mp.tcache_bins)))
                self.out.append("  tcache_max_bytes = {:#x},".format(int(mp.tcache_max_bytes)))
                self.out.append("  tcache_unsorted_limit = {:#x},".format(int(mp.tcache_unsorted_limit)))
            self.out.append("}")
        return

    def parse_heap_info(self, arena):
        if arena is None:
            return []

        if arena.is_main_arena:
            self.out.append(titlify("[heap_info]"))
            self.out.append("Not thread arena")
            return

        heap_info = arena.addr & gef_getpagesize_mask_high()

        try:
            cmd = "p ((struct _heap_info*) {:#x})[0]".format(heap_info)
            title = titlify("[heap_info] ----- {:s}".format(cmd))
            result = gdb.execute(cmd, to_string=True)
            self.out.append(title)
            self.out.extend(result.splitlines())
        except gdb.error:
            heap_info = GlibcHeap.HeapInfo(heap_info)
            self.out.append(titlify("[heap_info] ----- {:#x}".format(heap_info.addr)))
            self.out.append("$1 = {")
            self.out.append("  ar_ptr = {:#x},".format(int(heap_info.ar_ptr)))
            self.out.append("  prev = {:#x},".format(int(heap_info.prev)))
            self.out.append("  size = {:#x},".format(int(heap_info.size)))
            self.out.append("  mprotect_size = {:#x},".format(int(heap_info.mprotect_size)))
            if get_libc_version() >= (2, 35):
                self.out.append("  pagesize = {:#x},".format(int(heap_info.pagesize)))
            self.out.append("  pad = {},".format(heap_info.pad))
            self.out.append("}")
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        self.out = []
        self.parse_arena(arena)
        self.parse_mp()
        self.parse_heap_info(arena)

        # colorize
        for i in range(len(self.out)):
            self.out[i] = re.sub("  ([a-zA-Z_]+) =", "  \033[36m\\1\033[0m =", self.out[i])
            self.out[i] = re.sub(" = (0x[0-9a-f]+)", " = \033[34m\\1\033[0m", self.out[i])

        self.print_output(args)
        return


@register_command
class GlibcHeapChunkCommand(GenericCommand):
    """Display information on a heap chunk."""
    _cmdline_ = "heap chunk"
    _category_ = "06-a. Heap - Glibc"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the address to interpret as a chunk.")
    parser.add_argument("-a", "--arena-addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    parser.add_argument("-b", "--as-base", action="store_true",
                        help="use LOCATION as chunk base address (chunk_base_address = chunk_address - ptrsize * 2).")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        if arena is None:
            err("No valid arena")
            return

        if arena.heap_base is None or not is_valid_addr(arena.heap_base):
            err("Heap is not initialized")
            return

        # get chunk
        if args.as_base:
            chunk = GlibcHeap.GlibcChunk(args.location, from_base=True)
        else:
            chunk = GlibcHeap.GlibcChunk(args.location)

        # dump
        try:
            gef_print(chunk.psprint(arena))
        except gdb.MemoryError:
            err("Invalid address")
            return

        # extra information
        info = []
        arena.reset_bins_info()
        info.extend(arena.make_bins_info(chunk, skip_top=True))
        if chunk.chunk_base_address == arena.top:
            info.append("top")

        if info:
            freelist_hint_color = Config.get_gef_setting("theme.heap_freelist_hint")
            gef_print("  Found freelist/top: {:s}".format(Color.colorify(", ".join(info), freelist_hint_color)))
        else:
            gef_print("  Found freelist/top: None")
        return


@register_command
class GlibcHeapChunksCommand(GenericCommand, BufferingOutput):
    """Display information all heap chunks."""
    _cmdline_ = "heap chunks"
    _category_ = "06-a. Heap - Glibc"
    _aliases_ = ["chunks"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the address interpreted as the beginning of a contiguous chunk. (default: arena.heap_base)")
    parser.add_argument("-a", "--arena-addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    parser.add_argument("-b", "--nb-byte", type=lambda x: int(x, 0),
                        help="temporarily override `heap_chunks.peek_nb_byte`.")
    parser.add_argument("-o", "--peek-offset", type=lambda x: int(x, 0), default=0,
                        help="temporarily override `heap_chunks.peek_offset`.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}\n".format(_cmdline_)
    _example_ += "{:s} -a 0x7ffff0000020".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        self.add_setting("peek_nb_byte", 0, "Hexdump N first byte(s) inside the chunk data (0 to disable)")
        self.add_setting("peek_offset", 0, "the offset to start dumping from when using peek_nb_byte")
        return

    def print_heap_chunks(self, arena, dump_start, peek_nb, peek_offset):
        # Do not show if top is broken, as it affects exit conditions.
        if is_32bit() and arena.top % 0x08:
            self.err("arena.top is corrupted")
            return
        elif is_64bit() and arena.top % 0x10:
            self.err("arena.top is corrupted")
            return

        # It continues even if last_remainder is broken because it doesn't affect the exit condition.
        if is_32bit() and arena.last_remainder % 0x08:
            self.warn("arena.last_remainder is corrupted")
        elif is_64bit() and arena.last_remainder % 0x10:
            self.warn("arena.last_remainder is corrupted")

        freelist_hint_color = Config.get_gef_setting("theme.heap_freelist_hint")
        current_chunk = GlibcHeap.GlibcChunk(dump_start, from_base=True)

        arena.reset_bins_info()
        while True:
            if current_chunk.chunk_base_address == arena.top:
                top_str = Color.colorify("{:s} top".format(LEFT_ARROW), freelist_hint_color)
                self.out.append("{:s} {:s}".format(current_chunk.to_str(arena), top_str))
                break
            if current_chunk.chunk_base_address > arena.top:
                self.err("Corrupted: chunk > top")
                break
            if current_chunk.size == 0:
                # EOF
                break

            line = current_chunk.to_str(arena)

            # in or not in free-list
            info = arena.make_bins_info(current_chunk)
            if info:
                freelist_hint = Color.colorify(" {:s} {:s}".format(LEFT_ARROW, ", ".join(info)), freelist_hint_color)
                line += freelist_hint

            self.out.append(line)

            # peek nbyte
            if peek_nb:
                peek_addr = current_chunk.chunk_base_address + peek_offset
                peeked_data = read_memory(peek_addr, peek_nb)
                h = hexdump(peeked_data, 0x10, base=peek_addr)
                self.out.append(h)

            # goto next
            next_chunk = current_chunk.get_next_chunk()
            if next_chunk is None:
                break
            if not Address(value=next_chunk.address).valid:
                self.err("Corrupted: next_chunk_address is invalid")
                break
            current_chunk = next_chunk
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        if arena is None:
            err("No valid arena")
            return

        if arena.heap_base is None or not is_valid_addr(arena.heap_base):
            err("Heap is not initialized")
            return

        if args.location is None:
            dump_start = arena.heap_base
            # specific pattern
            if arena.is_main_arena:
                if (is_x86_32() or is_riscv32() or is_ppc32()) and get_libc_version() >= (2, 26):
                    dump_start += 8
        else:
            dump_start = args.location

        if args.nb_byte is not None:
            peek_nb = args.nb_byte
        else:
            peek_nb = Config.get_gef_setting("heap_chunks.peek_nb_byte")

        if args.peek_offset is not None:
            peek_offset = args.peek_offset
        else:
            peek_offset = Config.get_gef_setting("heap_chunks.peek_offset")

        self.out = []
        self.print_heap_chunks(arena, dump_start, peek_nb, peek_offset)
        self.print_output(args, term=True)
        return


@register_command
class GlibcHeapBinsCommand(GenericCommand):
    """Display information on the bins on an arena (default: main_arena)."""
    _cmdline_ = "heap bins"
    _category_ = "06-a. Heap - Glibc"
    _aliases_ = ["bins"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", "--arena-addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    parser.add_argument("-v", "--verbose", action="store_true", help="display empty bins.")
    parser.add_argument("--all", action="store_true", help="dump all arenas.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}\n".format(_cmdline_)
    _example_ += "{:s} -a 0x7ffff0000020 -v".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=True)
        return

    @staticmethod
    def pprint_bin(arena, index, bin_name, verbose=False):
        fw, bk = arena.bin(index)

        if bk == 0 and fw == 0:
            warn("Invalid backward and forward bin pointers(fd==bk==NULL)")
            return -1

        bins_addr = arena.bins_addr(index)
        head = bins_addr - current_arch.ptrsize * 2
        if fw == head and not verbose:
            return 0

        bin_table = GlibcHeap.get_binsize_table()[bin_name]
        if index not in bin_table:
            return 0

        bin_info = bin_table[index]
        if "size" in bin_info:
            size_str = "{:#x}".format(bin_info["size"])
        elif "size_min" in bin_info and "size_max" in bin_info:
            size_str = "{:#x}-{:#x}".format(bin_info["size_min"], bin_info["size_max"])
        else:
            size_str = "any"

        m = []
        bins_addr = ProcessMap.lookup_address(bins_addr)
        fw_ = ProcessMap.lookup_address(fw)
        bk_ = ProcessMap.lookup_address(bk)
        m.append("{:s}[idx={:d}, size={:s}, @{!s}]: fd={!s}, bk={!s}".format(
            bin_name, index, size_str, bins_addr, fw_, bk_,
        ))
        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")

        seen = []
        nb_chunk = 0
        while fw != head:
            chunk = GlibcHeap.GlibcChunk(fw, from_base=True)
            if chunk.address in seen:
                m.append(Color.colorify(
                    "{:s}{:#x} [loop detected]".format(RIGHT_ARROW, chunk.chunk_base_address),
                    corrupted_msg_color,
                ))
                break
            seen.append(chunk.address)
            try:
                m.append("{:s}{:s}".format(RIGHT_ARROW, chunk.to_str(arena)))
            except gdb.MemoryError:
                m.append(Color.colorify(
                    "{:s}{:#x} [Corrupted chunk]".format(RIGHT_ARROW, chunk.chunk_base_address),
                    corrupted_msg_color,
                ))
                break
            fw = chunk.fwd
            nb_chunk += 1
        if m:
            gef_print("\n".join(m))
        return nb_chunk

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        if arena is None:
            err("No valid arena")
            return

        if arena.heap_base is None or not is_valid_addr(arena.heap_base):
            err("Heap is not initialized")
            return

        if args.all:
            arenas = GlibcHeap.get_all_arenas()
        else:
            arenas = [arena]

        # doit
        for arena in arenas:
            arena.reset_bins_info()

            # tcache
            GlibcHeapTcachebinsCommand.print_tcache(arena, args.verbose)

            # fastbins
            GlibcHeapFastbinsYCommand.print_fastbin(arena, args.verbose)

            # unsorted bin
            gef_print(titlify("Unsorted Bin for arena '{:s}'".format(arena.name)))
            nb_chunk = GlibcHeapBinsCommand.pprint_bin(arena, 0, "unsorted_bin", args.verbose)
            info("Found {:d} valid chunks in unsorted bin.".format(nb_chunk))

            # small bins
            gef_print(titlify("Small Bins for arena '{:s}'".format(arena.name)))
            bins = {}
            for i in range(1, 63):
                nb_chunk = GlibcHeapBinsCommand.pprint_bin(arena, i, "small_bins", args.verbose)
                if nb_chunk < 0:
                    break
                if nb_chunk > 0:
                    bins[i] = nb_chunk
            info("Found {:d} valid chunks in {:d} small bins.".format(sum(bins.values()), len(bins)))

            # large bins
            gef_print(titlify("Large Bins for arena '{:s}'".format(arena.name)))
            bins = {}
            for i in range(63, 126):
                nb_chunk = GlibcHeapBinsCommand.pprint_bin(arena, i, "large_bins", args.verbose)
                if nb_chunk < 0:
                    break
                if nb_chunk > 0:
                    bins[i] = nb_chunk
            info("Found {:d} valid chunks in {:d} large bins.".format(sum(bins.values()), len(bins)))
        return


@register_command
class GlibcHeapTcachebinsCommand(GenericCommand):
    """Display information on the Tcache on an arena."""
    _cmdline_ = "heap bins tcache"
    _category_ = "06-a. Heap - Glibc"
    _aliases_ = ["tcache"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", "--arena-addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    parser.add_argument("-v", "--verbose", action="store_true", help="display empty bins.")
    parser.add_argument("--all", action="store_true", help="dump all arenas.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @staticmethod
    def print_tcache(arena, verbose):
        if get_libc_version() < (2, 26):
            return

        # Get tcache_perthread_struct for this arena
        tcache_perthread_struct = arena.heap_base + 0x10

        gef_print(titlify("Tcache Bins for arena '{:s}'".format(arena.name)))
        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")

        nb_chunk = 0
        for i in range(GlibcHeap.GlibcArena.TCACHE_MAX_BINS):
            chunk = arena.tcachebin(i)
            chunks = []
            m = []

            # Only print the entry if there are valid chunks. Don't trust count
            while True:
                if chunk is None:
                    break
                try:
                    m.append("{:s}{:s}".format(RIGHT_ARROW, chunk.to_str(arena)))
                    if chunk.address in chunks:
                        m.append(Color.colorify(
                            "{:s}{:#x} [loop detected]".format(RIGHT_ARROW, chunk.address),
                            corrupted_msg_color,
                        ))
                        break

                    chunks.append(chunk.address)
                    nb_chunk += 1

                    next_chunk = chunk.get_fwd_ptr(True)
                    if next_chunk == 0 or next_chunk is None:
                        break

                    chunk = GlibcHeap.GlibcChunk(next_chunk)
                except gdb.MemoryError:
                    m.append(Color.colorify(
                        "{:s}{:#x} [Corrupted chunk]".format(RIGHT_ARROW, chunk.address),
                        corrupted_msg_color,
                    ))
                    break

            if m or verbose:
                if get_libc_version() < (2, 30):
                    count = ord(read_memory(tcache_perthread_struct + i, 1))
                else:
                    count = u16(read_memory(tcache_perthread_struct + 2 * i, 2))
                size = GlibcHeap.get_binsize_table()["tcache"][i]["size"]
                bins_addr = ProcessMap.lookup_address(arena.tcachebins_addr(i))
                fd = ProcessMap.lookup_address(read_int_from_memory(bins_addr.value))
                gef_print("tcachebins[idx={:d}, size={:#x}, @{!s}]: fd={!s} count={:d}".format(
                    i, size, bins_addr, fd, count,
                ))
                if m:
                    gef_print("\n".join(m))

        info("Found {:d} valid chunks in tcache.".format(nb_chunk))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # Determine if we are using libc with tcache built in (2.26+)
        if get_libc_version() < (2, 26):
            info("No Tcache in this version of libc")
            return

        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        if arena is None:
            err("No valid arena")
            return

        if arena.heap_base is None or not is_valid_addr(arena.heap_base):
            err("Heap is not initialized")
            return

        if args.all:
            arenas = GlibcHeap.get_all_arenas()
        else:
            arenas = [arena]

        # doit
        for arena in arenas:
            arena.reset_bins_info()
            GlibcHeapTcachebinsCommand.print_tcache(arena, args.verbose)
        return


@register_command
class GlibcHeapFastbinsYCommand(GenericCommand):
    """Display information on the fastbinsY on an arena."""
    _cmdline_ = "heap bins fast"
    _category_ = "06-a. Heap - Glibc"
    _aliases_ = ["fastbins"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", "--arena-addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    parser.add_argument("-v", "--verbose", action="store_true", help="display empty bins.")
    parser.add_argument("--all", action="store_true", help="dump all arenas.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @staticmethod
    def print_fastbin(arena, verbose):
        def fastbin_index(sz):
            return (sz >> 4) - 2 if SIZE_SZ == 8 else (sz >> 3) - 2

        SIZE_SZ = current_arch.ptrsize
        MAX_FAST_SIZE = 80 * SIZE_SZ // 4
        NFASTBINS = fastbin_index(MAX_FAST_SIZE) - 1

        gef_print(titlify("Fast Bins for arena '{:s}'".format(arena.name)))
        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")

        nb_chunk = 0
        for i in range(NFASTBINS):
            chunk = arena.fastbin(i)
            chunks = []
            m = []

            while True:
                if chunk is None:
                    break

                try:
                    m.append("{:s}{:s}".format(RIGHT_ARROW, chunk.to_str(arena)))
                    if chunk.address in chunks:
                        m.append(Color.colorify(
                            "{:s}{:#x} [loop detected]".format(RIGHT_ARROW, chunk.chunk_base_address),
                            corrupted_msg_color,
                        ))
                        break

                    if fastbin_index(chunk.get_chunk_size()) != i:
                        m.append(Color.colorify("[incorrect fastbin_index]", corrupted_msg_color))

                    chunks.append(chunk.address)
                    nb_chunk += 1

                    next_chunk = chunk.get_fwd_ptr(True)
                    if next_chunk == 0 or next_chunk is None:
                        break

                    chunk = GlibcHeap.GlibcChunk(next_chunk, from_base=True)
                except gdb.MemoryError:
                    m.append(Color.colorify(
                        "{:s}{:#x} [Corrupted chunk]".format(RIGHT_ARROW, chunk.chunk_base_address),
                        corrupted_msg_color,
                    ))
                    break

            if m or verbose:
                bin_table = GlibcHeap.get_binsize_table()["fastbins"]
                if i in bin_table:
                    size = bin_table[i]["size"]
                    bins_addr = ProcessMap.lookup_address(arena.fastbins_addr(i))
                    fd = ProcessMap.lookup_address(read_int_from_memory(bins_addr.value))
                    gef_print("fastbins[idx={:d}, size={:#x}, @{!s}]: fd={!s}".format(
                        i, size, bins_addr, fd,
                    ))
                    if m:
                        gef_print("\n".join(m))

        info("Found {:d} valid chunks in fastbins.".format(nb_chunk))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        if arena is None:
            err("No valid arena")
            return

        if arena.heap_base is None or not is_valid_addr(arena.heap_base):
            err("Heap is not initialized")
            return

        if args.all:
            arenas = GlibcHeap.get_all_arenas()
        else:
            arenas = [arena]

        # doit
        for arena in arenas:
            arena.reset_bins_info()
            GlibcHeapFastbinsYCommand.print_fastbin(arena, args.verbose)
        return


@register_command
class GlibcHeapUnsortedBinsCommand(GenericCommand):
    """Display information on the Unsorted Bins of an arena."""
    _cmdline_ = "heap bins unsorted"
    _category_ = "06-a. Heap - Glibc"
    _aliases_ = ["unsortedbin"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", "--arena-addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    parser.add_argument("-v", "--verbose", action="store_true", help="display empty bins.")
    parser.add_argument("--all", action="store_true", help="dump all arenas.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        if arena is None:
            err("No valid arena")
            return

        if arena.heap_base is None or not is_valid_addr(arena.heap_base):
            err("Heap is not initialized")
            return

        if args.all:
            arenas = GlibcHeap.get_all_arenas()
        else:
            arenas = [arena]

        # doit
        for arena in arenas:
            arena.reset_bins_info()
            gef_print(titlify("Unsorted Bin for arena '{:s}'".format(arena.name)))
            nb_chunk = GlibcHeapBinsCommand.pprint_bin(arena, 0, "unsorted_bin", args.verbose)
            info("Found {:d} valid chunks in unsorted bin.".format(nb_chunk))
        return


@register_command
class GlibcHeapSmallBinsCommand(GenericCommand):
    """Display information on the Small Bins of an arena."""
    _cmdline_ = "heap bins small"
    _category_ = "06-a. Heap - Glibc"
    _aliases_ = ["smallbin"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", "--arena-addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    parser.add_argument("-v", "--verbose", action="store_true", help="display empty bins.")
    parser.add_argument("--all", action="store_true", help="dump all arenas.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        if arena is None:
            err("No valid arena")
            return

        if arena.heap_base is None or not is_valid_addr(arena.heap_base):
            err("Heap is not initialized")
            return

        if args.all:
            arenas = GlibcHeap.get_all_arenas()
        else:
            arenas = [arena]

        # doit
        for arena in arenas:
            arena.reset_bins_info()
            gef_print(titlify("Small Bins for arena '{:s}'".format(arena.name)))
            bins = {}
            for i in range(1, 63):
                nb_chunk = GlibcHeapBinsCommand.pprint_bin(arena, i, "small_bins", args.verbose)
                if nb_chunk < 0:
                    break
                if nb_chunk > 0:
                    bins[i] = nb_chunk
            info("Found {:d} valid chunks in {:d} small bins.".format(sum(bins.values()), len(bins)))
        return


@register_command
class GlibcHeapLargeBinsCommand(GenericCommand):
    """Display information on the Large Bins of an arena."""
    _cmdline_ = "heap bins large"
    _category_ = "06-a. Heap - Glibc"
    _aliases_ = ["largebin"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", "--arena_addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    parser.add_argument("-v", "--verbose", action="store_true", help="display empty bins.")
    parser.add_argument("--all", action="store_true", help="dump all arenas.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        if arena is None:
            err("No valid arena")
            return

        if arena.heap_base is None or not is_valid_addr(arena.heap_base):
            err("Heap is not initialized")
            return

        if args.all:
            arenas = GlibcHeap.get_all_arenas()
        else:
            arenas = [arena]

        # doit
        for arena in arenas:
            arena.reset_bins_info()
            gef_print(titlify("Large Bins for arena '{:s}'".format(arena.name)))
            bins = {}
            for i in range(63, 126):
                nb_chunk = GlibcHeapBinsCommand.pprint_bin(arena, i, "large_bins", args.verbose)
                if nb_chunk < 0:
                    break
                if nb_chunk > 0:
                    bins[i] = nb_chunk
            info("Found {:d} valid chunks in {:d} large bins.".format(sum(bins.values()), len(bins)))
        return


@register_command
class RegistersCommand(GenericCommand):
    """Display full details on one, many or all registers value from current architecture."""
    _cmdline_ = "registers"
    _category_ = "01-a. Debugging Support - Context"
    _aliases_ = ["regs"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("registers", metavar="REGISTERS", nargs="*",
                        help="An array of registers. (default: current_arch.all_registers)")
    _syntax_ = parser.format_help()

    _example_ = "{:s}\n".format(_cmdline_)
    _example_ += "{:s} $eax $eip $esp".format(_cmdline_)

    def __init__(self):
        super().__init__()
        self.regs_to_check_unavailable = None
        return

    def check_unavailable_regs(self):
        if self.regs_to_check_unavailable is not None:
            return

        self.regs_to_check_unavailable = []
        for regname in current_arch.all_registers:
            reg = gdb.parse_and_eval(regname)
            if reg.type.code == gdb.TYPE_CODE_VOID:
                continue
            if str(reg) == "<unavailable>":
                self.regs_to_check_unavailable.append(regname)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        self.check_unavailable_regs()

        unchanged_color = Config.get_gef_setting("theme.registers_register_name")
        changed_color = Config.get_gef_setting("theme.registers_value_changed")

        if args.registers:
            regs = []
            for creg in current_arch.all_registers:
                for reg in args.registers:
                    if not reg.startswith("$"):
                        reg = "$" + reg
                    if reg == creg:
                        regs.append(reg)
                        break
        else:
            regs = current_arch.all_registers

        widest = current_arch.get_aliased_registers_name_max()
        special_line = ""

        out = []
        for regname in regs:
            reg = gdb.parse_and_eval(regname)
            if reg.type.code == gdb.TYPE_CODE_VOID:
                continue

            # str(reg) is slow, so skip if unneeded
            if regname in self.regs_to_check_unavailable:
                # https://arvid.io/2016/08/21/test-if-a-variable-is-unavailable-in-gdb/
                # It seems unnecessary because Mac OS is not supported,
                # but when executing aarch64 under qiling framework, cpsr/fpsr/fpcr is unavailable.
                if str(reg) == "<unavailable>":
                    padreg = current_arch.get_aliased_registers()[regname].ljust(widest, " ")
                    line = "{}: ".format(Color.colorify(padreg, unchanged_color))
                    line += Color.colorify("<unavailable>", "yellow underline")
                    out.append(line)
                    continue

            # colorling
            if is_x86_16():
                value = AddressUtil.align_address(int(reg), memalign_size=4)
            else:
                value = AddressUtil.align_address(int(reg))
            old_value = ContextCommand.old_registers.get(regname, 0)
            if value == old_value:
                color = unchanged_color
            else:
                color = changed_color

            # Special (e.g. segment) registers go on their own line
            if current_arch.special_registers:
                if regname in current_arch.special_registers:
                    special_line += "{}: ".format(Color.colorify(regname, color))
                    special_line += "{:#04x} ".format(get_register(regname))
                    continue

            # reg name
            padreg = current_arch.get_aliased_registers()[regname].ljust(widest, " ")
            line = "{}: ".format(Color.colorify(padreg, color))

            # flag register
            if current_arch.flag_register and regname == current_arch.flag_register:
                line += current_arch.flag_register_to_human()
                out.append(line)
                continue

            # dereference values
            if is_x86_16():
                line += AddressUtil.format_address(value, memalign_size=4)
                derefs = AddressUtil.recursive_dereference_to_string(value, skip_idx=1)
                if derefs:
                    line += " {:s} {:s}".format(RIGHT_ARROW, derefs)
            else:
                line += AddressUtil.recursive_dereference_to_string(value)

            out.append(line)

        if special_line:
            out.append(special_line)

        if is_x86_16():
            for regname, (seg, reg) in current_arch.seg_extended_registers.items():
                segval = get_register(seg) & 0xffff
                regval = get_register(reg) & 0xffff
                value = current_arch.real2phys(segval, regval)

                # colorling
                old_value = ContextCommand.old_registers.get(regname, 0)
                if value == old_value:
                    color = unchanged_color
                else:
                    color = changed_color

                # reg name
                line = "{}:".format(Color.colorify(regname, color))

                # dereference values
                value_s = AddressUtil.format_address(value, memalign_size=2.5)
                line += " {:04x}:{:04x}: {:s} {:s} ".format(segval, regval, value_s, RIGHT_ARROW)
                line += AddressUtil.recursive_dereference_to_string(value, skip_idx=1)

                out.append(line)

        gef_print("\n".join(out))
        return


@register_command
class RopperCommand(GenericCommand):
    """Invoke ropper to search rop gadgets."""
    _cmdline_ = "ropper"
    _category_ = "07-b. External Command - Exploit Development"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("args", metavar="ROPPER_OPTIONS", nargs="*",
                        help="An array of arguments to pass as is to the ropper command. (default: %(default)s)")
    _syntax_ = parser.format_help()

    _example_ = "{:s}\n".format(_cmdline_)
    _example_ += "{:s} -h                 # show detail of options\n".format(_cmdline_)
    _example_ += '{:s} --jmp "rax,rcx"    # filter by jmp registers\n'.format(_cmdline_)
    _example_ += '{:s} --search "pop r?x" # filter by pop registers\n'.format(_cmdline_)

    _help_ = None
    _help_examples_ = None

    def print_help(self):
        self.usage()

        if self._help_ is None:
            self._help_ = subprocess.check_output("ropper --help", shell=True).decode("utf-8")
        if self._help_examples_ is None:
            self._help_examples_ = subprocess.check_output("ropper --help-examples", shell=True).decode("utf-8")

        help_text = titlify("gef --help")
        help_text += self._help_
        help_text += titlify("gef --help-examples")
        help_text += self._help_examples_
        gef_print(help_text, less=True)
        return

    # Need not @parse_args because argparse can't stop interpreting options for ropper.
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    @load_ropper
    def do_invoke(self, argv):
        if "-h" in argv or "--help" in argv:
            self.print_help()
            return

        if "--file" not in argv:
            filepath = Path.get_filepath()
            if filepath is None:
                err("Missing info about file. Please set: `file /path/to/target_binary`")
                return
            argv.extend(["--file", filepath])
        else:
            try:
                filepath = argv[argv.index("--file") + 1]
            except IndexError:
                self.print_help()
                return

        if not os.path.isfile(filepath):
            err("Invalid filepath")
            return

        # ropper set up own autocompleter after which gdb/gef autocomplete don't work
        # due to fork/waitpid, child will be broken but parent will not change
        gef_print(titlify(filepath))
        pid = os.fork()
        if pid == 0:
            try:
                ropper = sys.modules["ropper"]
                ropper.start(argv)
            except (Exception, SystemExit):
                pass
            os._exit(0)
        else:
            os.waitpid(pid, 0)
        return


@register_command
class RpCommand(GenericCommand):
    """Invoke rp++ (v2) command to search rop gadgets (only x64/x86)."""
    _cmdline_ = "rp"
    _category_ = "07-b. External Command - Exploit Development"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("--bin", action="store_true", help="apply rp++ to binary itself.")
    group.add_argument("--libc", action="store_true", help="apply rp++ to libc.so searched from vmmap.")
    group.add_argument("--file", help="apply rp++ to specified file.")
    group.add_argument("--kernel", action="store_true", help="dump kernel, then apply vmlinux-to-elf and rp++.")
    parser.add_argument("-f", "--filter", action="append", type=re.compile, default=[], help="REGEXP filter.")
    parser.add_argument("-r", "--rop", dest="rop_N", default=3,
                        help="the max length of rop gadget. (default: %(default)s)")
    parser.add_argument("--no-print", action="store_true",
                        help="run rp, create a temporary file, but don't display it.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} --bin -f "pop r[abcd]x"\n'.format(_cmdline_)
    _example_ += '{:s} --libc -f "(xchg|mov) [re]sp, \\\\w+" -f "ret"\n'.format(_cmdline_)
    _example_ += "{:s} --kernel # only under qemu-system".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_FILENAME)
        return

    def exec_rp(self, rp, ropN, path):
        output_file = "rp{}_rop_{}.txt".format(ropN, os.path.basename(path))
        output_path = os.path.join(GEF_TEMP_DIR, output_file)
        cmd = f"{rp} --file='{path}' --rop={ropN} --unique > {output_path}"
        gef_print(titlify(cmd))
        if not os.path.exists(output_path):
            os.system(cmd)
        return output_path

    def apply_filter(self, rp_output_path, filter_patterns, base_address):
        if not os.path.exists(rp_output_path):
            err(f"{rp_output_path} is not found")
            return
        lines = open(rp_output_path, "r").read()

        out = []
        for line in lines.splitlines():
            line = Color.remove_color(line)

            match = True
            for re_pattern in filter_patterns:
                if not re_pattern.search(line):
                    match = False
                    break

            if match:
                if line.startswith("0x"):
                    x = line.split(":")
                    addr, gadget = int(x[0], 16), ":".join(x[1:])
                    addr -= base_address # fix address
                    x = Color.redify("{:#08x}".format(addr)) + ":" + gadget # repaint color
                else:
                    x = line
                out.append(x)
        return "\n".join(out)

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("kgdb", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        try:
            rp = GefUtil.which("rp-lin")
        except FileNotFoundError as e:
            err("{}".format(e))
            return

        if args.kernel:
            try:
                nm = GefUtil.which("nm")
            except FileNotFoundError as e:
                err("{}".format(e))
                return

        base_address = 0
        if args.libc:
            libc_targets = ("libc-2.", "libc.so.6", "libuClibc-")
            libc = ProcessMap.process_lookup_path(libc_targets)
            if libc is None:
                err("libc is not found")
                return
            path = libc.path
        elif args.bin:
            binary = Path.get_filepath()
            if binary is None:
                err("binary is not found")
                return
            path = binary
        elif args.file:
            if not os.path.exists(args.file):
                err("{} is not found".format(args.file))
                return
            path = args.file
        elif args.kernel:
            if not is_qemu_system():
                err("--kernel are supported only under qemu-system.")
                return

            info("Wait for memory scan")
            # dump kernel then apply vmlinux-to-elf
            symboled_vmlinux_file = VmlinuxToElfApplyCommand.dump_kernel_elf()
            if symboled_vmlinux_file is None:
                err("Failed to create kernel ELF.")
                return
            path = symboled_vmlinux_file

            cmd = "{:s} '{:s}' | grep ' _stext$'".format(nm, symboled_vmlinux_file)
            out = GefUtil.gef_execute_external(cmd, as_list=True, shell=True)
            if len(out) != 1:
                err("Failed to resolve _stext")
                return
            base_address = int(out[0].split()[0], 16)

        # invoke rp++
        rp_output_path = self.exec_rp(rp, args.rop_N, path)

        # filtering
        out = self.apply_filter(rp_output_path, args.filter, base_address)

        # print
        if not args.no_print:
            gef_print(out, less=True)
        return


@register_command
class AssembleCommand(GenericCommand):
    """Inline code assemble by keystone."""
    _cmdline_ = "asm"
    _category_ = "01-e. Debugging Support - Assemble"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", dest="arch", help="specify the architecture. (default: current_arch.arch)")
    parser.add_argument("-m", dest="mode", help="specify the mode. (default: current_arch.mode)")
    parser.add_argument("-e", dest="big_endian", action="store_true", help="use big-endian.")
    parser.add_argument("-s", dest="as_shellcode", action="store_true", help="output like shellcode style.")
    parser.add_argument("-l", dest="overwrite_location", metavar="LOCATION",
                        type=AddressUtil.parse_address, help="write to memory address.")
    parser.add_argument("-H", "--hex", action="store_true", help="show in hex style.")
    parser.add_argument("instruction", metavar="INSTRUCTION", nargs="+", help="the code to assemble.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} -a X86 -m 64 "mov rax, qword ptr [rax] ; inc rax ;"\n'.format(_cmdline_)
    _example_ += '{:s} -a X86 -m 32 "mov eax, dword ptr [eax] ; inc eax ;"\n'.format(_cmdline_)
    _example_ += '{:s} -a X86 -m 16 "mov ax, word ptr [ax] ; inc ax"\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM -m ARM      "sub r1, r2, r3"\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM -m ARM -e   "sub r1, r2, r3"\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM -m THUMB    "movs r4, #0xf0"\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM -m THUMB -e "movs r4, #0xf0"\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM64 -m ARM    "ldr w1, [sp, #0x8]"\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m 32    "and $9, $6, $7"\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m 32 -e "and $9, $6, $7"\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m 64    "and $9, $6, $7"\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m 64 -e "and $9, $6, $7"\n'.format(_cmdline_)
    _example_ += '{:s} -a PPC -m 32 -e "add 1, 2, 3"\n'.format(_cmdline_)
    _example_ += '{:s} -a PPC -m 64    "add 1, 2, 3"\n'.format(_cmdline_)
    _example_ += '{:s} -a PPC -m 64 -e "add 1, 2, 3"\n'.format(_cmdline_)
    _example_ += '{:s} -a SPARC -m 32 -e "add %g1, %g2, %g3"\n'.format(_cmdline_)
    _example_ += '{:s} -a SPARC -m 32PLUS -e "add %g1, %g2, %g3"\n'.format(_cmdline_)
    _example_ += '{:s} -a SPARC -m 64 -e "add %g1, %g2, %g3"\n'.format(_cmdline_)
    _example_ += '{:s} -a S390X -m 64 -e "a %r0, 4095(%r15,%r1)"'.format(_cmdline_)

    @parse_args
    @load_keystone
    def do_invoke(self, args):
        if (args.arch, args.mode) == (None, None):
            if is_alive():
                arch, mode = UnicornKeystoneCapstone.get_keystone_arch(
                    arch=current_arch.arch, mode=current_arch.mode, endian=Endian.is_big_endian(),
                )
                arch_mode_s = ":".join([current_arch.arch, current_arch.mode])
                endian_s = "big" if Endian.is_big_endian() else "little"
            else:
                # if not alive, defaults to x86-64
                arch, mode = UnicornKeystoneCapstone.get_keystone_arch(arch="X86", mode="64", endian=False)
                arch_mode_s = "X86:64"
                endian_s = "little"
        elif not args.arch:
            err("An architecture (-a) must be provided")
            return
        elif not args.mode:
            # keystone gives no error so check here
            err("A mode (-m) must be provided")
            return
        elif args.arch in ["SPARC", "S390X"] and args.big_endian is False:
            # keystone gives no error so check here
            err("A big endian flag (-e) must be provided")
            return
        else:
            try:
                arch, mode = UnicornKeystoneCapstone.get_keystone_arch(arch=args.arch, mode=args.mode, endian=args.big_endian)
                arch_mode_s = ":".join([args.arch, args.mode])
                endian_s = "big" if args.big_endian else "little"
            except AttributeError:
                self.usage()
                return

        insns = " ".join(args.instruction)
        insns = [x.strip() for x in insns.split(";") if x is not None and x.strip() != ""]

        info("Assembling {} instruction{} for {} ({} endian)".format(len(insns), "s" if len(insns) > 1 else "", arch_mode_s, endian_s))

        if args.as_shellcode:
            gef_print('sc = ""')

        raw = b""
        for insn in insns:
            res = UnicornKeystoneCapstone.keystone_assemble(insn, arch, mode, raw=True)
            if not res:
                gef_print("(Invalid)")
                continue

            if args.overwrite_location is not None:
                raw += res
                continue

            s = binascii.hexlify(res)
            if args.hex:
                res = String.bytes2str(s)
            else:
                res = b"\\x" + b"\\x".join([s[i:i + 2] for i in range(0, len(s), 2)])
                res = res.decode("utf-8")

            if args.as_shellcode:
                res = 'sc += "{:s}"'.format(res)

            gef_print("{:60s} # {:s}".format(res, insn))

        if args.overwrite_location is not None:
            hex_code = binascii.hexlify(raw).decode()
            gdb.execute("patch hex {:#x} {:s}".format(args.overwrite_location, hex_code))
        return


@register_command
class DisassembleCommand(GenericCommand):
    """Inline code disassemble by capstone."""
    _cmdline_ = "dasm"
    _category_ = "01-e. Debugging Support - Assemble"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", dest="arch", help="specify the architecture. (default: current_arch.arch)")
    parser.add_argument("-m", dest="mode", help="specify the mode. (default: current_arch.mode)")
    parser.add_argument("-e", dest="big_endian", action="store_true", help="use big-endian.")
    parser.add_argument("hex_code", metavar="HEX_CODE", nargs="+", help="the hex code to disassemble.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} -a X86 -m 64 "488b00 48ffc0"\n'.format(_cmdline_)
    _example_ += '{:s} -a X86 -m 32 "8b00 40"\n'.format(_cmdline_)
    _example_ += '{:s} -a X86 -m 16 "8b00 40"\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM -m ARM      "031042e0"\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM -m ARM -e   "e0421003"\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM -m THUMB    "f024"\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM -m THUMB -e "24f0"\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM64 -m ARM    "e10b40b9"\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m 32    "2448c700"\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m 32 -e "00c74824"\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m 64    "2448c700"\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m 64 -e "00c74824"\n'.format(_cmdline_)
    _example_ += '{:s} -a PPC -m 32 -e "7c221a14"\n'.format(_cmdline_)
    _example_ += '{:s} -a PPC -m 64    "141a227c"\n'.format(_cmdline_)
    _example_ += '{:s} -a PPC -m 64 -e "7c221a14"\n'.format(_cmdline_)
    _example_ += '{:s} -a SPARC -m 32 -e "86004002"\n'.format(_cmdline_)
    _example_ += '{:s} -a SPARC -m 32PLUS -e "86004002"\n'.format(_cmdline_)
    _example_ += '{:s} -a SPARC -m 64 -e "86004002"\n'.format(_cmdline_)
    _example_ += '{:s} -a RISCV -m 32 "97c10600"\n'.format(_cmdline_)
    _example_ += '{:s} -a RISCV -m 64 "97c10600"\n'.format(_cmdline_)
    _example_ += '{:s} -a S390X -m 64 -e "5a0f1fff"\n'.format(_cmdline_)
    _example_ += '{:s} -a M68K -m 32 -e "9dce"'.format(_cmdline_)

    @parse_args
    @load_capstone
    def do_invoke(self, args):
        if (args.arch, args.mode) == (None, None):
            if is_alive():
                arch, mode = UnicornKeystoneCapstone.get_capstone_arch(
                    arch=current_arch.arch, mode=current_arch.mode, endian=Endian.is_big_endian(),
                )
                arch_mode_s = ":".join([current_arch.arch, current_arch.mode])
                endian_s = "big" if Endian.is_big_endian() else "little"
            else:
                # if not alive, defaults to x86-64
                arch, mode = UnicornKeystoneCapstone.get_capstone_arch(arch="X86", mode="64", endian=False)
                arch_mode_s = "X86:64"
                endian_s = "little"
        elif not args.arch:
            err("An architecture (-a) must be provided")
            return
        elif not args.mode:
            err("A mode (-m) must be provided")
            return
        elif args.arch in ["SPARC", "S390X", "M68K"] and args.big_endian is False:
            # capstone gives no error so check here
            err("A big endian flag (-e) must be provided")
            return
        else:
            try:
                arch, mode = UnicornKeystoneCapstone.get_capstone_arch(arch=args.arch, mode=args.mode, endian=args.big_endian)
                arch_mode_s = ":".join([args.arch, args.mode])
                endian_s = "big" if args.big_endian else "little"
            except AttributeError:
                self.usage()
                return

        insns = " ".join(args.hex_code)
        insns = insns.replace(" ", "").replace("\t", "")
        try:
            insns = binascii.unhexlify(insns)
        except binascii.Error:
            err("Invalid format")
            return

        info("Disassembling {} bytes for {} ({} endian)".format(len(insns), arch_mode_s, endian_s))

        capstone = sys.modules["capstone"]
        try:
            cs = capstone.Cs(arch, mode)
        except capstone.CsError:
            err("CsError")
            return
        cs.detail = True # noqa

        for insn in cs.disasm(insns, 0x0):
            b = binascii.hexlify(insn.bytes).decode("utf-8")
            gef_print("{:>#6x}:\t{:<10s}\t{:s}\t{:s}".format(insn.address, b, insn.mnemonic, insn.op_str))
        return


@register_command
class AsmListCommand(GenericCommand):
    """List up general instructions by capstone (only x64/x86)."""
    _cmdline_ = "asm-list"
    _category_ = "01-e. Debugging Support - Assemble"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", dest="arch", help="specify the architecture. (default: current_arch.arch)")
    parser.add_argument("-m", dest="mode", help="specify the mode. (default: current_arch.mode)")
    parser.add_argument("-e", dest="big_endian", action="store_true", help="use big-endian.")
    parser.add_argument("-b", dest="nbyte", type=int, help="filter by the length of asm byte.")
    parser.add_argument("-f", dest="include", action="append", help="filter by specified string.")
    parser.add_argument("-v", dest="exclude", action="append", help="filter by specified string.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -a X86 -m 64\n".format(_cmdline_)
    _example_ += "{:s} -a X86 -m 32\n".format(_cmdline_)
    _example_ += "{:s} -a X86 -m 16".format(_cmdline_)

    _note_ = "- F0 (LOCK prefix) is ignored\n"
    _note_ += "- F2/F3 (REPNE/REP prefix) are ignored\n"
    _note_ += "- 2E/36/3E/26/64/65 (CS/SS/DS/ES/FS/GS override prefix) are ignored\n"
    _note_ += "- 2E/3E (branch hint prefix) are ignored\n"
    _note_ += "- 66 (operand size prefix) is included\n"
    _note_ += "- 67 (address size prefix) is ignored\n"
    _note_ += "- 40-4F (REX prefix) are ignored\n"
    _note_ += "- C4/C5 (VEX prefix) are ignored\n"
    _note_ += "- 8F (XOP prefix) is ignored\n"
    _note_ += "- 62 (EVEX prefix) is ignored"

    def listup_x86(self, arch, mode):
        DISP64 = "1122334455667788"
        DISP32 = "11223344"
        DISP16 = "1122"
        DISP8 = "11"

        def get_typical_bytecodes_modrm(_reg):
            bytecodes = []
            for (mod, reg, rm) in itertools.product([0b00, 0b01, 0b10, 0b11], _reg, [0b000]):
                modrm = "{:02X}".format((mod << 6) | (reg << 3) | rm)
                if mod == 0b00:
                    if rm == 0b101: # special case; [REG + disp32]
                        bytecode = modrm + DISP32
                    elif rm == 0b100: # use sib; [INDEX * SCALE + BASE]
                        for sib in filter(lambda x: x & 0b111 != 0b101, range(256)):
                            bytecode = modrm + "{:02X}".format(sib)
                    else: # [REG]
                        bytecode = modrm
                elif mod == 0b01:
                    if rm == 0b100: # use sib; [INDEX * SCALE + BASE + disp8]
                        bytecode = []
                        for sib in filter(lambda x: x & 0b111 != 0b101, range(256)):
                            b = modrm + "{:02X}".format(sib) + DISP8
                            bytecode.append(b)
                    else: # [REG + disp8]
                        bytecode = modrm + DISP8
                elif mod == 0b10:
                    if rm == 0b100: # use sib; [INDEX * SCALE + BASE + disp32]
                        bytecode = []
                        for sib in filter(lambda x: x & 0b111 != 0b101, range(256)):
                            b = modrm + "{:02X}".format(sib) + DISP32
                            bytecode.append(b)
                    else: # [REG + disp32]
                        bytecode = modrm + DISP32
                elif mod == 0b11: # REG
                    bytecode = modrm
                bytecodes.append(bytecode)
            return bytecodes

        def get_typical_bytecodes(opcodes):
            bytecodes = []
            for operand in opcodes.split():
                if operand in ["ib", "cb"]:
                    bytecode = [DISP8]
                elif operand in ["iw", "cw"]:
                    bytecode = [DISP16]
                elif operand in ["id", "cd"]:
                    bytecode = [DISP32]
                elif operand in ["iq"]:
                    bytecode = [DISP64]
                elif operand in ["/0", "/1", "/2", "/3", "/4", "/5", "/6", "/7"]:
                    bytecode = get_typical_bytecodes_modrm(tuple([int(operand[1])]))
                elif operand == "/r":
                    bytecode = get_typical_bytecodes_modrm(tuple([0]))
                elif operand.endswith(("+r", "+i")):
                    b = int(operand.split("+")[0], 16)
                    bytecode = ["{:02X}".format(b + x) for x in range(8)]
                else:
                    bytecode = [operand]
                bytecodes.append(bytecode)
            return ["".join(b) for b in itertools.product(*bytecodes)]

        # load capstone
        capstone = sys.modules["capstone"]
        try:
            cs = capstone.Cs(arch, mode)
        except capstone.CsError:
            err("CsError")
            return None

        # download defines
        url = "https://raw.githubusercontent.com/bata24/gef/dev/asmdb/x86data.js"
        x86 = http_get(url)
        if x86 is None:
            err("Connection timed out: {:s}".format(url))
            return None
        x86 = x86.split(b"// ${JSON:BEGIN}")[1].split(b"// ${JSON:END}")[0]
        import json
        x86 = json.loads(x86)

        # manually added
        x86_insns = x86["instructions"]
        # [opcode_str, unused, unused, opcodes, attr]
        x86_insns.append(["icebp", "", "", "F1", "Undocumented"])
        x86_insns.append(["salc", "", "", "D6", "Undocumented"])
        #x86_insns.append(["umov", "", "", "0F 10 /r", "Undocumented"]) # used by another opcode
        #x86_insns.append(["umov", "", "", "0F 11 /r", "Undocumented"]) # used by another opcode
        #x86_insns.append(["umov", "", "", "0F 12 /r", "Undocumented"]) # used by another opcode
        #x86_insns.append(["umov", "", "", "0F 13 /r", "Undocumented"]) # used by another opcode
        #x86_insns.append(["loadall", "", "", "0F 05", "Undocumented"]) # used by another opcode
        #x86_insns.append(["loadall", "", "", "0F 07", "Undocumented"]) # used by another opcode
        #x86_insns.append(["xbts", "", "", "0F A6", "Undocumented"]) # removed now
        #x86_insns.append(["ibts", "", "", "0F A7", "Undocumented"]) # removed now

        # parse it
        valid_patterns = []
        seen_patterns = []
        for insn in x86_insns:
            opcodes = insn[3]
            attr = insn[4].split()

            # filter ignore prefix pattern
            if "REX.W" in opcodes.split():
                continue
            if "VEX" in opcodes.split()[0].split("."):
                continue
            if "EVEX" in opcodes.split()[0].split("."):
                continue
            if "XOP" in opcodes.split()[0].split("."):
                continue

            # e.g.: "FF /2" -> ["FF10", "FF5011", ...]
            bytecodes = get_typical_bytecodes(opcodes)

            # check it is valid or not
            for hex_code in bytecodes:
                # dup check
                if hex_code in seen_patterns:
                    continue
                # disasm
                code = bytes.fromhex(hex_code)
                try:
                    asm = cs.disasm(code, 0).__next__()
                except StopIteration:
                    continue
                opstr = asm.mnemonic + " " + asm.op_str
                # add
                valid_patterns.append([hex_code, opstr, opcodes, attr])
                seen_patterns.append(hex_code)
        return valid_patterns

    @parse_args
    @load_capstone
    def do_invoke(self, args):
        if (args.arch, args.mode) == (None, None):
            if is_alive():
                arch, mode = UnicornKeystoneCapstone.get_capstone_arch(
                    arch=current_arch.arch, mode=current_arch.mode, endian=Endian.is_big_endian(),
                )
                arch_mode_s = ":".join([current_arch.arch, current_arch.mode])
                endian_s = "big" if Endian.is_big_endian() else "little"
            else:
                # if not alive, defaults to x86-64
                arch, mode = UnicornKeystoneCapstone.get_capstone_arch(arch="X86", mode="64", endian=False)
                arch_mode_s = "X86:64"
                endian_s = "little"
        elif not args.arch:
            err("An architecture (-a) must be provided")
            return
        elif not args.mode:
            err("A mode (-m) must be provided")
            return
        elif args.arch in ["SPARC", "S390X", "M68K"] and args.big_endian is False:
            # capstone gives no error so check here
            err("A big endian flag (-e) must be provided")
            return
        else:
            try:
                arch, mode = UnicornKeystoneCapstone.get_capstone_arch(arch=args.arch, mode=args.mode, endian=args.big_endian)
                arch_mode_s = ":".join([args.arch, args.mode])
                endian_s = "big" if args.big_endian else "little"
            except AttributeError:
                self.usage()
                return

        # list up bytecode pattern
        if arch_mode_s.startswith("X86:"):
            if endian_s == "big":
                err("X86 is not big endian")
                return
            patterns = self.listup_x86(arch, mode)
        else:
            err("Unsupported other than x86/x64")
            return

        if patterns is None:
            err("Failed to listup")
            return

        # filter and print
        self.out = []
        fmt = "{:22s} {:60s} {:22s} {}\n"
        legend = ["Hex code", "Assembly code", "Opcode", "Attributes"]
        text = Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading"))
        self.out.append(text)
        for hex_code, opstr, opcodes, attr in patterns:
            # byte length filter
            if args.nbyte is not None and args.nbyte * 2 != len(hex_code):
                continue

            # keyword filter
            line = "{:22s} {:60s} {:22s} {}".format(hex_code, opstr, opcodes, ",".join(attr))
            if args.include and any(f not in line for f in args.include):
                continue
            if args.exclude and any(f in line for f in args.exclude):
                continue

            # not filtered
            self.out.append(line)

        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class ProcessSearchCommand(GenericCommand, BufferingOutput):
    """Display a smart list of processes."""
    _cmdline_ = "ps"
    _category_ = "07-a. External Command - General"
    _aliases_ = ["process-search"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("pattern", metavar="REGEX_PATTERN", nargs="?", help="filter by regex.")
    parser.add_argument("-a", "--attach", type=int, help="attach it.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="include kernel thread, socat, grep, gdb, sshd, bash, systemd, etc.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} ./a.out".format(_cmdline_)

    def __init__(self):
        super().__init__()
        ps = GefUtil.which("ps")
        self.add_setting("ps_command", "{:s} auxww".format(ps), "`ps` command to get process information")
        return

    def get_processes(self):
        ps_command = Config.get_gef_setting("ps.ps_command").split()
        output = GefUtil.gef_execute_external(ps_command, True)
        names = [x.lower().replace("%", "") for x in output[0].split()]

        for line in output[1:]:
            fields = line.split()
            t = {}

            for i, name in enumerate(names):
                if i == len(names) - 1:
                    t[name] = " ".join(fields[i:])
                else:
                    t[name] = fields[i]
            yield t
        return

    @parse_args
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        if args.pattern:
            pattern = re.compile(args.pattern)
        else:
            pattern = re.compile("^.*$")

        self.out = []
        for process in self.get_processes():
            pid = int(process["pid"])
            command = process["command"]
            process["user"] = process["user"].ljust(8)

            if not re.search(pattern, command):
                continue

            if not args.verbose:
                if command.startswith("[") and command.endswith("]"): # kernel thread
                    continue
                if command.startswith("socat "):
                    continue
                if command.startswith("grep "):
                    continue
                if command.startswith("gdb "):
                    continue
                if command.startswith("gdb-multiarch "):
                    continue
                if command.startswith("-bash"):
                    continue
                if command.startswith("sshd: "):
                    continue
                if command.startswith("avahi-daemon: "):
                    continue
                if command.startswith("@dbus-daemon "):
                    continue
                if command.startswith("(sd-pam)"):
                    continue
                if command.startswith("/lib/systemd/"):
                    continue
                if command.startswith("vmhgfs-fuse "):
                    continue
                if command.startswith("vmware-vmblock-fuse "):
                    continue
                if command.startswith("fusermount3 "):
                    continue
                if command.startswith("/usr/bin/vmtoolsd"):
                    continue
                if command.startswith("/usr/libexec/"):
                    continue
                if command.startswith("/snap/"):
                    continue

            if args.attach:
                if args.attach == pid:
                    ok("Attaching to process='{:s}' pid={:d}".format(process["command"], pid))
                    gdb.execute("attach {:d}".format(pid))
                    return

            line = [process[i] for i in ("pid", "user", "cpu", "mem", "tty", "command")]
            self.out.append("\t".join(line))

        self.print_output(args)
        return


@register_command
class ArchInfoCommand(GenericCommand):
    """Display current architecture information."""
    _cmdline_ = "arch-info"
    _category_ = "02-a. Process Information - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        if current_arch is None:
            err("current_arch not set")
            return

        gef_print(titlify("GDB/ELF settings"))
        show_arch = gdb.execute("show architecture", to_string=True).rstrip()
        gef_print("{:30s} {:s} {:s}".format("show architecture", RIGHT_ARROW, show_arch))
        if is_64bit():
            bit_str = "64-bit"
        else:
            bit_str = "32-bit"
        if Endian.is_big_endian():
            endian_str = "big"
        else:
            endian_str = "little"
        gef_print("{:30s} {:s} {:s}".format("bit", RIGHT_ARROW, bit_str))
        gef_print("{:30s} {:s} {:s}".format("endian", RIGHT_ARROW, endian_str))

        gef_print(titlify("GDB mode"))
        gef_print("{:30s} {:s} {!s}".format("is_normal_run()", RIGHT_ARROW, is_normal_run()))
        gef_print("{:30s} {:s} {!s}".format("is_attach()", RIGHT_ARROW, is_attach()))
        gef_print("{:30s} {:s} {!s}".format("is_remote_debug()", RIGHT_ARROW, is_remote_debug()))
        gef_print("{:30s} {:s} {!s}".format("is_container_attach()", RIGHT_ARROW, is_container_attach()))
        gef_print("{:30s} {:s} {!s}".format("is_qemu_system()", RIGHT_ARROW, is_qemu_system()))
        gef_print("{:30s} {:s} {!s}".format("is_qemu_user()", RIGHT_ARROW, is_qemu_user()))
        gef_print("{:30s} {:s} {!s}".format("is_pin()", RIGHT_ARROW, is_pin()))
        gef_print("{:30s} {:s} {!s}".format("is_kgdb()", RIGHT_ARROW, is_kgdb()))
        gef_print("{:30s} {:s} {!s}".format("is_qiling()", RIGHT_ARROW, is_qiling()))
        gef_print("{:30s} {:s} {!s}".format("is_vmware()", RIGHT_ARROW, is_vmware()))
        gef_print("{:30s} {:s} {!s}".format("is_in_kernel()", RIGHT_ARROW, is_in_kernel()))
        gef_print("{:30s} {:s} {!s}".format("is_rr()", RIGHT_ARROW, is_rr()))
        gef_print("{:30s} {:s} {!s}".format("is_wine()", RIGHT_ARROW, is_wine()))

        gef_print(titlify("Others"))
        gef_print("{:30s} {:s} {!s}".format("is_alive()", RIGHT_ARROW, is_alive()))
        gef_print("{:30s} {:s} {!s}".format("is_kvm_enabled()", RIGHT_ARROW, is_kvm_enabled()))
        gef_print("{:30s} {:s} {!s}".format("is_supported_physmode()", RIGHT_ARROW, is_supported_physmode()))
        if is_supported_physmode():
            gef_print("{:30s} {:s} {!s}".format("get_current_mmu_mode()", RIGHT_ARROW, QemuMonitor.get_current_mmu_mode()))

        gef_print(titlify("GEF architecture information"))
        gef_print("{:30s} {:s} {!s}".format("current_arch.arch", RIGHT_ARROW, current_arch.arch))
        gef_print("{:30s} {:s} {!s}".format("current_arch.mode", RIGHT_ARROW, current_arch.mode))
        gef_print("{:30s} {:s} {!s}".format("current_arch.ptrsize", RIGHT_ARROW, current_arch.ptrsize))

        if current_arch.instruction_length is None:
            inst_len = "variable length"
        else:
            inst_len = str(current_arch.instruction_length)
        gef_print("{:30s} {:s} {!s}".format("instruction length", RIGHT_ARROW, inst_len))

        if current_arch.return_register is None:
            ret_regs = "different for each system call"
        else:
            ret_regs = str(current_arch.return_register)
        gef_print("{:30s} {:s} {!s}".format("return register", RIGHT_ARROW, ret_regs))

        fparams = ", ".join(current_arch.function_parameters)
        if len(current_arch.function_parameters) == 1:
            fparams += " (passing via stack)"
        gef_print("{:30s} {:s} {!s}".format("function parameters", RIGHT_ARROW, fparams))

        gef_print("{:30s} {:s} {!s}".format("syscall register", RIGHT_ARROW, current_arch.syscall_register))

        if current_arch.syscall_parameters is None:
            sparams = "different for each system call"
        else:
            sparams = ", ".join(current_arch.syscall_parameters)
        gef_print("{:30s} {:s} {!s}".format("syscall parameters", RIGHT_ARROW, sparams))

        if is_x86() or is_arm32() or is_arm64():
            gef_print("{:30s} {:s} {!s}".format("32bit-emulated (compat mode)", RIGHT_ARROW, is_emulated32()))
        gef_print("{:30s} {:s} {!s}".format("Has a call/jump delay slot", RIGHT_ARROW, current_arch.has_delay_slot))
        gef_print("{:30s} {:s} {!s}".format("Has a syscall delay slot", RIGHT_ARROW, current_arch.has_syscall_delay_slot))
        gef_print("{:30s} {:s} {!s}".format("Has a ret delay slot", RIGHT_ARROW, current_arch.has_ret_delay_slot))
        gef_print("{:30s} {:s} {!s}".format("Stack grow down", RIGHT_ARROW, current_arch.stack_grow_down))
        gef_print("{:30s} {:s} {!s}".format("Thread Local Storage support", RIGHT_ARROW, current_arch.tls_supported))
        gef_print("{:30s} {:s} {!s}".format("keystone support", RIGHT_ARROW, current_arch.keystone_support))
        gef_print("{:30s} {:s} {!s}".format("capstone support", RIGHT_ARROW, current_arch.capstone_support))
        gef_print("{:30s} {:s} {!s}".format("unicorn support", RIGHT_ARROW, current_arch.unicorn_support))
        return


@register_command
class ElfInfoCommand(GenericCommand):
    """Display a limited subset of ELF header information."""
    _cmdline_ = "elf-info"
    _category_ = "02-a. Process Information - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-e", "--use-readelf", action="store_true", help="use readelf.")
    parser.add_argument("-r", "--remote", action="store_true",
                        help="parse remote binary if download feature is available.")
    parser.add_argument("-f", "--file", help="the file path to parse.")
    parser.add_argument("-a", "--address", type=AddressUtil.parse_address,
                        help="the memory address to parse.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="dump the content of each section.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}                   # parse binary itself\n".format(_cmdline_)
    _example_ += "{:s} -f /bin/ls        # parse binary\n".format(_cmdline_)
    _example_ += "{:s} -f /bin/ls -r     # parse remote binary\n".format(_cmdline_)
    _example_ += "{:s} -a 0x555555554000 # parse memory\n".format(_cmdline_)
    _example_ += "{:s} -e -f /bin/ls     # show `readelf -a FILE | less`".format(_cmdline_)

    def __init__(self, *args, **kwargs):
        super().__init__(complete=gdb.COMPLETE_FILENAME)
        return

    classes = {
        Elf.ELF_CLASS_NONE : "Unknown",
        Elf.ELF_32_BITS    : "32-bit",
        Elf.ELF_64_BITS    : "64-bit",
    }

    endianness = {
        Elf.ELF_DATA_NONE : "Unknown",
        Elf.LITTLE_ENDIAN : "Little-Endian",
        Elf.BIG_ENDIAN    : "Big-Endian",
    }

    osabis = {
        Elf.OSABI_SYSTEMV    : "UNIX System V ABI",
        Elf.OSABI_HPUX       : "Hewlett-Packard HP-UX",
        Elf.OSABI_NETBSD     : "NetBSD",
        Elf.OSABI_LINUX      : "GNU Linux",
        Elf.OSABI_HURD       : "GNU Hurd",
        Elf.OSABI_86OPEN     : "86Open Common IA32 ABI",
        Elf.OSABI_SOLARIS    : "Sun Solaris",
        Elf.OSABI_AIX        : "IBM AIX",
        Elf.OSABI_IRIX       : "SGI IRIX",
        Elf.OSABI_FREEBSD    : "FreeBSD",
        Elf.OSABI_TRU64      : "Compaq TRU64 UNIX",
        Elf.OSABI_MODESTO    : "Novell Modesto",
        Elf.OSABI_OPENBSD    : "OpenBSD",
        Elf.OSABI_OPENVMS    : "OpenVMS",
        Elf.OSABI_NSK        : "Hewlett-Packard Non-Stop Kernel",
        Elf.OSABI_AROS       : "Amiga Research OS",
        Elf.OSABI_FENIXOS    : "The FenixOS highly scalable multi-core OS",
        Elf.OSABI_CLOUDABI   : "Nuxi CloudABI",
        Elf.OSABI_OPENVOS    : "Stratus Technologies OpenVOS",
        Elf.OSABI_ARM_AEABI  : "ARM EABI",
        Elf.OSABI_ARM        : "ARM",
        Elf.OSABI_STANDALONE : "Standalone (embedded) application",
    }

    types = {
        Elf.ET_NONE : "No file type",
        Elf.ET_REL  : "Relocatable",
        Elf.ET_EXEC : "Executable",
        Elf.ET_DYN  : "Shared",
        Elf.ET_CORE : "Core",
    }

    machines = {
        Elf.EM_NONE                  : "No machine",
        Elf.EM_M32                   : "AT&T WE 32100",
        Elf.EM_SPARC                 : "SUN SPARC",
        Elf.EM_386                   : "Intel 80386",
        Elf.EM_68K                   : "Motorola m68k family",
        Elf.EM_88K                   : "Motorola m88k family",
        Elf.EM_IAMCU                 : "Intel MCU",
        Elf.EM_860                   : "Intel 80860",
        Elf.EM_MIPS                  : "MIPS R3000 big-endian",
        Elf.EM_S370                  : "IBM System/370 Processor",
        Elf.EM_MIPS_RS3_LE           : "MIPS RS3000 Little-endian",
        Elf.EM_PARISC                : "Hewlett-Packard PA-RISC",
        Elf.EM_VPP500                : "Fujitsu VPP500",
        Elf.EM_SPARC32PLUS           : "Enhanced instruction set SPARC",
        Elf.EM_960                   : "Intel 80960",
        Elf.EM_PPC                   : "PowerPC",
        Elf.EM_PPC64                 : "64-bit PowerPC",
        Elf.EM_S390                  : "IBM System/390 Processor",
        Elf.EM_SPU                   : "IBM SPU/SPC",
        Elf.EM_V800                  : "NEC V800",
        Elf.EM_FR20                  : "Fujitsu FR20",
        Elf.EM_RH32                  : "TRW RH-32",
        Elf.EM_RCE                   : "Motorola RCE",
        Elf.EM_ARM                   : "ARM 32-bit architecture (AARCH32)",
        Elf.EM_ALPHA                 : "Digital Alpha",
        Elf.EM_SH                    : "Hitachi SH",
        Elf.EM_SPARCV9               : "SPARC Version 9",
        Elf.EM_TRICORE               : "Siemens TriCore embedded processor",
        Elf.EM_ARC                   : "Argonaut RISC Core, Argonaut Technologies Inc.",
        Elf.EM_H8_300                : "Hitachi H8/300",
        Elf.EM_H8_300H               : "Hitachi H8/300H",
        Elf.EM_H8S                   : "Hitachi H8S",
        Elf.EM_H8_500                : "Hitachi H8/500",
        Elf.EM_IA_64                 : "Intel IA-64 processor architecture",
        Elf.EM_MIPS_X                : "Stanford MIPS-X",
        Elf.EM_COLDFIRE              : "Motorola ColdFire",
        Elf.EM_68HC12                : "Motorola M68HC12",
        Elf.EM_MMA                   : "Fujitsu MMA Multimedia Accelerator",
        Elf.EM_PCP                   : "Siemens PCP",
        Elf.EM_NCPU                  : "Sony nCPU embedded RISC processor",
        Elf.EM_NDR1                  : "Denso NDR1 microprocessor",
        Elf.EM_STARCORE              : "Motorola Star*Core processor",
        Elf.EM_ME16                  : "Toyota ME16 processor",
        Elf.EM_ST100                 : "STMicroelectronics ST100 processor",
        Elf.EM_TINYJ                 : "Advanced Logic Corp. TinyJ embedded processor family",
        Elf.EM_X86_64                : "AMD x86-64 architecture",
        Elf.EM_PDSP                  : "Sony DSP Processor",
        Elf.EM_PDP10                 : "Digital Equipment Corp. PDP-10",
        Elf.EM_PDP11                 : "Digital Equipment Corp. PDP-11",
        Elf.EM_FX66                  : "Siemens FX66 microcontroller",
        Elf.EM_ST9PLUS               : "STMicroelectronics ST9+ 8/16 bit microcontroller",
        Elf.EM_ST7                   : "STMicroelectronics ST7 8-bit microcontroller",
        Elf.EM_68HC16                : "Motorola MC68HC16 Microcontroller",
        Elf.EM_68HC11                : "Motorola MC68HC11 Microcontroller",
        Elf.EM_68HC08                : "Motorola MC68HC08 Microcontroller",
        Elf.EM_68HC05                : "Motorola MC68HC05 Microcontroller",
        Elf.EM_SVX                   : "Silicon Graphics SVx",
        Elf.EM_ST19                  : "STMicroelectronics ST19 8-bit microcontroller",
        Elf.EM_VAX                   : "Digital VAX",
        Elf.EM_CRIS                  : "Axis Communications 32-bit embedded processor",
        Elf.EM_JAVELIN               : "Infineon Technologies 32-bit embedded processor",
        Elf.EM_FIREPATH              : "Element 14 64-bit DSP Processor",
        Elf.EM_ZSP                   : "LSI Logic 16-bit DSP Processor",
        Elf.EM_MMIX                  : "Donald Knuth's educational 64-bit processor",
        Elf.EM_HUANY                 : "Harvard University machine-independent object files",
        Elf.EM_PRISM                 : "SiTera Prism",
        Elf.EM_AVR                   : "Atmel AVR 8-bit microcontroller",
        Elf.EM_FR30                  : "Fujitsu FR30",
        Elf.EM_D10V                  : "Mitsubishi D10V",
        Elf.EM_D30V                  : "Mitsubishi D30V",
        Elf.EM_V850                  : "NEC v850",
        Elf.EM_M32R                  : "Mitsubishi M32R",
        Elf.EM_MN10300               : "Matsushita MN10300",
        Elf.EM_MN10200               : "Matsushita MN10200",
        Elf.EM_PJ                    : "picoJava",
        Elf.EM_OPENRISC              : "OpenRISC 32-bit embedded processor",
        Elf.EM_ARC_COMPACT           : "ARC International ARCompact processor (old spelling/synonym: EM_ARC_A5)",
        Elf.EM_XTENSA                : "Tensilica Xtensa Architecture",
        Elf.EM_VIDEOCORE             : "Alphamosaic VideoCore processor",
        Elf.EM_TMM_GPP               : "Thompson Multimedia General Purpose Processor",
        Elf.EM_NS32K                 : "National Semiconductor 32000 series",
        Elf.EM_TPC                   : "Tenor Network TPC processor",
        Elf.EM_SNP1K                 : "Trebia SNP 1000 processor",
        Elf.EM_ST200                 : "STMicroelectronics ST200 microcontroller",
        Elf.EM_IP2K                  : "Ubicom IP2xxx microcontroller family",
        Elf.EM_MAX                   : "MAX Processor",
        Elf.EM_CR                    : "National Semiconductor CompactRISC microprocessor",
        Elf.EM_F2MC16                : "Fujitsu F2MC16",
        Elf.EM_MSP430                : "Texas Instruments embedded microcontroller msp430",
        Elf.EM_BLACKFIN              : "Analog Devices Blackfin (DSP) processor",
        Elf.EM_SE_C33                : "S1C33 Family of Seiko Epson processors",
        Elf.EM_SEP                   : "Sharp embedded microprocessor",
        Elf.EM_ARCA                  : "Arca RISC Microprocessor",
        Elf.EM_UNICORE               : "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University",
        Elf.EM_EXCESS                : "eXcess: 16/32/64-bit configurable embedded CPU",
        Elf.EM_DXP                   : "Icera Semiconductor Inc. Deep Execution Processor",
        Elf.EM_ALTERA_NIOS2          : "Altera Nios II soft-core processor",
        Elf.EM_CRX                   : "National Semiconductor CompactRISC CRX microprocessor",
        Elf.EM_XGATE                 : "Motorola XGATE embedded processor",
        Elf.EM_C166                  : "Infineon C16x/XC16x processor",
        Elf.EM_M16C                  : "Renesas M16C series microprocessors",
        Elf.EM_DSPIC30F              : "Microchip Technology dsPIC30F Digital Signal Controller",
        Elf.EM_CE                    : "Freescale Communication Engine RISC core",
        Elf.EM_M32C                  : "Renesas M32C series microprocessors",
        Elf.EM_TSK3000               : "Altium TSK3000 core",
        Elf.EM_RS08                  : "Freescale RS08 embedded processor",
        Elf.EM_SHARC                 : "Analog Devices SHARC family of 32-bit DSP processors",
        Elf.EM_ECOG2                 : "Cyan Technology eCOG2 microprocessor",
        Elf.EM_SCORE7                : "Sunplus S+core7 RISC processor",
        Elf.EM_DSP24                 : "New Japan Radio (NJR) 24-bit DSP Processor",
        Elf.EM_VIDEOCORE3            : "Broadcom VideoCore III processor",
        Elf.EM_LATTICEMICO32         : "RISC processor for Lattice FPGA architecture",
        Elf.EM_SE_C17                : "Seiko Epson C17 family",
        Elf.EM_TI_C6000              : "The Texas Instruments TMS320C6000 DSP family",
        Elf.EM_TI_C2000              : "The Texas Instruments TMS320C2000 DSP family",
        Elf.EM_TI_C5500              : "The Texas Instruments TMS320C55x DSP family",
        Elf.EM_TI_ARP32              : "Texas Instruments Application Specific RISC Processor, 32bit fetch",
        Elf.EM_TI_PRU                : "Texas Instruments Programmable Realtime Unit",
        Elf.EM_MMDSP_PLUS            : "STMicroelectronics 64bit VLIW Data Signal Processor",
        Elf.EM_CYPRESS_M8C           : "Cypress M8C microprocessor",
        Elf.EM_R32C                  : "Renesas R32C series microprocessors",
        Elf.EM_TRIMEDIA              : "NXP Semiconductors TriMedia architecture family",
        Elf.EM_QDSP6                 : "QUALCOMM DSP6 Processor",
        Elf.EM_8051                  : "Intel 8051 and variants",
        Elf.EM_STXP7X                : "STMicroelectronics STxP7x family of configurable and extensible RISC processors",
        Elf.EM_NDS32                 : "Andes Technology compact code size embedded RISC processor family",
        Elf.EM_ECOG1                 : "Cyan Technology eCOG1X family",
        Elf.EM_ECOG1X                : "Cyan Technology eCOG1X family",
        Elf.EM_MAXQ30                : "Dallas Semiconductor MAXQ30 Core Micro-controllers",
        Elf.EM_XIMO16                : "New Japan Radio (NJR) 16-bit DSP Processor",
        Elf.EM_MANIK                 : "M2000 Reconfigurable RISC Microprocessor",
        Elf.EM_CRAYNV2               : "Cray Inc. NV2 vector architecture",
        Elf.EM_RX                    : "Renesas RX family",
        Elf.EM_METAG                 : "Imagination Technologies META processor architecture",
        Elf.EM_MCST_ELBRUS           : "MCST Elbrus general purpose hardware architecture",
        Elf.EM_ECOG16                : "Cyan Technology eCOG16 family",
        Elf.EM_CR16                  : "National Semiconductor CompactRISC CR16 16-bit microprocessor",
        Elf.EM_ETPU                  : "Freescale Extended Time Processing Unit",
        Elf.EM_SLE9X                 : "Infineon Technologies SLE9X core",
        Elf.EM_L10M                  : "Intel L10M",
        Elf.EM_K10M                  : "Intel K10M",
        182                          : "Reserved for future Intel use",
        Elf.EM_AARCH64               : "ARM 64-bit architecture (AARCH64)",
        184                          : "Reserved for future ARM use",
        Elf.EM_AVR32                 : "Atmel Corporation 32-bit microprocessor family",
        Elf.EM_STM8                  : "STMicroeletronics STM8 8-bit microcontroller",
        Elf.EM_TILE64                : "Tilera TILE64 multicore architecture family",
        Elf.EM_TILEPRO               : "Tilera TILEPro multicore architecture family",
        Elf.EM_MICROBLAZE            : "Xilinx MicroBlaze 32-bit RISC soft processor core",
        Elf.EM_CUDA                  : "NVIDIA CUDA architecture",
        Elf.EM_TILEGX                : "Tilera TILE-Gx multicore architecture family",
        Elf.EM_CLOUDSHIELD           : "CloudShield architecture family",
        Elf.EM_COREA_1ST             : "KIPO-KAIST Core-A 1st generation processor family",
        Elf.EM_COREA_2ND             : "KIPO-KAIST Core-A 2nd generation processor family",
        Elf.EM_ARCV2                 : "Synopsys ARCompact V2",
        Elf.EM_OPEN8                 : "Open8 8-bit RISC soft processor core",
        Elf.EM_RL78                  : "Renesas RL78 family",
        Elf.EM_VIDEOCORE5            : "Broadcom VideoCore V processor",
        Elf.EM_78KOR                 : "Renesas 78KOR family",
        Elf.EM_56800EX               : "Freescale 56800EX Digital Signal Controller (DSC)",
        Elf.EM_BA1                   : "Beyond BA1 CPU architecture",
        Elf.EM_BA2                   : "Beyond BA2 CPU architecture",
        Elf.EM_XCORE                 : "XMOS xCORE processor family",
        Elf.EM_MCHP_PIC              : "Microchip 8-bit PIC(r) family",
        Elf.EM_INTELGT               : "Intel Graphics Technology",
        Elf.EM_INTEL206              : "Reserved by Intel",
        Elf.EM_INTEL207              : "Reserved by Intel",
        Elf.EM_INTEL208              : "Reserved by Intel",
        Elf.EM_INTEL209              : "Reserved by Intel",
        Elf.EM_KM32                  : "KM211 KM32 32-bit processor",
        Elf.EM_KMX32                 : "KM211 KMX32 32-bit processor",
        Elf.EM_KMX16                 : "KM211 KMX16 16-bit processor",
        Elf.EM_KMX8                  : "KM211 KMX8 8-bit processor",
        Elf.EM_KVARC                 : "KM211 KVARC processor",
        Elf.EM_CDP                   : "Paneve CDP architecture family",
        Elf.EM_COGE                  : "Cognitive Smart Memory Processor",
        Elf.EM_COOL                  : "Bluechip Systems CoolEngine",
        Elf.EM_NORC                  : "Nanoradio Optimized RISC",
        Elf.EM_CSR_KALIMBA           : "CSR Kalimba architecture family",
        Elf.EM_Z80                   : "Zilog Z80",
        Elf.EM_VISIUM                : "Controls and Data Services VISIUMcore processor",
        Elf.EM_FT32                  : "FTDI Chip FT32 high performance 32-bit RISC architecture",
        Elf.EM_MOXIE                 : "Moxie processor family",
        Elf.EM_AMDGPU                : "AMD GPU architecture",
        Elf.EM_RISCV                 : "RISC-V",
        Elf.EM_LANAI                 : "Lanai 32-bit processor",
        Elf.EM_CEVA                  : "CEVA Processor Architecture Family",
        Elf.EM_CEVA_X2               : "CEVA X2 Processor Family",
        Elf.EM_BPF                   : "Linux BPF - in-kernel virtual machine",
        Elf.EM_GRAPHCORE_IPU         : "Graphcore Intelligent Processing Unit",
        Elf.EM_IMG1                  : "Imagination Technologies",
        Elf.EM_NFP                   : "Netronome Flow Processor",
        Elf.EM_VE                    : "NEC Vector Engine",
        Elf.EM_CSKY                  : "C-SKY processor family",
        Elf.EM_ARC_COMPACT3_64       : "Synopsys ARCv2.3 64-bit",
        Elf.EM_MCS6502               : "MOS Technology MCS 6502 processor",
        Elf.EM_ARC_COMPACT3          : "Synopsys ARCv2.3 32-bit",
        Elf.EM_KVX                   : "Kalray VLIW core of the MPPA processor family",
        Elf.EM_65816                 : "WDC 65816/65C816",
        Elf.EM_LOONGARCH             : "LoongArch",
        Elf.EM_KF32                  : "ChipON KungFu32",
        Elf.EM_U16_U8CORE            : "LAPIS nX-U16/U8",
        Elf.EM_TACHYUM               : "Tachyum",
        Elf.EM_56800EF               : "NXP 56800EF Digital Signal Controller (DSC)",

        Elf.EM_AVR_UNOFFICIAL        : "AVR (unofficial)",
        Elf.EM_MSP430_UNOFFICIAL     : "MSP430 (unofficial)",
        Elf.EM_EPIPHANY_UNOFFICIAL   : "Adapteva Epiphany (unofficial)",
        Elf.EM_AVR32_UNOFFICIAL      : "Atmel AVR32 (unofficial)",
        Elf.EM_MT_UNOFFICIAL         : "Morpho MT (unofficial)",
        Elf.EM_FR30_UNOFFICIAL       : "FR30 (unofficial)",
        Elf.EM_OPENRISC_OLD          : "OpenRISC (obsolete)",
        Elf.EM_WEBASSEMBLY           : "Web Assembly binaries (unofficial)",
        Elf.EM_C166_UNOFFICIAL       : "Infineon C166 (unofficial)",
        Elf.EM_S12Z                  : "Freescale S12Z",
        Elf.EM_FRV_UNOFFICIAL        : "Cygnus FR-V (unofficial)",
        Elf.EM_DLX_UNOFFICIAL        : "DLX (unofficial)",
        Elf.EM_D10V_UNOFFICIAL       : "Cygnus D10V (unofficial)",
        Elf.EM_D30V_UNOFFICIAL       : "Cygnus D30V (unofficial)",
        Elf.EM_IP2K_UNOFFICIAL       : "Ubicom IP2xxx (unofficial)",
        Elf.EM_OPENRISC_OLD2         : "OpenRISC (obsolete)",
        Elf.EM_PPC_UNOFFICIAL        : "Cygnus PowerPC (unofficial)",
        Elf.EM_ALPHA_UNOFFICIAL      : "Digital Alpha (unofficial)",
        Elf.EM_M32R_UNOFFICIAL       : "Cygnus M32R (unofficial)",
        Elf.EM_V850_UNOFFICIAL       : "Cygnus V859 (unofficial)",
        Elf.EM_S390_OLD              : "IBM S/390 (obsolete)",
        Elf.EM_XTENSA_UNOFFICIAL     : "Old Xtensa (unofficial)",
        Elf.EM_XSTORMY_UNOFFICIAL    : "xstormy16 (unofficial)",
        Elf.EM_MICROBLAZE_UNOFFICIAL : "Old MicroBlaze (unofficial)",
        Elf.EM_MN10300_UNOFFICIAL    : "Cygnus MN10300 (unofficial)",
        Elf.EM_MN10200_UNOFFICIAL    : "Cygnus MN10200 (unofficial)",
        Elf.EM_MEP_UNOFFICIAL        : "Toshiba MeP (unofficial)",
        Elf.EM_M32C_UNOFFICIAL       : "Renesas M32C (unofficial)",
        Elf.EM_IQ2000_UNOFFICIAL     : "Vitesse IQ2000 (unofficial)",
        Elf.EM_NIOS_UNOFFICIAL       : "NIOS (unofficial)",
        Elf.EM_MOXIE_UNOFFICIAL      : "Moxie (unofficial)",
    }

    versions = {
        Elf.EV_NONE    : "Invalid version",
        Elf.EV_CURRENT : "Current version",
    }

    ptype = {
        Elf.Phdr.PT_NULL          : "NULL",
        Elf.Phdr.PT_LOAD          : "LOAD",
        Elf.Phdr.PT_DYNAMIC       : "DYNAMIC",
        Elf.Phdr.PT_INTERP        : "INTERP",
        Elf.Phdr.PT_NOTE          : "NOTE",
        Elf.Phdr.PT_SHLIB         : "SHLIB",
        Elf.Phdr.PT_PHDR          : "PHDR",
        Elf.Phdr.PT_TLS           : "TLS",
        Elf.Phdr.PT_GNU_EH_FRAME  : "GNU_EH_FLAME",
        Elf.Phdr.PT_GNU_STACK     : "GNU_STACK",
        Elf.Phdr.PT_GNU_RELRO     : "GNU_RELRO",
        Elf.Phdr.PT_GNU_PROPERTY  : "GNU_PROPERTY",
        Elf.Phdr.PT_SUNWBSS       : "SUNWBSS",
        Elf.Phdr.PT_SUNWSTACK     : "SUNWSTACK",
        Elf.Phdr.PT_MIPS_REGINFO  : "REGINFO",
        Elf.Phdr.PT_MIPS_RTPROC   : "RTPROC",
        Elf.Phdr.PT_MIPS_OPTIONS  : "OPTIONS",
        Elf.Phdr.PT_MIPS_ABIFLAGS : "ABIFLAGS",
    }

    pflags = {
        0                                             : "---",
        Elf.Phdr.PF_X                                 : "--X",
        Elf.Phdr.PF_W                                 : "-W-",
        Elf.Phdr.PF_R                                 : "R--",
        Elf.Phdr.PF_W | Elf.Phdr.PF_X                 : "-WX",
        Elf.Phdr.PF_R | Elf.Phdr.PF_X                 : "R-X",
        Elf.Phdr.PF_R | Elf.Phdr.PF_W                 : "RW-",
        Elf.Phdr.PF_R | Elf.Phdr.PF_W | Elf.Phdr.PF_X : "RWX",
    }

    stype = {
        Elf.Shdr.SHT_NULL           : "NULL",
        Elf.Shdr.SHT_PROGBITS       : "PROGBITS",
        Elf.Shdr.SHT_SYMTAB         : "SYMTAB",
        Elf.Shdr.SHT_STRTAB         : "STRTAB",
        Elf.Shdr.SHT_RELA           : "RELA",
        Elf.Shdr.SHT_HASH           : "HASH",
        Elf.Shdr.SHT_DYNAMIC        : "DYNAMIC",
        Elf.Shdr.SHT_NOTE           : "NOTE",
        Elf.Shdr.SHT_NOBITS         : "NOBITS",
        Elf.Shdr.SHT_REL            : "REL",
        Elf.Shdr.SHT_SHLIB          : "SHLIB",
        Elf.Shdr.SHT_DYNSYM         : "DYNSYM",
        Elf.Shdr.SHT_INIT_ARRAY     : "INIT_ARRAY",
        Elf.Shdr.SHT_FINI_ARRAY     : "FINI_ARRAY",
        Elf.Shdr.SHT_PREINIT_ARRAY  : "PREINIT_ARRAY",
        Elf.Shdr.SHT_GROUP          : "GROUP",
        Elf.Shdr.SHT_SYMTAB_SHNDX   : "SYMTAB_SHNDX",
        Elf.Shdr.SHT_RELR           : "RELR",
        Elf.Shdr.SHT_GNU_ATTRIBUTES : "GNU_ATTRIBUTES",
        Elf.Shdr.SHT_GNU_HASH       : "GNU_HASH",
        Elf.Shdr.SHT_GNU_LIBLIST    : "GNU_LIBLIST",
        Elf.Shdr.SHT_CHECKSUM       : "CHECKSUM",
        Elf.Shdr.SHT_SUNW_move      : "SUNW_move",
        Elf.Shdr.SHT_SUNW_COMDAT    : "SUNW_COMDAT",
        Elf.Shdr.SHT_SUNW_syminfo   : "SUNW_syminfo",
        Elf.Shdr.SHT_GNU_verdef     : "GNU_verdef",
        Elf.Shdr.SHT_GNU_verneed    : "GNU_verneed",
        Elf.Shdr.SHT_GNU_versym     : "GNU_versym",
    }

    def elf_info(self, elf, orig_filepath=None):
        if elf.filename:
            if orig_filepath:
                filename = "{:s} (remote: {:s})".format(elf.filename, orig_filepath)
            else:
                filename = elf.filename
        elif elf.addr is not None:
            filename = "{:#x}".format(elf.addr)

        magic_hex = " ".join(slicer(struct.pack(">I", elf.e_magic).hex(), 2))
        if Endian.is_big_endian():
            magic_str = repr(p32(elf.e_magic).decode())
        else:
            magic_str = repr(p32(elf.e_magic).decode()[::-1])
        data = [
            ("Magic", "{:s} ({:s})".format(magic_hex, magic_str)),
            ("Class", "{:#x} - {:s}".format(elf.e_class, self.classes[elf.e_class])),
            ("Endianness", "{:#x} - {:s}".format(elf.e_endianness, self.endianness[elf.e_endianness])),
            ("ELF Version", "{:#x} - {:s}".format(elf.e_eiversion, self.versions[elf.e_eiversion])),
            ("OS ABI", "{:#x} - {:s}".format(elf.e_osabi, self.osabis[elf.e_osabi])),
            ("ABI Version", "{:#x}".format(elf.e_abiversion)),
            ("Type", "{:#x} - {:s}".format(elf.e_type, self.types[elf.e_type])),
            ("Machine", "{:#x} - {:s}".format(elf.e_machine, self.machines.get(elf.e_machine, "Unknown"))),
            ("Version", "{:#x} - {:s}".format(elf.e_version, self.versions[elf.e_version])),
            ("Entry point", "{:s}".format(AddressUtil.format_address(elf.e_entry))),
            ("Program Header Table", "{:s}".format(AddressUtil.format_address(elf.e_phoff))),
            ("Program Header Entry Size", "{0:d} ({0:#x})".format(elf.e_phentsize)),
            ("Number of Program Headers", "{:d}".format(elf.e_phnum)),
            ("Section Header Table", "{:s}".format(AddressUtil.format_address(elf.e_shoff))),
            ("Section Header Entry Size", "{0:d} ({0:#x})".format(elf.e_shentsize)),
            ("Number of Section Headers", "{:d}".format(elf.e_shnum)),
            ("ELF Header Size", "{0:d} ({0:#x})".format(elf.e_ehsize)),
            ("Section Header String Table Index", "{0:d} ({0:#x})".format(elf.e_shstrndx)),
            ("Processor Specific Flags", "{:#x}".format(elf.e_flags)),
        ]

        self.out.append(titlify("ELF Header - {:s}".format(filename)))
        for title, content in data:
            self.out.append("{:<34s}: {}".format(title, content))

        self.out.append(titlify("Program Header - {:s}".format(filename)))
        self.phdr_info(elf)

        self.out.append(titlify("Section Header - {:s}".format(filename)))
        self.shdr_info(elf)
        return

    def phdr_info(self, elf):
        name_width = max([len(self.ptype.get(p.p_type, "UNKNOWN")) for p in elf.phdrs])

        fmt = "[{:>2s}] {:{:d}s} {:>12s} {:>12s} {:>12s} {:>12s} {:>12s} {:5s} {:>8s}"
        legend = [
            "#", "Type", name_width, "Offset", "Virtaddr",
            "Physaddr", "FileSiz", "MemSiz", "Flags", "Align",
        ]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        for i, p in enumerate(elf.phdrs):
            p_type = self.ptype.get(p.p_type, "UNKNOWN")
            p_flags = self.pflags.get(p.p_flags, "???")
            fmt = "[{:2d}] {:{:d}s} {:#12x} {:#12x} {:#12x} {:#12x} {:#12x} {:5s} {:#8x}"
            args = [
                i, p_type, name_width, p.p_offset, p.p_vaddr,
                p.p_paddr, p.p_filesz, p.p_memsz, p_flags, p.p_align,
            ]
            self.out.append(fmt.format(*args))
        return

    def shdr_info(self, elf):
        if not elf.shdrs:
            self.out.append("Not loaded")
            return

        name_width = max([len(s.sh_name) for s in elf.shdrs])

        fmt = "[{:>2s}] {:{:d}s} {:>15s} {:>12s} {:>12s} {:>12s} {:>12s} {:>5s} {:>5s} {:>5s} {:>8s}"
        legend = ["#", "Name", name_width, "Type", "Address", "Offset", "Size", "EntSiz", "Flags", "Link", "Info", "Align"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        for i, s in enumerate(elf.shdrs):
            sh_type = self.stype.get(s.sh_type, "UNKNOWN")
            sh_flags = ""
            if s.sh_flags & Elf.Shdr.SHF_WRITE:
                sh_flags += "W"
            if s.sh_flags & Elf.Shdr.SHF_ALLOC:
                sh_flags += "A"
            if s.sh_flags & Elf.Shdr.SHF_EXECINSTR:
                sh_flags += "X"
            if s.sh_flags & Elf.Shdr.SHF_MERGE:
                sh_flags += "M"
            if s.sh_flags & Elf.Shdr.SHF_STRINGS:
                sh_flags += "S"
            if s.sh_flags & Elf.Shdr.SHF_INFO_LINK:
                sh_flags += "I"
            if s.sh_flags & Elf.Shdr.SHF_LINK_ORDER:
                sh_flags += "L"
            if s.sh_flags & Elf.Shdr.SHF_OS_NONCONFORMING:
                sh_flags += "O"
            if s.sh_flags & Elf.Shdr.SHF_GROUP:
                sh_flags += "G"
            if s.sh_flags & Elf.Shdr.SHF_TLS:
                sh_flags += "T"
            if s.sh_flags & Elf.Shdr.SHF_EXCLUDE:
                sh_flags += "E"
            if s.sh_flags & Elf.Shdr.SHF_COMPRESSED:
                sh_flags += "C"

            fmt = "[{:2d}] {:{:d}s} {:>15s} {:#12x} {:#12x} {:#12x} {:#12x} {:5s} {:#5x} {:#5x} {:#8x}"
            args = [
                i, s.sh_name, name_width, sh_type, s.sh_addr, s.sh_offset, s.sh_size,
                s.sh_entsize, sh_flags, s.sh_link, s.sh_info, s.sh_addralign,
            ]
            self.out.append(fmt.format(*args))

            if self.verbose:
                if s.sh_size > 0x1000:
                    self.out.append("Skip because too large ({:#x} > 0x1000)".format(s.sh_size))
                else:
                    fd = open(elf.filename, "rb")
                    fd.seek(s.sh_offset, 0)
                    section_data = fd.read(s.sh_size)
                    self.out.append(hexdump(section_data, show_symbol=False, base=s.sh_offset))
        return

    @parse_args
    def do_invoke(self, args):
        local_filepath = None
        remote_filepath = None
        tmp_filepath = None
        self.verbose = args.verbose
        self.out = []

        # memory parse pattern
        if args.address is not None:
            try:
                elf = Elf.get_elf(args.address)
            except gdb.MemoryError:
                err("Memory error.")
                return

            if elf is None or not elf.is_valid():
                err("Failed to parse elf.")
            else:
                self.elf_info(elf)
                gef_print("\n".join(self.out), less=not args.no_pager)
            return

        # file parse pattern
        if args.remote:
            if not is_remote_debug():
                err("-r option is allowed only remote debug.")
                return
            if is_qemu_system():
                err("-r option is unsupported under qemu-system.")
                return

            if args.file:
                remote_filepath = args.file # if specified, assume it is remote
            elif gdb.current_progspace().filename:
                f = gdb.current_progspace().filename
                if f.startswith("target:"): # gdbserver
                    f = f[7:]
                remote_filepath = f
            elif Pid.get_pid(remote=True):
                remote_filepath = "/proc/{:d}/exe".format(Pid.get_pid(remote=True))
            else:
                err("File name could not be determined.")
                return

            data = Path.read_remote_file(remote_filepath, as_byte=True) # qemu-user is failed here, it is ok
            if not data:
                err("Failed to read remote filepath.")
                return
            tmp_fd, tmp_filepath = tempfile.mkstemp(dir=GEF_TEMP_DIR, suffix=".elf", prefix="elf-info-")
            os.fdopen(tmp_fd, "wb").write(data)
            local_filepath = tmp_filepath
            del data

        elif args.file:
            local_filepath = args.file

        elif args.file is None:
            if is_qemu_system():
                err("Argument-less calls are unsupported under qemu-system.")
                return
            local_filepath = Path.get_filepath()

        if local_filepath is None:
            err("File name could not be determined.")
            return

        # readelf pattern
        if args.use_readelf:
            if args.no_pager:
                os.system("LANG=C readelf -a --wide '{:s}'".format(local_filepath))
            else:
                os.system("LANG=C readelf -a --wide '{:s}' | less".format(local_filepath))
            if tmp_filepath and os.path.exists(tmp_filepath):
                os.unlink(tmp_filepath)
            return

        # self parse pattern
        elf = Elf.get_elf(local_filepath)
        if elf is None or not elf.is_valid():
            err("Failed to parse elf.")
        else:
            data = open(local_filepath, "rb").read()
            self.out.append("size: {:d} bytes, sha1: {:s}".format(len(data), hashlib.sha1(data).hexdigest()))
            self.elf_info(elf, remote_filepath)
            gef_print("\n".join(self.out), less=not args.no_pager)

        if tmp_filepath and os.path.exists(tmp_filepath):
            os.unlink(tmp_filepath)
        return


@register_command
class ChecksecCommand(GenericCommand):
    """Checksec the security properties of the current executable or passed as argument."""
    _cmdline_ = "checksec"
    _category_ = "02-f. Process Information - Security"
    _aliases_ = ["cs"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-r", "--remote", action="store_true",
                        help="parse remote binary if download feature is available.")
    parser.add_argument("-f", "--file", help="the file path to parse.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -f /bin/ls\n".format(_cmdline_)
    _example_ += "{:s} -r".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_FILENAME)
        return

    def check_CET_SHSTK(self, sec):
        # Intel CET SHSTK flags via Ehdr
        if "CET SHSTK flag" not in sec:
            # elf is not x86_64
            return
        if sec["CET SHSTK flag"]:
            gef_print("{:<40s}: {:s}".format("CET SHSTK feature flag (via Ehdr)", Color.colorify("Found", "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format("CET SHSTK feature flag (via Ehdr)", Color.colorify("Not found", "bold red")))

        # gdb mode check
        if not is_x86():
            return
        if not is_alive():
            return
        if is_rr():
            return

        # Intel CET SHSTK status via arch_prctl
        if is_pin():
            # Intel SDE implements userspace CET SHSTK but old interface
            r = Checksec.get_cet_status_old_interface()
            if r is None:
                msg = Color.colorify("Disabled", "bold red") + " (kernel does not support; Intel SDE has no `-cet` option)"
                gef_print("{:<40s}: {:s}".format("CET IBT status (via old arch_prctl IF)", msg))
            else:
                if r & 0b10:
                    msg = Color.colorify("Enabled", "bold green") + " (kernel supports; Intel SDE has `-cet` option)"
                    gef_print("{:<40s}: {:s}".format("CET SHSTK status (via old arch_prctl IF)", msg))
                else:
                    msg = Color.colorify("Disabled", "bold red") + " (kernel supports but disabled; Intel SDE has `-cet` option)"
                    gef_print("{:<40s}: {:s}".format("CET SHSTK status (via old arch_prctl IF)", msg))
        else:
            # kernel 6.6 or after supports userspace CET SHSTK
            r = Checksec.get_cet_status_new_interface()
            if r is None:
                msg = Color.colorify("Unimplemented", "bold red") + " (kernel does not support; kernel supports it from 6.6)"
                gef_print("{:<40s}: {:s}".format("CET SHSTK status (via new arch_prctl IF)", msg))
            else:
                if r & 0b01:
                    msg = Color.colorify("Enabled", "bold green") + " (kernel supports and enabled)"
                    gef_print("{:<40s}: {:s}".format("CET SHSTK status (via new arch_prctl IF)", msg))
                else:
                    msg = Color.colorify("Disabled", "bold red") + " (kernel supports but disabled)"
                    gef_print("{:<40s}: {:s}".format("CET SHSTK status (via new arch_prctl IF)", msg))

        # Intel CET SHSTK status via procfs
        r = Checksec.get_cet_status_via_procfs()
        if r is None:
            msg = Color.grayify("Unknown") + " (failed to open /proc/PID/status)"
            gef_print("{:<40s}: {:s}".format("CET SHSTK status (via procfs)", msg))
            gef_print("{:<40s}: {:s}".format("CET SHSTK Lock status (via procfs)", msg))
        elif r is False:
            msg = Color.colorify("Unimplemented", "bold red") + " (kernel does not support; kernel supports it from 6.6)"
            gef_print("{:<40s}: {:s}".format("CET SHSTK status (via procfs)", msg))
            gef_print("{:<40s}: {:s}".format("CET SHSTK Lock status (via procfs)", msg))
        else:
            if r["shstk"]:
                gef_print("{:<40s}: {:s}".format("CET SHSTK status (via procfs)", Color.colorify("Enabled", "bold green")))
            else:
                msg = Color.colorify("Disabled", "bold red") + " (kernel supports but disabled)"
                gef_print("{:<40s}: {:s}".format("CET SHSTK status (via procfs)", msg))
            if r["shstk lock"]:
                gef_print("{:<40s}: {:s}".format("CET SHSTK Lock status (via procfs)", Color.colorify("Enabled", "bold green")))
            else:
                msg = Color.colorify("Disabled", "bold red") + " (kernel supports but no locked)"
                gef_print("{:<40s}: {:s}".format("CET SHSTK Lock status (via procfs)", msg))
        return

    def check_CET_IBT(self, sec):
        # Intel CET IBT flags via Ehdr
        if "CET IBT flag" not in sec:
            # elf is not x86_64
            return
        if sec["CET IBT flag"]:
            gef_print("{:<40s}: {:s}".format("CET IBT feature flag (via Ehdr)", Color.colorify("Found", "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format("CET IBT feature flag (via Ehdr)", Color.colorify("Not found", "bold red")))

        # gdb mode check
        if not is_x86():
            return
        if not is_alive():
            return
        if is_rr():
            return

        # Intel CET IBT status via arch_prctl
        if is_pin():
            # Intel SDE implements userspace CET IBT but old interface
            r = Checksec.get_cet_status_old_interface()
            if r is None:
                msg = Color.colorify("Disabled", "bold red") + " (kernel does not support; Intel SDE has no `-cet` option)"
                gef_print("{:<40s}: {:s}".format("CET IBT status (via old arch_prctl IF)", msg))
            else:
                if r & 0b01:
                    msg = Color.colorify("Enabled", "bold green") + " (kernel supports; Intel SDE has `-cet` option)"
                    gef_print("{:<40s}: {:s}".format("CET IBT status (via old arch_prctl IF)", msg))
                else:
                    msg = Color.colorify("Disabled", "bold red") + " (kernel supports but disabled; Intel SDE has `-cet` option)"
                    gef_print("{:<40s}: {:s}".format("CET IBT status (via old arch_prctl IF)", msg))
        else:
            # kernel does not support userspace CET IBT yet, only supports kernel space CET IBT.
            # https://lwn.net/Articles/889475/ (2022/3/31)
            msg = Color.colorify("Unimplemented", "bold red") + " (at least kernel 6.6 does not support userspace IBT)"
            gef_print("{:<40s}: {:s}".format("CET IBT status", msg))
        return

    def check_PAC(self, sec):
        # PAC opcode
        if "PAC" not in sec:
            # elf is not ARM64
            return
        if sec["PAC"] is None:
            gef_print("{:<40s}: {:s}".format("PAC opcode", Color.grayify("Unknown")))
        elif sec["PAC"]:
            gef_print("{:<40s}: {:s}".format("PAC opcode", Color.colorify("Found", "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format("PAC opcode", Color.colorify("Not found", "bold red")))

        # gdb mode check
        if not is_arm64():
            return
        if not is_alive():
            return
        if is_rr():
            return

        # PAC status
        r = Checksec.get_pac_status()
        if r is None:
            msg = Color.colorify("Disabled", "bold red") + " (kernel does not support PAC)"
            gef_print("{:<40s}: {:s}".format("PAC", msg))
        elif r < 0:
            msg = Color.grayify("Unknown") + " (kernel supports PAC but does not support PR_PAC_GET_ENABLED_KEYS prctl option)"
            gef_print("{:<40s}: {:s}".format("PAC", msg))
        elif r == 0:
            msg = Color.colorify("Disabled", "bold red") + " (kernel supports PAC but no keys are enabled)"
            gef_print("{:<40s}: {:s}".format("PAC", msg))
        elif r > 0:
            keys = []
            if r & 0b00001:
                keys.append("APIAKEY")
            if r & 0b00010:
                keys.append("APIBKEY")
            if r & 0b00100:
                keys.append("APDAKEY")
            if r & 0b01000:
                keys.append("APDBKEY")
            if r & 0b10000:
                keys.append("APGAKEY")
            keys = ", ".join(keys)
            msg = Color.colorify("Enabled", "bold green") + " (enabled keys: {:s})".format(keys)
            gef_print("{:<40s}: {:s}".format("PAC", msg))
        return

    def check_MTE(self, sec):
        # gdb mode check
        if not is_arm64():
            return
        if not is_alive():
            return
        if is_rr():
            return

        # MTE status
        r = Checksec.get_mte_status()
        if r is None:
            msg = Color.colorify("Disabled", "bold red") + " (kernel does not support MTE)"
            gef_print("{:<40s}: {:s}".format("MTE", msg))
        elif r < 0:
            msg = Color.grayify("Unknown") + " (kernel supports MTE but does not support PR_SET_TAGGED_ADDR_CTRL)"
            gef_print("{:<40s}: {:s}".format("MTE", msg))
        elif (r & 0b1) == 0:
            msg = Color.colorify("Disabled", "bold red") + " (kernel supports MTE but disabled)"
            gef_print("{:<40s}: {:s}".format("MTE", msg))
        elif (r & 0b1) == 1 and (r & 0b110) == 0:
            msg = Color.colorify("Disabled", "bold red") + " (MTE is enabled, but fault is ignored)"
            gef_print("{:<40s}: {:s}".format("MTE", msg))
        else:
            keys = []
            if r & 0b010:
                keys.append("PR_MTE_TCF_SYNC")
            if r & 0b100:
                keys.append("PR_MTE_TCF_ASYNC")
            keys = ", ".join(keys)
            msg = Color.colorify("Enabled", "bold green") + " (MTE is enabled as: {:s})".format(keys)
            gef_print("{:<40s}: {:s}".format("MTE", msg))
        return

    def check_system_ASLR(self):
        if is_remote_debug():
            msg = Color.grayify("Unknown")
            gef_print("{:<40s}: {:s} (remote process)".format("System-ASLR", msg))
        else:
            try:
                system_aslr = int(open("/proc/sys/kernel/randomize_va_space").read())
                if system_aslr == 0:
                    msg = Color.colorify("Disabled", "bold red")
                    gef_print("{:<40s}: {:s} (randomize_va_space: 0)".format("System ASLR", msg))
                elif system_aslr == 1:
                    msg = Color.colorify("Partially Enabled", "bold yellow")
                    gef_print("{:<40s}: {:s} (randomize_va_space: 1)".format("System ASLR", msg))
                elif system_aslr == 2:
                    msg = Color.colorify("Enabled", "bold green")
                    gef_print("{:<40s}: {:s} (randomize_va_space: 2)".format("System ASLR", msg))
            except (FileNotFoundError, OSError):
                msg = Color.grayify("Unknown")
                gef_print("{:<40s}: {:s} (randomize_va_space: error)".format("System-ASLR", msg))
        return

    def check_gdb_ASLR(self):
        if is_attach() or is_remote_debug():
            msg = Color.grayify("Ignored")
            gef_print("{:<40s}: {:s} (attached or remote process)".format("GDB ASLR setting", msg))
        else:
            ret = gdb.parameter("disable-randomization")
            if ret is True:
                msg = Color.colorify("Disabled", "bold red")
                gef_print("{:<40s}: {:s} (disable-randomization: on)".format("GDB ASLR setting", msg))
            elif ret is False:
                msg = Color.colorify("Enabled", "bold green")
                gef_print("{:<40s}: {:s} (disable-randomization: off)".format("GDB ASLR setting", msg))
            else:
                msg = Color.grayify("Unknown")
                gef_print("{:<40s}: {:s}".format("GDB ASLR setting", msg))
        return

    def get_colored_msg(self, val):
        if val is True:
            msg = Color.greenify(Color.boldify("Enabled"))
        elif val is False:
            msg = Color.redify(Color.boldify("Disabled"))
        elif val is None:
            msg = Color.grayify("Unknown")
        return msg

    def print_security_properties(self, filename):
        elf = Elf.get_elf(filename)
        if not elf.is_valid():
            err("checksec is failed")
            return

        sec = elf.checksec()
        if sec is False:
            err("checksec is failed")
            return

        gef_print(titlify("Basic information"))

        # Canary
        msg = self.get_colored_msg(sec["Canary"])
        if sec["Canary"] is True and is_alive():
            res = CanaryCommand.gef_read_canary()
            if not res:
                msg += " (Could not get the canary value)"
            else:
                msg += " (value: {:#x})".format(res[0])
        gef_print("{:<40s}: {:s}".format("Canary", msg))

        # NX
        gef_print("{:<40s}: {:s}".format("NX", self.get_colored_msg(sec["NX"])))

        # PIE
        if sec["PIE"]:
            gef_print("{:<40s}: {:s}".format("PIE", self.get_colored_msg(sec["PIE"])))
        else:
            vaddr = min([p.p_vaddr for p in elf.phdrs if p.p_type==Elf.Phdr.PT_LOAD])
            gef_print("{:<40s}: {:s} ({:#x})".format("PIE", self.get_colored_msg(sec["PIE"]), vaddr))

        # RELRO
        if sec["Full RELRO"]:
            # -Wl,-z,relro -Wl,-z,now
            gef_print("{:<40s}: {:s}".format("RELRO", Color.colorify("Full RELRO", "bold green")))
        elif sec["Partial RELRO"]:
            # -Wl,-z,relro -Wl,-z,lazy
            gef_print("{:<40s}: {:s}".format("RELRO", Color.colorify("Partial RELRO", "bold yellow")))
        else:
            # -Wl,-z,norelro
            gef_print("{:<40s}: {:s}".format("RELRO", Color.colorify("No RELRO", "bold red")))

        # Fortify
        if sec["Fortify"]:
            gef_print("{:<40s}: {:s}".format("Fortify", Color.colorify("Found", "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format("Fortify", Color.colorify("Not found", "bold red")))

        gef_print(titlify("Additional information"))

        # Static
        if sec["Static"]:
            if sec["PIE"]:
                gef_print("{:<40s}: {:s}".format("Static/Dynamic", "Static-PIE"))
            else:
                gef_print("{:<40s}: {:s}".format("Static/Dynamic", "Static"))
        else:
            gef_print("{:<40s}: {:s}".format("Static/Dynamic", "Dynamic"))

        # Symbol
        if sec["Symbol"]:
            gef_print("{:<40s}: {:s}".format("Symbol", Color.colorify("Found", "bold red")))
        else:
            gef_print("{:<40s}: {:s}".format("Symbol", Color.colorify("Stripped", "bold green")))

        # Debug information
        if sec["Debuginfo"]:
            gef_print("{:<40s}: {:s}".format("Debuginfo", Color.colorify("Found", "bold red")))
        else:
            gef_print("{:<40s}: {:s}".format("Debuginfo", Color.colorify("Stripped", "bold green")))

        # Intel CET
        self.check_CET_SHSTK(sec)
        self.check_CET_IBT(sec)

        # ARM64 PAC/MTE
        self.check_PAC(sec)
        self.check_MTE(sec)

        # RPATH
        if sec["RPATH"]:
            gef_print("{:<40s}: {:s}".format("RPATH", Color.colorify("Found", "bold red")))

        # RUNPATH
        if sec["RUNPATH"]:
            gef_print("{:<40s}: {:s}".format("RUNPATH", Color.colorify("Found", "bold red")))

        # Clang CFI
        if sec["Clang CFI"]:
            gef_print("{:<40s}: {:s}".format("Clang CFI", self.get_colored_msg(sec["Clang CFI"])))

        # Clang SafeStack
        if sec["Clang SafeStack"]:
            gef_print("{:<40s}: {:s}".format("Clang SafeStack", self.get_colored_msg(sec["Clang SafeStack"])))

        # ASLR
        self.check_system_ASLR()
        self.check_gdb_ASLR()
        return

    @parse_args
    @exclude_specific_gdb_mode(mode=("wine", "kgdb"))
    def do_invoke(self, args):
        if is_qemu_system() or is_vmware():
            info("Redirect to kchecksec")
            gdb.execute("kchecksec")
            return

        local_filepath = None
        remote_filepath = None
        tmp_filepath = None

        if args.remote:
            if not is_remote_debug():
                err("-r option is allowed only remote debug.")
                return

            if args.file:
                remote_filepath = args.file # if specified, assume it is remote
            elif gdb.current_progspace().filename:
                f = gdb.current_progspace().filename
                if f.startswith("target:"): # gdbserver
                    f = f[7:]
                remote_filepath = f
            elif Pid.get_pid(remote=True):
                remote_filepath = "/proc/{:d}/exe".format(Pid.get_pid(remote=True))
            else:
                err("File name could not be determined.")
                return

            data = Path.read_remote_file(remote_filepath, as_byte=True) # qemu-user is failed here, it is ok
            if not data:
                err("Failed to read remote filepath")
                return
            tmp_fd, tmp_filepath = tempfile.mkstemp(dir=GEF_TEMP_DIR, suffix=".elf", prefix="checksec-")
            os.fdopen(tmp_fd, "wb").write(data)
            local_filepath = tmp_filepath
            del data

        elif args.file:
            local_filepath = args.file

        elif args.file is None:
            if is_qemu_system():
                err("Argument-less calls are unsupported under qemu-system.")
                return
            local_filepath = Path.get_filepath()

        if local_filepath is None:
            err("File name could not be determined.")
            return

        if remote_filepath:
            print_filename = "{:s} (remote: {:s})".format(local_filepath, remote_filepath)
        else:
            print_filename = local_filepath

        self.print_security_properties(local_filepath)

        if tmp_filepath and os.path.exists(tmp_filepath):
            os.unlink(tmp_filepath)
        return


@register_command
class KernelChecksecCommand(GenericCommand):
    """Checksec the security properties of the current kernel."""
    _cmdline_ = "kchecksec"
    _category_ = "08-b. Qemu-system Cooperation - Linux Basic"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @staticmethod
    def get_slab_type():
        # Cases where ksymaddr-remote is not working properly
        if not gdb.execute("ksymaddr-remote --quiet commit_creds", to_string=True):
            return "Unknown"

        if gdb.execute("ksymaddr-remote --quiet --no-pager slub_", to_string=True):
            kversion = Kernel.kernel_version()
            if kversion < "6.2":
                return "SLUB"
            else:
                if gdb.execute("ksymaddr-remote --quiet --no-pager deactivate_slab", to_string=True):
                    return "SLUB"
                else:
                    return "SLUB_TINY"
        elif gdb.execute("ksymaddr-remote --quiet --no-pager cache_reap", to_string=True):
            return "SLAB"
        elif gdb.execute("ksymaddr-remote --quiet --no-pager slob_", to_string=True):
            return "SLOB"
        return "Unknown"

    def check_basic_information(self):
        kcmdline = Kernel.kernel_cmdline()
        if kcmdline is None or kcmdline.cmdline is None:
            gef_print("{:<40s}: {:s}".format("Kernel cmdline", "Not found"))
        else:
            gef_print("{:<40s}: {:s}".format("Kernel cmdline", kcmdline.cmdline.strip()))

        kinfo = Kernel.get_kernel_base()
        if kinfo.text_base is None:
            gef_print("{:<40s}: {:s}".format("Kernel base (heuristic)", "Not found"))
        else:
            gef_print("{:<40s}: {:#x}".format("Kernel base (heuristic)", kinfo.text_base))

        stext = Symbol.get_ksymaddr("_stext")
        if stext is None:
            gef_print("{:<40s}: {:s}".format("Kernel base (_stext from kallsyms)", "Not found"))
        else:
            gef_print("{:<40s}: {:#x}".format("Kernel base (_stext from kallsyms)", stext))
        return

    def x86_specific(self):
        if not is_x86():
            return

        cr0 = get_register("cr0", use_monitor=True)
        cr4 = get_register("cr4", use_monitor=True)

        # WP
        if (cr0 >> 16) & 1:
            gef_print("{:<40s}: {:s}".format("Write Protection (CR0 bit 16)", Color.colorify("Enabled", "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format("Write Protection (CR0 bit 16)", Color.colorify("Disabled", "bold red")))

        # PAE
        if (cr4 >> 5) & 1:
            gef_print("{:<40s}: {:s} (NX is supported)".format("PAE (CR4 bit 5)", Color.colorify("Enabled", "bold green")))
        else:
            gef_print("{:<40s}: {:s} (NX is unsupported)".format("PAE (CR4 bit 5)", Color.colorify("Disabled", "bold red")))

        # SMEP
        if (cr4 >> 20) & 1:
            gef_print("{:<40s}: {:s}".format("SMEP (CR4 bit 20)", Color.colorify("Enabled", "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format("SMEP (CR4 bit 20)", Color.colorify("Disabled", "bold red")))

        # SMAP
        if (cr4 >> 21) & 1:
            gef_print("{:<40s}: {:s}".format("SMAP (CR4 bit 21)", Color.colorify("Enabled", "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format("SMAP (CR4 bit 21)", Color.colorify("Disabled", "bold red")))

        # CET
        if (cr4 >> 23) & 1:
            gef_print("{:<40s}: {:s}".format("CET (CR4 bit 23)", Color.colorify("Enabled", "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format("CET (CR4 bit 23)", Color.colorify("Disabled", "bold red")))

        # CET MSR
        if (cr4 >> 23) & 1:
            if is_kvm_enabled():
                additional = "for more precisely, use `msr MSR_IA32_S_CET` without --enable-kvm"
                gef_print("{:<40s}: {:s} ({:s})".format("CET SHSTK (MSR_IA32_S_CET bit 0)", Color.grayify("Unknown"), additional))
                gef_print("{:<40s}: {:s} ({:s})".format("CET IBT (MSR_IA32_S_CET bit 2)", Color.grayify("Unknown"), additional))
            else:
                ret = gdb.execute("msr --quiet MSR_IA32_S_CET", to_string=True)
                MSR_IA32_S_CET = int(ret, 16)
                if MSR_IA32_S_CET & 1:
                    gef_print("{:<40s}: {:s}".format("CET SHSTK (MSR_IA32_S_CET bit 0)", Color.colorify("Enabled", "bold green")))
                else:
                    gef_print("{:<40s}: {:s}".format("CET SHSTK (MSR_IA32_S_CET bit 0)", Color.colorify("Disabled", "bold red")))
                if (MSR_IA32_S_CET >> 2) & 1:
                    gef_print("{:<40s}: {:s}".format("CET IBT (MSR_IA32_S_CET bit 2)", Color.colorify("Enabled", "bold green")))
                else:
                    gef_print("{:<40s}: {:s}".format("CET IBT (MSR_IA32_S_CET bit 2)", Color.colorify("Disabled", "bold red")))
        return

    def arm32_specific(self):
        if not is_arm32():
            return

        # PXN
        ID_MMFR0 = get_register("$ID_MMFR0")
        ID_MMFR0_S = get_register("$ID_MMFR0_S")
        if ID_MMFR0 is not None and (ID_MMFR0 >> 2) & 1:
            gef_print("{:<40s}: {:s}".format("PXN (ID_MMFR0 bit 2)", Color.colorify("Enabled", "bold green")))
        elif ID_MMFR0_S is not None and (ID_MMFR0_S >> 2) & 1:
            gef_print("{:<40s}: {:s}".format("PXN (ID_MMFR0 bit 2)", Color.colorify("Enabled", "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format("PXN (ID_MMFR0 bit 2)", Color.colorify("Disabled", "bold red")))

        # PAN
        gef_print("{:<40s}: {:s} (all ARMv7 is unsupported)".format("PAN", Color.colorify("Disabled", "bold red")))
        return

    def arm64_specific(self):
        if not is_arm64():
            return

        # PXN
        gef_print("{:<40s}: {:s} (all ARMv8~ is supported)".format("PXN", Color.colorify("Enabled", "bold green")))

        # PAN
        ID_AA64MMFR1_EL1 = get_register("$ID_AA64MMFR1_EL1")
        if ID_AA64MMFR1_EL1 is not None and ((ID_AA64MMFR1_EL1 >> 20) & 0b1111) != 0b0000:
            gef_print("{:<40s}: {:s}".format("PAN (ID_AA64MMFR1_EL1 bit 23-20)", Color.colorify("Enabled", "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format("PAN (ID_AA64MMFR1_EL1 bit 23-20)", Color.colorify("Disabled", "bold red")))
        return

    def check_kaslr(self):
        cfg = "CONFIG_RANDOMIZE_BASE (KASLR)"
        kcmdline = Kernel.kernel_cmdline()
        ksym_ret = gdb.execute("ksymaddr-remote --quiet --no-pager kaslr_", to_string=True)

        if not ksym_ret:
            additional = "`kaslr_*`: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        if kcmdline and "nokaslr" in kcmdline.cmdline:
            additional = "nokaslr is in cmdline"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
        else:
            additional = "`kaslr_*`: Found, nokaslr is not in cmdline"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        return

    def check_fgkaslr(self):
        # https://github.com/alobakin/linux/pull/3
        if not is_x86_64():
            return

        cfg = "CONFIG_FG_KASLR (FGKASLR)"
        kcmdline = Kernel.kernel_cmdline()
        swapgs_restore_regs_and_return_to_usermode = Symbol.get_ksymaddr("swapgs_restore_regs_and_return_to_usermode")
        commit_creds = Symbol.get_ksymaddr("commit_creds")

        if not swapgs_restore_regs_and_return_to_usermode:
            if commit_creds:
                additional = "swapgs_restore_regs_and_return_to_usermode: Not found"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
                cfg = "CONFIG_MODULE_FG_KASLR (FGKASLR)"
                gef_print("{:<40s}: {:s}".format(cfg, Color.colorify("Unsupported", "bold red")))
            else:
                gef_print("{:<40s}: {:s}".format(cfg, Color.grayify("Unknown")))
                cfg = "CONFIG_MODULE_FG_KASLR (FGKASLR)"
                gef_print("{:<40s}: {:s}".format(cfg, Color.grayify("Unknown")))
            return

        # swapgs_restore_regs_and_return_to_usermode is in a fixed location.
        # commit_creds are placed dynamically.
        if swapgs_restore_regs_and_return_to_usermode < commit_creds: # For some reason this works fine
            if kcmdline and "nokaslr" in kcmdline.cmdline:
                additional = "nokaslr is in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            elif kcmdline and "nofgkaslr" in kcmdline.cmdline:
                additional = "nofgkaslr is in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            elif kcmdline and "fgkaslr=off" in kcmdline.cmdline:
                additional = "fgkaslr=off is in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            else:
                additional = "swapgs_restore_regs_and_return_to_usermode < commit_creds"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
            # Could not build detection logic for CONFIG_MODULE_FG_KASLR.
            # But there is no way to disable it except at build time.
            # It's included in the patch that introduces FGKASLR, so I'm assuming it's always enabled.
            cfg = "CONFIG_MODULE_FG_KASLR (FGKASLR)"
            gef_print("{:<40s}: {:s}".format(cfg, Color.colorify("Enabled (maybe)", "bold green")))
        else:
            additional = "swapgs_restore_regs_and_return_to_usermode > commit_creds"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            cfg = "CONFIG_MODULE_FG_KASLR (FGKASLR)"
            gef_print("{:<40s}: {:s}".format(cfg, Color.colorify("Unsupported", "bold red")))
        return

    def check_kpti(self):
        cfg = "CONFIG_PAGE_TABLE_ISOLATION (KPTI)"
        kcmdline = Kernel.kernel_cmdline()

        if is_x86():
            pti_init = Symbol.get_ksymaddr("pti_init")
            if pti_init is None:
                additional = "pti_init: Not found"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            elif kcmdline and "nopti" in kcmdline.cmdline:
                additional = "nopti is in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            elif kcmdline and "pti=off" in kcmdline.cmdline:
                additional = "pti=off is in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            elif kcmdline and "mitigations=off" in kcmdline.cmdline:
                additional = "mitigations=off is in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            elif kcmdline and "pti=on" in kcmdline.cmdline:
                additional = "pti=on is in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
            elif is_in_kernel():
                lines = PageMap.get_page_maps_by_pagewalk("pagewalk --quiet --no-pager --simple").splitlines()
                for line in lines:
                    if "USER" in line and "R-X" in line:
                        additional = "USER memory has R-X permission in kernel context"
                        gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
                        return
                else:
                    additional = "USER memory has no R-X permission in kernel context"
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled (maybe)", "bold green"), additional))
            else:
                gef_print("{:<40s}: {:s}".format(cfg, Color.grayify("Unknown")))

        if is_arm32():
            gef_print("{:<40s}: {:s} (ARMv7 is unsupported)".format(cfg, Color.colorify("Unsupported", "bold red")))

        if is_arm64():
            pti_init = Symbol.get_ksymaddr("pti_init")
            if pti_init is None:
                additional = "pti_init: Not found"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            elif kcmdline and "kpti=0" in kcmdline.cmdline:
                additional = "kpti=0 is in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            elif kcmdline and "mitigations=off" in kcmdline.cmdline and "nokaslr" in kcmdline.cmdline:
                additional = "mitigations=off and nokaslr are in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            elif kcmdline and "mitigations=off" in kcmdline.cmdline and "nokaslr" not in kcmdline.cmdline:
                additional = "mitigations=off is in cmdline, nokaslr is not in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
            elif kcmdline and "kpti=1" in kcmdline.cmdline:
                additional = "kpti=1 is in cmdline"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
            else:
                gef_print("{:<40s}: {:s}".format(cfg, Color.colorify("Enabled (maybe)", "bold green")))
        return

    def check_rwx_page(self):
        cfg = "RWX kernel page"
        kinfo = Kernel.get_kernel_base()
        for m in kinfo.maps:
            if m[2] == "RWX":
                gef_print("{:<40s}: {:s}".format(cfg, Color.colorify("Found", "bold red")))
                return
        gef_print("{:<40s}: {:s}".format(cfg, Color.colorify("Not found", "bold green")))
        return

    def check_secure_world(self):
        if not is_arm32() and not is_arm64():
            return

        mtree_ret = gdb.execute("monitor info mtree -f", to_string=True)
        if ".secure-ram" in mtree_ret:
            gef_print("{:<40s}: {:s}".format("Secure world", "Found"))
        else:
            gef_print("{:<40s}: {:s}".format("Secure world", "Not found"))
        return

    def check_CONFIG_SLAB_FREELIST_HARDENED(self):
        cfg = "CONFIG_SLAB_FREELIST_HARDENED"
        slab_cache_names = " ".join("kmalloc-{:d}".format(n) for n in [8, 16, 32, 64, 96, 128, 192, 256, 512])
        slub_dump_ret = gdb.execute("slub-dump --quiet --no-pager {:s}".format(slab_cache_names), to_string=True)
        if slub_dump_ret.count("Corrupted") >= 2: # Destruction of up to one SLUB freelist is allowed.
            gef_print("{:<40s}: {:s}".format(cfg, Color.grayify("Unknown")))
        else:
            slub_dump_ret = gdb.execute("slub-dump --meta", to_string=True)
            r = re.search(r"offsetof\(kmem_cache, random\): (0x\S+)", slub_dump_ret)
            if r:
                additional = "offsetof(kmem_cache, random): {:s}".format(r.group(1))
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
            else:
                gef_print("{:<40s}: {:s}".format(cfg, Color.colorify("Disabled", "bold red")))
        return

    def check_selinux(self):
        cfg = "SELinux"
        # SELinux does not support building format as a kernel module.
        # Therefore, only symbols in the kernel can be used to determine whether or not support.
        selinux_init = Symbol.get_ksymaddr("selinux_init")
        if selinux_init is None:
            additional = "selinux_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        kversion = Kernel.kernel_version()
        if kversion < "4.17":
            selinux_enabled_addr = Symbol.get_ksymaddr("selinux_enabled")
            selinux_enforcing_addr = Symbol.get_ksymaddr("selinux_enforcing")
            if selinux_enabled_addr is None:
                additional = "selinux_init: Found, seliux_enabled: Not detected"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
            elif selinux_enforcing_addr is None:
                additional = "selinux_init: Found, seliux_enforcing: Not detected"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
            else:
                selinux_enabled = u32(read_memory(selinux_enabled_addr, 4))
                selinux_enforcing = u32(read_memory(selinux_enforcing_addr, 4))
                additional = "selinux_init: Found, selinux_enabled: {:d}, selinux_enforcing: {:d}".format(selinux_enabled, selinux_enforcing)
                if selinux_enabled == 0:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
                elif selinux_enforcing == 0:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Permissive", "bold red"), additional))
                else:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enforcing", "bold green"), additional))

        else: # kernel >= 4.17-rc1
            """
            struct selinux_state {
            #ifdef CONFIG_SECURITY_SELINUX_DISABLE
                abool disabled;
            #endif
            #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
                abool enforcing;
            #endif
                abool checkreqprot;
                abool initialized;
                abool policycap[__POLICYDB_CAP_MAX]; # __POLICYDB_CAP_MAX:6 ~ 8 bytes
                astruct page *status_page;
                astruct mutex status_lock;
                astruct selinux_avc *avc;
                astruct selinux_policy __rcu *policy;
                astruct mutex policy_mutex;
            } __randomize_layout;

            x64 sample
            gef> x/16xg 0xffffffff8ba20740
            0xffffffff8ba20740:     0x0100010101010001      0x0000000000000001
            0xffffffff8ba20750:     0xffffe3bc00215140      0x0000000000000000
            0xffffffff8ba20760:     0x0000000000000000      0xffffffff8ba20768
            0xffffffff8ba20770:     0xffffffff8ba20768      0xffffffff8ba1ef20
            0xffffffff8ba20780:     0xffff8ecc7fe62800      0x0000000000000000
            """

            selinux_state = KernelAddressHeuristicFinder.get_selinux_state()

            if selinux_state is None:
                additional = "selinux_init: Found, selinux_state: Not detected"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))

            elif u64(read_memory(selinux_state, 8)) == 0:
                additional = "selinux_init: Found, selinux_state: Not initialized"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))

            else:
                selinux_disable = Symbol.get_ksymaddr("selinux_disable")
                CONFIG_SECURITY_SELINUX_DISABLE = selinux_disable is not None
                enforcing_setup = Symbol.get_ksymaddr("enforcing_setup")
                CONFIG_SECURITY_SELINUX_DEVELOP = enforcing_setup is not None

                # selinux_state.disabled
                if CONFIG_SECURITY_SELINUX_DISABLE:
                    selinux_disabled = u8(read_memory(selinux_state, 1))
                    additional = "selinux_init: Found, selinux_state.disable: {:d}".format(selinux_disabled)
                else:
                    selinux_disabled = None
                    additional = "selinux_init: Found, selinux_state.disable: Not found"

                # selinux_state.enforcing
                if CONFIG_SECURITY_SELINUX_DEVELOP and CONFIG_SECURITY_SELINUX_DISABLE:
                    selinux_enforcing = u8(read_memory(selinux_state + 1, 1))
                    additional += ", selinux_state.enforcing: {:d}".format(selinux_enforcing)
                elif CONFIG_SECURITY_SELINUX_DEVELOP and not CONFIG_SECURITY_SELINUX_DISABLE:
                    selinux_enforcing = u8(read_memory(selinux_state, 1)) != 0
                    additional += ", selinux_state.enforcing: {:d}".format(selinux_enforcing)
                else:
                    selinux_enforcing = True
                    additional += ", selinux_state.enforcing: Not found"

                if selinux_disabled:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
                elif not selinux_enforcing:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Permissive", "bold red"), additional))
                elif selinux_enforcing:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enforcing", "bold green"), additional))
        return

    def check_smack(self):
        cfg = "SMACK"
        smack_init = Symbol.get_ksymaddr("smack_init")
        if smack_init is None:
            additional = "smack_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        kfilesystems_ret = gdb.execute("kfilesystems --quiet --no-pager --skip-mount-path", to_string=True)
        if not kfilesystems_ret:
            additional = "smack_init: Found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
            return

        if "smackfs" in kfilesystems_ret:
            additional = "smack_init: Found, smackfs: Mounted"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        else:
            additional = "smack_init: Found, smackfs: Not mounted"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
        return

    def check_apparmor(self):
        cfg = "AppArmor"
        apparmor_init = Symbol.get_ksymaddr("apparmor_init")
        if apparmor_init is None:
            additional = "apparmor_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        apparmor_enabled_addr = KernelAddressHeuristicFinder.get_apparmor_enabled()
        apparmor_initialized_addr = KernelAddressHeuristicFinder.get_apparmor_initialized()
        if apparmor_enabled_addr is None:
            additional = "apparmor_init: Found, apparmor_enabled: Not detected"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
        elif apparmor_initialized_addr is None:
            additional = "apparmor_init: Found, apparmor_initialized: Not detected"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
        else:
            kversion = Kernel.kernel_version()
            if kversion < "5.1":
                apparmor_enabled = u8(read_memory(apparmor_enabled_addr, 1)) # bool
            else:
                apparmor_enabled = u32(read_memory(apparmor_enabled_addr, 4)) # int
            apparmor_initialized = u32(read_memory(apparmor_initialized_addr, 4))

            if apparmor_enabled not in [0, 1]:
                additional = "apparmor_init: Found, apparmor_enabled: {:#x}".format(apparmor_enabled)
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
            elif apparmor_initialized not in [0, 1]:
                additional = "apparmor_init: Found, apparmor_initialized: {:#x}".format(apparmor_initialized)
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
            else:
                additional = "apparmor_init: Found"
                additional += ", apparmor_initialized: {:d}".format(apparmor_initialized)
                additional += ", apparmor_enabled: {:d}".format(apparmor_enabled)
                if apparmor_enabled == 0:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
                elif apparmor_initialized == 0:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
                else:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        return

    def check_tomoyo(self):
        cfg = "TOMOYO"
        tomoyo_init = Symbol.get_ksymaddr("tomoyo_init")
        if tomoyo_init is None:
            additional = "tomoyo_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        tomoyo_enabled_addr = KernelAddressHeuristicFinder.get_tomoyo_enabled()
        if tomoyo_enabled_addr is None:
            additional = "tomoyo_init: Found, tomoyo_enabled: Not detected"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
        else:
            tomoyo_enabled = u32(read_memory(tomoyo_enabled_addr, 4))
            additional = "tomoyo_init: Found, tomoyo_enabled: {:d}".format(tomoyo_enabled)
            if tomoyo_enabled == 0:
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            else:
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        return

    def check_yama(self):
        cfg = "Yama (ptrace_scope)"
        yama_init = Symbol.get_ksymaddr("yama_init")
        if yama_init is None:
            additional = "yama_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        ptrace_scope_addr = KernelAddressHeuristicFinder.get_ptrace_scope()
        if ptrace_scope_addr is None:
            additional = "yama_init: Found, kernel.yama.ptrace_scope: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
        else:
            ptrace_scope = u32(read_memory(ptrace_scope_addr, 4))
            additional = "yama_init: Found, kernel.yama.ptrace_scope: {:d}".format(ptrace_scope)
            if ptrace_scope == 0:
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            else:
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        return

    def check_integrity(self):
        cfg = "Integrity"
        integrity_iintcache_init = Symbol.get_ksymaddr("integrity_iintcache_init")
        if integrity_iintcache_init is None:
            additional = "integrity_iintcache_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        additional = "integrity_iintcache_init: Found"
        gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
        return

    def check_loadpin(self):
        cfg = "LoadPin"
        loadpin_init = Symbol.get_ksymaddr("loadpin_init")
        if loadpin_init is None:
            additional = "loadpin_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        loadpin_enabled_addr = KernelAddressHeuristicFinder.get_loadpin_enabled()
        if loadpin_enabled_addr is None:
            additional = "loadpin_init: Found, kernel.loadpin.enabled: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
        else:
            loadpin_enabled = u32(read_memory(loadpin_enabled_addr, 4))
            additional = "loadpin_init: Found, kernel.loadpin.enabled: {:d}".format(loadpin_enabled)
            if loadpin_enabled == 0:
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            else:
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        return

    def check_safe_setid(self):
        cfg = "SafeSetID"
        safesetid_security_init = Symbol.get_ksymaddr("safesetid_security_init")
        if safesetid_security_init is None:
            additional = "safesetid_security_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        additional = "safesetid_security_init: Found"
        gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
        return

    def check_lockdown(self):
        cfg = "Lockdown"
        lockdown_lsm_init = Symbol.get_ksymaddr("lockdown_lsm_init")
        if lockdown_lsm_init is None:
            additional = "lockdown_lsm_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        additional = "lockdown_lsm_init: Found"
        gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
        return

    def check_bpf(self):
        cfg = "BPF"
        bpf_lsm_init = Symbol.get_ksymaddr("bpf_lsm_init")
        if bpf_lsm_init is None:
            additional = "bpf_lsm_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        additional = "bpf_lsm_init: Found"
        gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
        return

    def check_landlock(self):
        cfg = "Landlock"
        landlock_init = Symbol.get_ksymaddr("landlock_init")
        if landlock_init is None:
            additional = "landlock_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unsupported", "bold red"), additional))
            return

        additional = "landlock_init: Found"
        gef_print("{:<40s}: {:s} ({:s})".format(cfg, "Supported", additional))
        return

    def check_lkrg(self):
        cfg = "Linux Kernel Runtime Guard (LKRG)"
        kmod_ret = gdb.execute("kmod --quiet --no-pager", to_string=True)
        if "Not found" in kmod_ret:
            additional = "kmod is failed"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
        elif ": lkrg " in kmod_ret:
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), "Loaded"))
        else:
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), "Not loaded"))
        return

    def check_unprivileged_userfaultfd(self):
        cfg = "vm.unprivileged_userfaultfd"
        kversion = Kernel.kernel_version()
        if kversion < "5.2":
            additional = "{:s}: implemented from linux 5.2".format(cfg)
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unimplemented", "bold red"), additional))
            return

        stv_uff_ret = gdb.execute("syscall-table-view -f userfaultfd --quiet --no-pager", to_string=True)
        if "userfaultfd" not in stv_uff_ret:
            additional = "userfaultfd syscall: Unimplemented"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Syscall unsupported", "bold green"), additional))
        elif "invalid userfaultfd" in stv_uff_ret:
            additional = "userfaultfd syscall: Disabled"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Syscall unsupported", "bold green"), additional))
        else:
            sysctl_unprivileged_userfaultfd = KernelAddressHeuristicFinder.get_sysctl_unprivileged_userfaultfd()
            if sysctl_unprivileged_userfaultfd is None:
                additional = "{:s}: Not found".format(cfg)
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
            else:
                v = u32(read_memory(sysctl_unprivileged_userfaultfd, 4))
                additional = "{:s}: {:d}".format(cfg, v)
                if v == 0:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold green"), additional))
                else:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold red"), additional))
        return

    def check_unprivileged_bpf_disabled(self):
        cfg = "kernel.unprivileged_bpf_disabled"
        kversion = Kernel.kernel_version()
        if kversion < "4.4":
            additional = "{:s}: implemented from linux 4.4".format(cfg)
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unimplemented", "bold red"), additional))
            return

        stv_bpf_ret = gdb.execute("syscall-table-view -f bpf --quiet --no-pager", to_string=True)
        if "bpf" not in stv_bpf_ret:
            additional = "bpf syscall: Unimplemented"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Syscall unsupported", "bold green"), additional))
        elif "invalid bpf" in stv_bpf_ret:
            additional = "bpf syscall: Disabled"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Syscall unsupported", "bold green"), additional))
        else:
            sysctl_unprivileged_bpf_disabled = KernelAddressHeuristicFinder.get_sysctl_unprivileged_bpf_disabled()
            if sysctl_unprivileged_bpf_disabled is None:
                additional = "{:s}: Not found".format(cfg)
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
            else:
                v = u32(read_memory(sysctl_unprivileged_bpf_disabled, 4))
                additional = "{:s}: {:d}".format(cfg, v)
                if v == 0:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
                else:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        return

    def check_kexec_load_disabled(self):
        cfg = "kernel.kexec_load_disabled"
        kversion = Kernel.kernel_version()
        if kversion < "3.14":
            additional = "{:s}: implemented from linux 3.14".format(cfg)
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unimplemented", "bold red"), additional))
            return

        r1 = gdb.execute("syscall-table-view -f kexec_load --quiet --no-pager", to_string=True)
        r2 = gdb.execute("syscall-table-view -f kexec_file_load --quiet --no-pager", to_string=True)
        if ("kexec_load" not in r1 or "invalid kexec_load" in r1) and ("kexec_file_load" not in r2 or "invalid kexec_file_load" in r2):
            additional = ""
            if "kexec_load" not in r1:
                additional = "kexec_load syscall: Unimplemented"
            elif "invalid kexec_load" in r1:
                additional = "kexec_load syscall: Disabled"
            if "kexec_file_load" not in r2:
                additional += ", " + "kexec_file_load syscall: Unimplemented"
            elif "invalid kexec_file_load" in r2:
                additional += ", " + "kexec_file_load syscall: Disabled"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Syscall unsupported", "bold green"), additional))
        else:
            kexec_load_disabled = KernelAddressHeuristicFinder.get_kexec_load_disabled()
            if kexec_load_disabled is None:
                additional = "{:s}: Not found".format(cfg)
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
            else:
                v1 = u32(read_memory(kexec_load_disabled, 4))
                additional = "{:s}: {:d}".format(cfg, v1)
                if v1 == 0:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
                else:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        return

    def check_namespaces(self):
        kversion = Kernel.kernel_version()
        ksysctl_ret = Kernel.get_ksysctl("kernel.version")
        cfgs = [
            ["4.9", "user.max_user_namespaces"],
            ["4.9", "user.max_pid_namespaces"],
            ["4.9", "user.max_uts_namespaces"],
            ["4.9", "user.max_ipc_namespaces"],
            ["4.9", "user.max_net_namespaces"],
            ["4.9", "user.max_mnt_namespaces"],
            ["4.9", "user.max_cgroup_namespaces"],
            ["5.6", "user.max_time_namespaces"],
        ]
        prev_fail = False
        for kv, cfg in cfgs:
            if kversion < kv:
                additional = "{:s}: implemented from linux {:s}".format(cfg, kv)
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unimplemented", "bold red"), additional))
                continue
            if not ksysctl_ret: # maybe CONFIG_RANDSTRUCT=y
                additional = "{:s}: Not found".format(cfg)
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
                continue
            if prev_fail: # Kernel.get_ksysctl is very slow, so skip if previous Kernel.get_ksysctl() was failed
                additional = "{:s}: Not found".format(cfg)
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
                continue
            addr = Kernel.get_ksysctl(cfg) # very slow
            if addr is None:
                additional = "{:s}: Not found".format(cfg)
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
                prev_fail = True
                continue
            val = u32(read_memory(addr, 4))
            if val:
                gef_print("{:<40s}: {:s}".format(cfg, Color.colorify("{:d}".format(val), "bold red")))
            else:
                gef_print("{:<40s}: {:s}".format(cfg, Color.colorify("{:d}".format(val), "bold green")))
        return

    def check_unprivileged_userns_clone(self):
        cfg = "kernel.unprivileged_userns_clone"
        addr = Kernel.get_ksysctl(cfg)
        if addr is None:
            additional = "{:s}: Not found, Only present in debian-based environments".format(cfg)
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
            return

        val = u32(read_memory(addr, 4))
        additional = "{:s}: {:d}, Only present in debian-based environments".format(cfg, val)
        if val:
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold red"), additional))
        else:
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold green"), additional))
        return

    def check_userns_restrict(self):
        cfg = "kernel.userns_restrict"
        addr = Kernel.get_ksysctl(cfg)
        if addr is None:
            additional = "{:s}: Not found, Only present in ALT-linux-based environments".format(cfg)
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
            return

        val = u32(read_memory(addr, 4))
        additional = "{:s}: {:d}, Only present in ALT-linux-based environments".format(cfg, val)
        if val:
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        else:
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
        return

    def check_CONFIG_KALLSYMS_ALL(self):
        cfg = "CONFIG_KALLSYMS_ALL"
        modprobe_path = Symbol.get_ksymaddr("modprobe_path")
        if modprobe_path:
            additional = "modprobe_path: Found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold red"), additional))
        else:
            additional = "modprobe_path: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold green"), additional))
        return

    def check_CONFIG_IKCONFIG(self):
        cfg = "CONFIG_IKCONFIG"
        ikconfig_init = Symbol.get_ksymaddr("ikconfig_init")
        if ikconfig_init:
            additional = "ikconfig_init: Found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold red"), additional))
        else:
            additional = "ikconfig_init: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold green"), additional))
        return

    def check_CONFIG_RANDSTRUCT(self):
        cfg = "CONFIG_RANDSTRUCT"
        # In cases where kallsyms could be resolved, but ksysctl could not be resolved correctly,
        # it is assumed that the structure is strange.
        # Each structure parsed by ksysctl has no difference among kernel versions, except for `struct ctl_dir.inodes`.
        # Additionally, the first member of struct ctl_table is a *char procname, which will almost certainly readable something.
        # If this fails, it can be determined that the randstruct is used.
        ksysctl_ret = Kernel.get_ksysctl("kernel.version")
        if not ksysctl_ret:
            additional = "ksysctl was failed"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        else:
            additional = "ksysctl was successful"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
        return

    def check_CONFIG_STATIC_USERMODEHELPER(self):
        def get_permission(addr):
            maps = Kernel.get_maps()
            if not maps:
                return None
            for vaddr, size, perm in maps:
                if vaddr <= addr < vaddr + size:
                    return perm
            return None

        cfg = "CONFIG_STATIC_USERMODEHELPER"
        kversion = Kernel.kernel_version()
        if kversion < "4.11":
            additional = "{:s}: implemented from linux 4.11".format(cfg)
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Unimplemented", "bold red"), additional))
            return

        call_usermodehelper_setup = Symbol.get_ksymaddr("call_usermodehelper_setup")
        if call_usermodehelper_setup is None:
            additional = "call_usermodehelper_setup: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
        else:
            res = gdb.execute("x/50i {:#x}".format(call_usermodehelper_setup), to_string=True)
            use_static = False
            if is_x86_64():
                g = KernelAddressHeuristicFinderUtil.x64_x86_any_const(res)
            elif is_x86_32():
                g = KernelAddressHeuristicFinderUtil.x64_x86_any_const(res)
            elif is_arm64():
                g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
            elif is_arm32():
                g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
            for x in g:
                if not is_valid_addr(x):
                    continue
                # default value of CONFIG_STATIC_USERMODEHELPER_PATH is "/sbin/usermode-helper".
                if read_memory(x, 5) == b"/sbin":
                    use_static = True
                    break
                # sometimes CONFIG_STATIC_USERMODEHELPER_PATH is set to "".
                # If CONFIG_STATIC_USERMODEHELPER_PATH is "", one NUL should be stored.
                # In many cases, another string seems to start being stored at the next address of NUL.
                # It is rare for two consecutive NULs to occur, and we use this in the detection logic.
                if read_memory(x, 1) == b"\x00" and read_memory(x + 1, 1) != b"\x00":
                    # check if the address is read-only or not
                    if get_permission(x) == "R--":
                        use_static = True
                        break
            if use_static:
                additional = "call_usermodehelper_setup uses static path"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
            else:
                additional = "call_usermodehelper_setup uses dynamic path"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
        return

    def check_CONFIG_STACKPROTECTOR(self):
        cfg = "CONFIG_STACKPROTECTOR"
        ktask_ret = gdb.execute("ktask --meta", to_string=True)
        r = re.search(r"offsetof\(task_struct, stack_canary\): (0x\S+)", ktask_ret)
        if r:
            additional = "offsetof(task_struct, stack_canary): {:s}".format(r.group(1))
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        else:
            if "stack_canary" in ktask_ret:
                gef_print("{:<40s}: {:s}".format(cfg, Color.colorify("Disabled", "bold red")))
            else:
                additional = "ktask was failed"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
        return

    def check_CONFIG_SHADOW_CALL_STACK(self):
        if not is_arm64():
            return

        cfg = "CONFIG_SHADOW_CALL_STACK (Clang ARM64)"
        scs_alloc = Symbol.get_ksymaddr("scs_alloc")
        if scs_alloc:
            additional = "scs_alloc: Found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        else:
            additional = "scs_alloc: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
        return

    def check_CONFIG_HARDENED_USERCOPY(self):
        cfg = "CONFIG_HARDENED_USERCOPY"
        __check_heap_object = Symbol.get_ksymaddr("__check_heap_object")
        if __check_heap_object:
            additional = "__check_heap_object: Found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        else:
            additional = "__check_heap_object: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
        return

    def check_kadr_kallsyms(self):
        cfg = "KADR (kallsyms)"
        kversion = Kernel.kernel_version()
        if kversion < "4.15":
            kptr_restrict = KernelAddressHeuristicFinder.get_kptr_restrict()
            if kptr_restrict is None:
                additional = "kernel.kptr_restrict: Not found"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
            else:
                v1 = u32(read_memory(kptr_restrict, 4))
                additional = "kernel.kptr_restrict: {:d}".format(v1)
                if v1 == 0:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
                else:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        else:
            kptr_restrict = KernelAddressHeuristicFinder.get_kptr_restrict()
            sysctl_perf_event_paranoid = KernelAddressHeuristicFinder.get_sysctl_perf_event_paranoid()
            if kptr_restrict is None:
                additional = "kernel.kptr_restrict: Not found"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
            elif sysctl_perf_event_paranoid is None:
                additional = "kernel.perf_event_paranoid: Not found"
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
            else:
                v1 = u32(read_memory(kptr_restrict, 4))
                v2 = u32(read_memory(sysctl_perf_event_paranoid, 4), s=True)
                additional = "kernel.kptr_restrict: {:d}, kernel.perf_event_paranoid: {:d}".format(v1, v2)
                if v1 == 0 and v2 <= 1:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
                else:
                    gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        return

    def check_kadr_dmesg(self):
        dmesg_restrict = KernelAddressHeuristicFinder.get_dmesg_restrict()
        cfg = "KADR (dmesg)"
        if dmesg_restrict is None:
            additional = "kernel.dmesg_restrict: Not found"
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
        else:
            v1 = u32(read_memory(dmesg_restrict, 4))
            additional = "kernel.dmesg_restrict: {:d}".format(v1)
            if v1 == 0:
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Disabled", "bold red"), additional))
            else:
                gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.colorify("Enabled", "bold green"), additional))
        return

    def check_mmap_min_addr(self):
        cfg = "vm.mmap_min_addr"
        mmap_min_addr = KernelAddressHeuristicFinder.get_mmap_min_addr()
        if mmap_min_addr is None:
            additional = "{:s}: Not found".format(cfg)
            gef_print("{:<40s}: {:s} ({:s})".format(cfg, Color.grayify("Unknown"), additional))
            return

        val = read_int_from_memory(mmap_min_addr)
        if val:
            gef_print("{:<40s}: {:s}".format(cfg, Color.colorify_hex(val, "bold green")))
        else:
            gef_print("{:<40s}: {:s}".format(cfg, Color.colorify_hex(val, "bold red")))
        return

    def check_supported_syscall(self):
        cfg = "Supported system call"
        supported_syscall = []
        if is_x86_32():
            if KernelAddressHeuristicFinder.get_sys_call_table_x86():
                supported_syscall.append("x86(native)")
        elif is_x86_64():
            if KernelAddressHeuristicFinder.get_sys_call_table_x64():
                supported_syscall.append("x64")
            if KernelAddressHeuristicFinder.get_sys_call_table_x86():
                supported_syscall.append("x86(compat)")
            elif Symbol.get_ksymaddr("ia32_sys_call"): # 6.6.26~
                supported_syscall.append("x86(compat)")
            if KernelAddressHeuristicFinder.get_sys_call_table_x32():
                supported_syscall.append("x32")
            elif Symbol.get_ksymaddr("x32_sys_call"): # 6.6.26~
                supported_syscall.append("x32")
        elif is_arm32():
            if KernelAddressHeuristicFinder.get_sys_call_table_arm32():
                supported_syscall.append("arm32(native)")
        elif is_arm64():
            if KernelAddressHeuristicFinder.get_sys_call_table_arm64():
                supported_syscall.append("arm64")
            if KernelAddressHeuristicFinder.get_sys_call_table_arm64_compat():
                supported_syscall.append("arm32(compat)")
        if supported_syscall:
            gef_print("{:<40s}: {:s}".format(cfg, ", ".join(supported_syscall)))
        else:
            gef_print("{:<40s}: {:s}".format(cfg, "???"))
        return

    def print_security_properties_qemu_system(self):
        gef_print(titlify("Kernel information"))
        kversion = Kernel.kernel_version()
        if kversion is None:
            err("Linux kernel is not found")
            return
        gef_print("{:<40s}: {:d}.{:d}.{:d}".format("Kernel version", kversion.major, kversion.minor, kversion.patch))
        self.check_basic_information()

        gef_print(titlify("Register settings"))
        self.x86_specific()
        self.arm32_specific()
        self.arm64_specific()

        if Symbol.get_ksymaddr("_stext") is None:
            err("ksymaddr-remote is failed.")
            return

        gef_print(titlify("Memory settings"))
        self.check_kaslr()
        self.check_fgkaslr()
        self.check_kpti()
        self.check_rwx_page()
        self.check_secure_world()

        gef_print(titlify("Allocator"))
        allocator = KernelChecksecCommand.get_slab_type()
        gef_print("{:<40s}: {:s}".format("Allocator", allocator))
        if allocator == "SLUB":
            self.check_CONFIG_SLAB_FREELIST_HARDENED()

        gef_print(titlify("Security Module"))
        self.check_selinux()
        self.check_smack()
        self.check_apparmor()
        self.check_tomoyo()
        self.check_yama()
        self.check_integrity()
        self.check_loadpin()
        self.check_safe_setid()
        self.check_lockdown()
        self.check_bpf()
        self.check_landlock()
        self.check_lkrg()

        gef_print(titlify("Dangerous system call"))
        self.check_unprivileged_userfaultfd()
        self.check_unprivileged_bpf_disabled()
        self.check_kexec_load_disabled()

        gef_print(titlify("namespaces"))
        self.check_namespaces()
        self.check_unprivileged_userns_clone()
        self.check_userns_restrict()

        gef_print(titlify("Other"))
        self.check_CONFIG_KALLSYMS_ALL()
        self.check_CONFIG_IKCONFIG()
        self.check_CONFIG_RANDSTRUCT()
        self.check_CONFIG_STATIC_USERMODEHELPER()
        self.check_CONFIG_STACKPROTECTOR()
        self.check_CONFIG_SHADOW_CALL_STACK()
        self.check_CONFIG_HARDENED_USERCOPY()
        self.check_kadr_kallsyms()
        self.check_kadr_dmesg()
        self.check_mmap_min_addr()
        self.check_supported_syscall()
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.print_security_properties_qemu_system()
        return


@register_command
class DwarfExceptionHandlerInfoCommand(GenericCommand):
    """Dump the DWARF exception handler information with the byte code itself."""
    _cmdline_ = "dwarf-exception-handler"
    _category_ = "02-e. Process Information - Complex Structure Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--file", help="the file path to parse.")
    parser.add_argument("-r", "--remote", action="store_true",
                        help="parse remote binary if download feature is available.")
    parser.add_argument("-x", "--hexdump", action="store_true", help="with hexdump.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}                    # parse loaded binary\n".format(_cmdline_)
    _example_ += "{:s} -r                 # parse remote binary\n".format(_cmdline_)
    _example_ += "{:s} -f /path/to/binary # parse specified binary\n".format(_cmdline_)
    _example_ += "{:s} -x                 # with hexdump".format(_cmdline_)

    _note_ = "Simplified DWARF exception structure:\n"
    _note_ += "\n"
    _note_ += "[OLD IMPLEMENTATION]\n"
    _note_ += " libgcc_s.so bss area               ELF Program Header (for .eh_frame_hdr)\n"
    _note_ += "+-----------------------+      +-->+----------------+\n"
    _note_ += "| ...                   |      |   | p_type         |\n"
    _note_ += "| frame_hdr_cache_head  |---+  |   | p_flags        |\n"
    _note_ += "+-frame_hdr_cache_entry-+<--+  |   | p_offset       |\n"
    _note_ += "| pc_low                |      |   | p_vaddr        |----+\n"
    _note_ += "| pc_high               |      |   | p_paddr        |    |\n"
    _note_ += "| load_base             |      |   | p_filesz       |    |\n"
    _note_ += "| p_eh_frame_hdr        |------+   | p_memsz        |    |\n"
    _note_ += "| p_dynamic             |          | p_align        |    |         [NEW IMPLEMENTATION]\n"
    _note_ += "| link                  |---+      +----------------+    |          _dlfo_main@ld.so rodata area\n"
    _note_ += "+-frame_hdr_cache_entry-+<--+                            |          _dlfo_nodelete_mappings@ld.so rodata area\n"
    _note_ += "| pc_low                |                                |         +-------------+\n"
    _note_ += "| pc_high               |                                |         | map_start   |\n"
    _note_ += "| load_base             |                                |         | map_end     |\n"
    _note_ += "| p_eh_frame_hdr        |                                |         | map         |\n"
    _note_ += "| p_dynamic             |                                |<--------| eh_frame    |\n"
    _note_ += "| link                  |                                |         | (eh_dbase)  |\n"
    _note_ += "+-----------------------+                                |         | (eh_count)  |\n"
    _note_ += "The frame_hdr_cache_head and frame_hdr_cache_entry are   |         +-------------+\n"
    _note_ += "initialized the first time they are called.              |\n"
    _note_ += "                                                         |\n"
    _note_ += "                           +-----------------------------+\n"
    _note_ += "                           |\n"
    _note_ += ".eh_frame_hdr              |      .eh_frame                                           .gcc_except_table\n"
    _note_ += "+----------------------+<--+  +-->+-CIE-------------------+<--+                   +-->+-LSDA-----------------+\n"
    _note_ += "| version              |      |   | length                |   |                   |   | lpstart_enc          |\n"
    _note_ += "| eh_frame_ptr_enc     |      |   | cie_id (=0)           |   |                   |   | ttype_enc            |\n"
    _note_ += "| fde_count_enc        |      |   | version               |   |                   |   | ttype_off            |\n"
    _note_ += "| table_enc            |      |   | augmentation_string   |   |                   |   | call_site_encoding   |\n"
    _note_ += "| eh_frame_ptr         |------+   | code_alignment_factor |   |                   |   | call_site_table_len  |\n"
    _note_ += "| fde_count            |          | data_alignment_factor |   |                   |   |+-CallSite-----------+|\n"
    _note_ += "| Table[0] initial_loc |          | retaddr_register      |   |                   |   || call_site_start    || try_start\n"
    _note_ += "| Table[0] fde         |---+      | augmentation_len      |   |                   |   || call_site_length   || try_end\n"
    _note_ += "| Table[1] initial_loc |   |      | augmentation_data[0]  |   |                   |   || landing_pad        || catch_start\n"
    _note_ += "| Table[1] fde         |   |      | ...                   |-(augmentation=='P')-+ |   || action             ||---+\n"
    _note_ += "| ...                  |   |      | ...                   |   |                 | |   |+-CallSite-----------+|   |\n"
    _note_ += "| Table[N] initial_loc |   |      | augmentation_data[N]  |   |                 | |   || ...                ||   |\n"
    _note_ += "| Table[N] fde         |   |      | program               |   |                 | |   |+-ActionTable--------+|<--+\n"
    _note_ += "+----------------------+   +----->+-FDE-------------------+   |                 | |   || ar_filter          ||---+\n"
    _note_ += "                                  | length                |   |                 | |   || ar_disp            ||   |\n"
    _note_ += "                                  | cie_pointer (!=0)     |---+                 | |   |+-ActionTable--------+|   |\n"
    _note_ += "                                  | pc_begin              | try_catch_base      | |   || ...                ||   |\n"
    _note_ += "                                  | pc_range              |                     | |   |+-TTypeTable---------+|   |\n"
    _note_ += "                                  | augmentation_len      |                     | |   || ...(stored upward) ||   |\n"
    _note_ += "                                  | augmentation_data[0]  |                     | |   |+-TTypeTable---------+|<--+\n"
    _note_ += "                                  | ...                   |-(augmentation=='L')-|-+   || ttype              ||---> type_info\n"
    _note_ += "                                  | augmentation_data[N]  |                     |     |+--------------------+|\n"
    _note_ += "                                  | program               |                     |     +-LSDA-----------------+\n"
    _note_ += "                                  +-CIE-------------------+   +-----------------+     | ...                  |\n"
    _note_ += "                                  | ...                   |   |                       +----------------------+\n"
    _note_ += "                                  +-FDE-------------------+   |\n"
    _note_ += "                                  | ...                   |   |\n"
    _note_ += "                                  +-----------------------+   |\n"
    _note_ += "                                                              +----> personality_routine(=__gxx_personality_v0@libstdc++.so)"

    # FDE data encoding
    DW_EH_PE_ptr      = 0x00
    DW_EH_PE_uleb128  = 0x01
    DW_EH_PE_udata2   = 0x02
    DW_EH_PE_udata4   = 0x03
    DW_EH_PE_udata8   = 0x04
    DW_EH_PE_signed   = 0x08 # noqa: F841
    DW_EH_PE_sleb128  = 0x09
    DW_EH_PE_sdata2   = 0x0a
    DW_EH_PE_sdata4   = 0x0b
    DW_EH_PE_sdata8   = 0x0c
    # FDE flags
    DW_EH_PE_absptr   = 0x00
    DW_EH_PE_pcrel    = 0x10
    DW_EH_PE_textrel  = 0x20
    DW_EH_PE_datarel  = 0x30
    DW_EH_PE_funcrel  = 0x40
    DW_EH_PE_aligned  = 0x50
    DW_EH_PE_indirect = 0x80
    DW_EH_PE_omit     = 0xff

    def format_entry(self, sec, entries):
        out = []
        out.append(titlify(sec.name))

        # hexdump
        if self.hexdump:
            out.append(hexdump(sec.data, show_symbol=False, base=sec.offset))

        # print details
        fmt = "[{:<8}|+{:<6}] {:<23s} {:<30s}: {:<18s}  |  {:s}"
        legend = ["FileOff", "Offset", "Raw bytes", "Name", "Value", "Extra Information"]
        out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        for entry in entries:
            if len(entry) == 1:
                out.append("[!] " + entry[0])

            elif len(entry) == 3: # separation
                pos, name, extra = entry
                if extra:
                    extra_s = "  |  {:s}".format(extra)
                else:
                    extra_s = ""
                out.append(titlify("[{:#06x}] {:4s}{:s}".format(pos, name, extra_s), color="red", msg_color="red"))

            elif len(entry) == 5: # data
                pos, raw_data, name, value, extra = entry

                pos_s = "[{:#08x}|+{:#06x}]".format(sec.offset + pos, pos)

                if raw_data is None:
                    raw_data_s = ""
                elif isinstance(raw_data, int):
                    raw_data_s = "{:02x}".format(raw_data)
                elif isinstance(raw_data, bytes):
                    raw_data_s = " ".join(["{:02x}".format(x) for x in raw_data])
                else:
                    raise

                if isinstance(value, str):
                    value_s = value
                elif isinstance(value, int):
                    value_s = "{:#018x}".format(value)
                elif isinstance(value, list):
                    value_s = " ".join(["{:#018x}".format(x) for x in value])

                if value is not None:
                    out.append("{:s} {:<23s} {:<30s}: {:<18s}  |  {:s}".format(pos_s, raw_data_s, name, value_s, extra))
                else:
                    out.append("{:s} {:<23s} {:<50s}  |  {:s}".format(pos_s, raw_data_s, name, extra))
        return out

    def get_uleb128(self, data, pos):
        acc = 0
        i = 0
        while True:
            if i == 10:
                return pos, 0xffffffffffffffff
            pos, b = self.read_1ubyte(data, pos)
            acc |= (b & 0x7f) << (i * 7)
            if (b & 0x80) == 0:
                return pos, acc
            i += 1

    def get_sleb128(self, data, pos):
        orig_pos = pos
        pos, acc = self.get_uleb128(data, pos)
        length = pos - orig_pos
        sleb_sign_mask = 1 << (length * 7 - 1)
        if (acc & sleb_sign_mask) == 0:
            return pos, acc
        else:
            sleb_value_mask = sleb_sign_mask - 1
            sleb_value = acc & sleb_value_mask
            bit_len = len("{:b}".format(sleb_value))
            real_sign_mask = 1 << bit_len
            real_value_mask = real_sign_mask - 1
            return pos, -1 * (((~sleb_value) & real_value_mask) + 1)

    def read_1ubyte(self, data, pos):
        acc = data[pos]
        return pos + 1, acc

    def read_1sbyte(self, data, pos):
        pB = lambda a: struct.pack("<B", a & 0xff)
        ub = lambda a: struct.unpack("<b", a)[0]
        u2i = lambda a: ub(pB(a))
        acc = data[pos]
        return pos + 1, u2i(acc)

    def read_2ubyte(self, data, pos):
        acc = (data[pos + 1] << 8) | data[pos]
        return pos + 2, acc

    def read_2sbyte(self, data, pos):
        pH = lambda a: struct.pack("<H", a & 0xffff)
        uh = lambda a: struct.unpack("<h", a)[0]
        u2i = lambda a: uh(pH(a))
        acc = (data[pos + 1] << 8) | data[pos]
        return pos + 2, u2i(acc)

    def read_4ubyte(self, data, pos):
        acc = (data[pos + 3] << 24) | (data[pos + 2] << 16) | (data[pos + 1] << 8) | data[pos]
        return pos + 4, acc

    def read_4sbyte(self, data, pos):
        pI = lambda a: struct.pack("<I", a & 0xffffffff)
        ui = lambda a: struct.unpack("<i", a)[0]
        u2i = lambda a: ui(pI(a))
        acc = (data[pos + 3] << 24) | (data[pos + 2] << 16) | (data[pos + 1] << 8) | data[pos]
        return pos + 4, u2i(acc)

    def read_8ubyte(self, data, pos):
        acc = (data[pos + 7] << 56) | (data[pos + 6] << 48) | (data[pos + 5] << 40) | (data[pos + 4] << 32)
        acc |= (data[pos + 3] << 24) | (data[pos + 2] << 16) | (data[pos + 1] << 8) | data[pos]
        return pos + 8, acc

    def read_8sbyte(self, data, pos):
        pQ = lambda a: struct.pack("<Q", a & 0xffffffffffffffff)
        uq = lambda a: struct.unpack("<q", a)[0]
        u2i = lambda a: uq(pQ(a))
        acc = (data[pos + 7] << 56) | (data[pos + 6] << 48) | (data[pos + 5] << 40) | (data[pos + 4] << 32)
        acc |= (data[pos + 3] << 24) | (data[pos + 2] << 16) | (data[pos + 1] << 8) | data[pos]
        return pos + 8, u2i(acc)

    def read_encoded(self, encoding, data, pos):
        if (encoding & 0xf) == self.DW_EH_PE_ptr:
            if self.elf.e_class == Elf.ELF_32_BITS:
                pos, res = self.read_4ubyte(data, pos)
            else:
                pos, res = self.read_8ubyte(data, pos)
        elif (encoding & 0xf) == self.DW_EH_PE_uleb128:
            pos, res = self.get_uleb128(data, pos)
        elif (encoding & 0xf) == self.DW_EH_PE_sleb128:
            pos, res = self.get_sleb128(data, pos)
        elif (encoding & 0xf) == self.DW_EH_PE_udata2:
            pos, res = self.read_2ubyte(data, pos)
        elif (encoding & 0xf) == self.DW_EH_PE_udata4:
            pos, res = self.read_4ubyte(data, pos)
        elif (encoding & 0xf) == self.DW_EH_PE_udata8:
            pos, res = self.read_8ubyte(data, pos)
        elif (encoding & 0xf) == self.DW_EH_PE_sdata2:
            pos, res = self.read_2sbyte(data, pos)
        elif (encoding & 0xf) == self.DW_EH_PE_sdata4:
            pos, res = self.read_4sbyte(data, pos)
        elif (encoding & 0xf) == self.DW_EH_PE_sdata8:
            pos, res = self.read_8sbyte(data, pos)
        else:
            raise
        return pos, res

    def get_encoding_str(self, fde_encoding):
        if fde_encoding == self.DW_EH_PE_omit:
            return "omit"
        s = []
        if (fde_encoding & 0xf) == self.DW_EH_PE_ptr:
            s.append("ptr")
        elif (fde_encoding & 0xf) == self.DW_EH_PE_uleb128:
            s.append("uleb128")
        elif (fde_encoding & 0xf) == self.DW_EH_PE_sleb128:
            s.append("sleb128")
        elif (fde_encoding & 0xf) == self.DW_EH_PE_udata2:
            s.append("udata2")
        elif (fde_encoding & 0xf) == self.DW_EH_PE_sdata2:
            s.append("sdata2")
        elif (fde_encoding & 0xf) == self.DW_EH_PE_udata4:
            s.append("udata4")
        elif (fde_encoding & 0xf) == self.DW_EH_PE_sdata4:
            s.append("sdata4")
        elif (fde_encoding & 0xf) == self.DW_EH_PE_udata8:
            s.append("udata8")
        elif (fde_encoding & 0xf) == self.DW_EH_PE_sdata8:
            s.append("sdata8")
        if (fde_encoding & 0x70) == self.DW_EH_PE_absptr:
            s.append("absptr")
        elif (fde_encoding & 0x70) == self.DW_EH_PE_pcrel:
            s.append("pcrel")
        elif (fde_encoding & 0x70) == self.DW_EH_PE_textrel:
            s.append("textrel")
        elif (fde_encoding & 0x70) == self.DW_EH_PE_datarel:
            s.append("datarel")
        elif (fde_encoding & 0x70) == self.DW_EH_PE_funcrel:
            s.append("funcrel")
        elif (fde_encoding & 0x70) == self.DW_EH_PE_aligned:
            s.append("aligned")
        if (fde_encoding & 0x80) == self.DW_EH_PE_indirect:
            s.append("indirect")
        return ",".join(s)

    def encoded_ptr_size(self, encoding, ptr_size):
        if (encoding & 0xf) == self.DW_EH_PE_ptr:
            return ptr_size
        elif (encoding & 0xf) in [self.DW_EH_PE_udata2, self.DW_EH_PE_sdata2]:
            return 2
        elif (encoding & 0xf) in [self.DW_EH_PE_udata4, self.DW_EH_PE_sdata4]:
            return 4
        elif (encoding & 0xf) in [self.DW_EH_PE_udata8, self.DW_EH_PE_sdata8]:
            return 8
        elif encoding == self.DW_EH_PE_omit:
            return 0
        err("Unsupported pointer encoding: {:#x}, assuming pointer size of {:d}.".format(encoding, ptr_size))
        return 0

    def parse_eh_frame_hdr(self, eh_frame_hdr):
        data = eh_frame_hdr.data
        shdr = self.elf.get_shdr(".eh_frame_hdr")
        load_base = self.elf.get_phdr(Elf.Phdr.PT_LOAD).p_vaddr

        entries = []
        pos = 0

        try:
            new_pos, version = self.read_1ubyte(data, pos)
            entries.append([pos, data[pos:new_pos], "version", version, ""])
            pos = new_pos

            new_pos, eh_frame_ptr_enc = self.read_1ubyte(data, pos)
            encoding_str = self.get_encoding_str(eh_frame_ptr_enc)
            entries.append([pos, data[pos:new_pos], "eh_frame_ptr_enc", eh_frame_ptr_enc, "encoding: {:s}".format(encoding_str)])
            pos = new_pos

            new_pos, fde_count_enc = self.read_1ubyte(data, pos)
            encoding_str = self.get_encoding_str(fde_count_enc)
            entries.append([pos, data[pos:new_pos], "fde_count_enc", fde_count_enc, "encoding: {:s}".format(encoding_str)])
            pos = new_pos

            new_pos, table_enc = self.read_1ubyte(data, pos)
            encoding_str = self.get_encoding_str(table_enc)
            entries.append([pos, data[pos:new_pos], "table_enc", table_enc, "encoding: {:s}".format(encoding_str)])
            pos = new_pos

            eh_frame_ptr = 0
            if eh_frame_ptr_enc != self.DW_EH_PE_omit:
                new_pos, eh_frame_ptr = self.read_encoded(eh_frame_ptr_enc, data, pos)
                if (eh_frame_ptr_enc & 0x70) == self.DW_EH_PE_pcrel:
                    elf_offset = shdr.sh_offset + 4 + eh_frame_ptr
                    if self.elf.is_pie():
                        extra_s = "vma: $codebase+{:#x}".format(load_base + elf_offset)
                    else:
                        extra_s = "vma: {:#x}".format(load_base + elf_offset)
                    entries.append([pos, data[pos:new_pos], "eh_frame_ptr", elf_offset, extra_s])
                else:
                    entries.append([pos, data[pos:new_pos], "eh_frame_ptr", eh_frame_ptr, ""])
                pos = new_pos

            fde_count = 0
            if fde_count_enc != self.DW_EH_PE_omit:
                new_pos, fde_count = self.read_encoded(fde_count_enc, data, pos)
                entries.append([pos, data[pos:new_pos], "fde_count", fde_count, ""])
                pos = new_pos

            table_cnt = 0
            if table_enc == (self.DW_EH_PE_datarel | self.DW_EH_PE_sdata4):
                while fde_count and data[pos:]:
                    entries.append([pos, "Table[{:4d}]".format(table_cnt), ""])

                    new_pos, initial_loc = self.read_4sbyte(data, pos)
                    initial_offset = shdr.sh_offset + initial_loc
                    if self.elf.is_pie():
                        extra_s = "vma: $codebase+{:#x}".format(load_base + initial_offset)
                    else:
                        extra_s = "vma: {:#x}".format(load_base + initial_offset)
                    entries.append([pos, data[pos:new_pos], "initial_loc", initial_offset, extra_s])
                    pos = new_pos

                    new_pos, fde_offset = self.read_4sbyte(data, pos)
                    fde_offset_adjusted = fde_offset - (eh_frame_ptr + 4)
                    if self.elf.is_pie():
                        extra_s = "vma: $codebase+{:#x}".format(load_base + shdr.sh_offset + fde_offset)
                    else:
                        extra_s = "vma: {:#x}".format(load_base + shdr.sh_offset + fde_offset)
                    entries.append([pos, data[pos:new_pos], "fde", fde_offset_adjusted, extra_s])
                    pos = new_pos

                    table_cnt += 1
        except Exception:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            entries.append(["Parse Error\n{}".format(exc_value)])
        return entries

    def parse_eh_frame(self, eh_frame):
        data = eh_frame.data
        shdr = self.elf.get_shdr(".eh_frame")
        load_base = self.elf.get_phdr(Elf.Phdr.PT_LOAD).p_vaddr

        cies = []
        entries = []
        pos = 0

        try:
            while data[pos:]:
                offset = pos
                tmp_entries = []

                # parse length
                new_pos, unit_length = self.read_4ubyte(data, pos)
                length = 4 # default
                tmp_entries.append([pos, data[pos:new_pos], "length", unit_length, ""])
                pos = new_pos
                if unit_length == 0xffffffff:
                    new_pos, unit_length = self.read_8ubyte(data, pos)
                    length = 8
                    tmp_entries.append([pos, data[pos:new_pos], "extended_length", unit_length, ""])
                    pos = new_pos
                if unit_length == 0:
                    entries.append([offset, "Zero terminator", ""])
                    entries += tmp_entries
                    tmp_entries = []
                    continue

                ptr_size = 4 if self.elf.e_class == Elf.ELF_32_BITS else 8
                start = pos # use later
                cie_end = pos + unit_length

                # parse cie_id / cie_pointer
                if length == 4:
                    new_pos, cie_id = self.read_4ubyte(data, pos)
                else:
                    new_pos, cie_id = self.read_8ubyte(data, pos)
                if cie_id == 0:
                    tmp_entries.append([pos, data[pos:new_pos], "cie_id", cie_id, "type: CIE"])
                else:
                    extra_s = "type: FDE, Associated_CIE: {:#x}(={:#x}-{:#x})".format(start - cie_id, start, cie_id)
                    tmp_entries.append([pos, data[pos:new_pos], "cie_pointer", cie_id, extra_s])
                pos = new_pos

                version = 2
                fde_encoding = 0
                lsda_encoding = 0
                initial_location = 0
                vma_base = 0

                if cie_id == 0:  # CIE parsing
                    entries.append([offset, "CIE", ""])
                    entries += tmp_entries
                    tmp_entries = []

                    # parse version
                    new_pos, version = self.read_1ubyte(data, pos)
                    entries.append([pos, data[pos:new_pos], "version", version, ""])
                    pos = new_pos

                    # parse augmentation string
                    orig_pos = pos
                    augmentation = ""
                    while data[pos]:
                        augmentation += chr(data[pos])
                        pos += 1
                    pos += 1 # skip NUL
                    entries.append([orig_pos, data[orig_pos:pos], "augmentation_string", '"{:s}"'.format(augmentation), ""])

                    # parse ptr_size, segment_size
                    segment_size = 0
                    if version >= 4:
                        new_pos, ptr_size = self.raed_1ubyte(data, pos)
                        entries.append([pos, data[pos:new_pos], "ptr_size", ptr_size, ""])
                        pos = new_pos
                        new_pos, segment_size = self.read_1ubyte(data, pos)
                        entries.append([pos, data[pos:new_pos], "segment_size", segment_size, ""])
                        pos = new_pos

                    # parse code/data alignment factor
                    new_pos, code_alignment_factor = self.get_uleb128(data, pos)
                    entries.append([pos, data[pos:new_pos], "code_alignment_factor", code_alignment_factor, ""])
                    pos = new_pos
                    new_pos, data_alignment_factor = self.get_sleb128(data, pos)
                    entries.append([pos, data[pos:new_pos], "data_alignment_factor", data_alignment_factor, ""])
                    pos = new_pos

                    # parse augmentation data
                    if augmentation == "eh":
                        if self.elf.e_class == Elf.ELF_32_BITS:
                            new_pos, adjust = self.read_4ubyte(data, pos)
                        else:
                            new_pos, adjust = self.read_8ubyte(data, pos)
                        entries.append([pos, data[pos:new_pos], "eh_data", adjust, ""])
                        pos = new_pos

                    if version == 1:
                        new_pos, return_address_register = self.read_1ubyte(data, pos)
                        ra_reg_name = self.get_register_name(return_address_register)
                        extra_s = "Reg: {:s}".format(ra_reg_name)
                        entries.append([pos, data[pos:new_pos], "return_address_register", return_address_register, extra_s])
                        pos = new_pos
                    else:
                        new_pos, return_address_register = self.get_uleb128(data, pos)
                        ra_reg_name = self.get_register_name(return_address_register)
                        extra_s = "Reg: {:s}".format(ra_reg_name)
                        entries.append([pos, data[pos:new_pos], "return_address_register", return_address_register, extra_s])
                        pos = new_pos

                    if augmentation[0] == "z":
                        new_pos, augmentation_len = self.get_uleb128(data, pos)
                        entries.append([pos, data[pos:new_pos], "augmentation_len", augmentation_len, ""])
                        pos = new_pos

                        for cp in augmentation[1:]:
                            if cp == "R":
                                new_pos, fde_encoding = self.read_1ubyte(data, pos)
                                encoding_str = self.get_encoding_str(fde_encoding)
                                extra_s = "FDE address encoding: {:s}".format(encoding_str)
                                entries.append([pos, data[pos:new_pos], "augmentation_data(R)", fde_encoding, extra_s])
                                pos = new_pos
                            elif cp == "L":
                                new_pos, lsda_encoding = self.read_1ubyte(data, pos)
                                encoding_str = self.get_encoding_str(lsda_encoding)
                                extra_s = "LSDA pointer encoding: {:s}".format(encoding_str)
                                entries.append([pos, data[pos:new_pos], "augmentation_data(L)", lsda_encoding, extra_s])
                                pos = new_pos
                            elif cp == "P":
                                new_pos, p_encoding = self.read_1ubyte(data, pos)
                                encoding_str = self.get_encoding_str(p_encoding)
                                extra_s = "Personality pointer encoding: {:s}".format(encoding_str)
                                entries.append([pos, data[pos:new_pos], "augmentation_data(P)", p_encoding, extra_s])
                                pos = new_pos
                                new_pos, p_addr = self.read_encoded(p_encoding, data, pos)
                                if (p_encoding & 0x70) == self.DW_EH_PE_pcrel:
                                    p_addr += shdr.sh_offset + pos
                                    if self.elf.is_pie():
                                        extra_s = "Personality pointer address: $codebase+{:#x}".format(load_base + p_addr)
                                    else:
                                        extra_s = "Personality pointer address: {:#x}".format(load_base + p_addr)
                                else:
                                    extra_s = "Personality pointer address"
                                entries.append([pos, data[pos:new_pos], "augmentation_data(P)", p_addr, extra_s])
                                pos = new_pos
                            else: # unknown
                                new_pos, x = self.read_1ubyte(data, pos)
                                entries.append([pos, data[pos:new_pos], "augmentation_data({:s})".format(cp), x, ""])
                                pos = new_pos
                    if ptr_size == 4 or ptr_size == 8:
                        _cie = {}
                        _cie["cie_offset"] = offset
                        _cie["augmentation"] = augmentation
                        _cie["fde_encoding"] = fde_encoding
                        _cie["lsda_encoding"] = lsda_encoding
                        _cie["address_size"] = ptr_size
                        _cie["code_alignment_factor"] = code_alignment_factor
                        _cie["data_alignment_factor"] = data_alignment_factor
                        Cie = collections.namedtuple("Cie", _cie.keys())
                        cie = Cie(*_cie.values())
                        cies.append(cie)

                else: # FDE parsing
                    cie = [x for x in cies if start - cie_id == x.cie_offset][0]

                    entries.append([offset, "FDE", ""])
                    entries += tmp_entries # unit_length, cie_pointer
                    tmp_entries = []

                    ptr_size = self.encoded_ptr_size(cie.fde_encoding, cie.address_size)
                    base = pos

                    # parse pc_begin
                    if ptr_size == 4:
                        new_pos, initial_location = self.read_4ubyte(data, pos)
                    elif ptr_size == 8:
                        new_pos, initial_location = self.read_8ubyte(data, pos)
                    if (cie.fde_encoding & 0x70) == self.DW_EH_PE_pcrel:
                        vma_base = shdr.sh_offset + base + initial_location
                        if ptr_size == 4:
                            vma_base &= 0xffffffff
                        elif ptr_size == 8:
                            vma_base &= 0xffffffffffffffff
                        if self.elf.is_pie():
                            extra_s = "pc_begin vma: $codebase+{:#x}".format(load_base + vma_base)
                        else:
                            extra_s = "pc_begin vma: {:#x}".format(load_base + vma_base)
                        entries.append([pos, data[pos:new_pos], "pc_begin", vma_base, extra_s])
                    else:
                        entries.append([pos, data[pos:new_pos], "pc_begin", initial_location, ""])
                    pos = new_pos

                    # parse pc_range
                    if ptr_size == 4:
                        new_pos, pc_range = self.read_4ubyte(data, pos)
                    elif ptr_size == 8:
                        new_pos, pc_range = self.read_8ubyte(data, pos)
                    if (cie.fde_encoding & 0x70) == self.DW_EH_PE_pcrel:
                        end_off = vma_base + pc_range
                    else:
                        end_off = initial_location + pc_range
                    if ptr_size == 4:
                        end_off &= 0xffffffff
                    elif ptr_size == 8:
                        end_off &= 0xffffffffffffffff
                    if self.elf.is_pie():
                        extra_s = "pc_end vma: $codebase+{:#x}".format(load_base + end_off)
                    else:
                        extra_s = "pc_end vma: {:#x}".format(load_base + end_off)
                    entries.append([pos, data[pos:new_pos], "pc_range", pc_range, extra_s])
                    pos = new_pos

                    # parse augmentation
                    if cie.augmentation[0] == "z":
                        new_pos, augmentation_len = self.get_uleb128(data, pos)
                        entries.append([pos, data[pos:new_pos], "augmentation_len", augmentation_len, ""])
                        pos = new_pos

                        aug_end = pos + augmentation_len
                        if augmentation_len:
                            for cp in cie.augmentation[1:]:
                                if cp == "L":
                                    new_pos, lsda_pointer = self.read_encoded(cie.lsda_encoding, data, pos)
                                    if (cie.lsda_encoding & 0x70) == self.DW_EH_PE_pcrel:
                                        lsda_pointer += shdr.sh_offset + pos
                                        if self.elf.is_pie():
                                            extra_s = "LSDA pointer vma: $codebase+{:#x}".format(load_base + lsda_pointer)
                                        else:
                                            extra_s = "LSDA pointer vma: {:#x}".format(load_base + lsda_pointer)
                                        entries.append([pos, data[pos:new_pos], "augmentation_data(L)", lsda_pointer, extra_s])
                                    else:
                                        entries.append([pos, data[pos:new_pos], "augmentation_data(L)", lsda_pointer, "LSDA pointer"])
                                    pos = new_pos
                            if pos < aug_end:
                                entries.append([pos, data[pos:aug_end], "?", "", ""])
                            pos = aug_end

                # common
                entries += self.parse_cfa_program(data, pos, cie_end, vma_base, version, cie)
                pos = cie_end
        except Exception:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            entries.append(["Parse Error\n{}".format(exc_value)])
        return entries

    DW_CFA_advance_loc                  = 0x40
    DW_CFA_offset                       = 0x80
    DW_CFA_restore                      = 0xc0
    DW_CFA_nop                          = 0x00
    DW_CFA_set_loc                      = 0x01
    DW_CFA_advance_loc1                 = 0x02
    DW_CFA_advance_loc2                 = 0x03
    DW_CFA_advance_loc4                 = 0x04
    DW_CFA_offset_extended              = 0x05
    DW_CFA_restore_extended             = 0x06
    DW_CFA_undefined                    = 0x07
    DW_CFA_same_value                   = 0x08
    DW_CFA_register                     = 0x09
    DW_CFA_remember_state               = 0x0a
    DW_CFA_restore_state                = 0x0b
    DW_CFA_def_cfa                      = 0x0c
    DW_CFA_def_cfa_register             = 0x0d
    DW_CFA_def_cfa_offset               = 0x0e
    DW_CFA_def_cfa_expression           = 0x0f
    DW_CFA_expression                   = 0x10
    DW_CFA_offset_extended_sf           = 0x11
    DW_CFA_def_cfa_sf                   = 0x12
    DW_CFA_def_cfa_offset_sf            = 0x13
    DW_CFA_val_offset                   = 0x14
    DW_CFA_val_offset_sf                = 0x15
    DW_CFA_val_expression               = 0x16
    DW_CFA_low_user                     = 0x1c # noqa: F841
    DW_CFA_MIPS_advance_loc8            = 0x1d
    DW_CFA_GNU_window_save              = 0x2d # dup
    DW_CFA_AARCH64_negate_ra_state      = 0x2d # noqa: F841
    DW_CFA_GNU_args_size                = 0x2e
    DW_CFA_GNU_negative_offset_extended = 0x2f # noqa: F841
    DW_CFA_high_user                    = 0x3f # noqa: F841

    def get_register_name(self, reg):
        if self.elf.e_machine == Elf.EM_X86_64:
            REG_LIST = [
                "rax", "rdx", "rcx", "rbx", "rsi", "rdi", "rbp", "rsp",
                "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
                "rip", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
                "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14",
                "xmm15", "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7",
                "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
                "rflags", "es", "cs", "ss", "ds", "fs", "gs", "???",
                "???", "fs.base", "gs.base", "???", "???", "tr", "ldtr", "mxcsr",
                "fcw", "fsw",
            ]
        elif self.elf.e_machine == Elf.EM_386:
            REG_LIST = [
                "eax", "ecx", "edx", "rbx", "esp", "ebp", "esi", "edi",
                "eip", "eflags", "trapno", "st0", "st1", "st2", "st3", "st4",
                "st5", "st6", "st7", "???", "???", "xmm0", "xmm1", "xmm2",
                "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "mm0", "mm1", "mm2",
                "mm3", "mm4", "mm5", "mm6", "mm7", "fctrl", "fstat", "mxcsr",
                "es", "cs", "ss", "ds", "fs", "gs",
            ]
        elif self.elf.e_machine == Elf.EM_ARM:
            REG_LIST = [
                "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
                "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
                "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
            ] + ["???"] * 40 + [
                "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
                "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
                "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
                "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
                "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
                "wcgr0", "wcgr1", "wcgr2", "wcgr3", "wcgr4", "wcgr5", "wcgr6", "wcgr7",
                "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
                "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15",
                "spsr", "spsr_fiq", "spsr_irq", "spsr_abt", "spsr_und", "spsr_svc",
            ] + ["???"] * 10 + [
                "r8_usr", "r9_usr", "r10_usr", "r11_usr", "r12_usr", "r13_usr", "r14_usr", "r8_fiq",
                "r9_fiq", "r10_fiq", "r11_fiq", "r12_fiq", "r13_fiq", "r14_fiq", "r13_irq", "r14_irq",
                "r13_abt", "r14_abt", "r13_und", "r14_und", "r13_svc", "r14_svc",
            ] + ["???"] * 26 + [
                "wc0", "wc1", "wc2", "wc3", "wc4", "wc5", "wc6", "wc7",
            ]
        elif self.elf.e_machine == Elf.EM_AARCH64:
            REG_LIST = [
                "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
                "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
                "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
                "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp",
                "???", "elr",
            ] + ["???"] * 30 + [
                "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
                "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
                "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
                "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
            ]
        else:
            # other arch is unimplemented
            return "r{:d}".format(reg)

        if reg < len(REG_LIST):
            return REG_LIST[reg]
        return "???"

    def parse_cfa_program(self, data, pos, pos_end, vma_base, version, cie):
        encoding = cie.fde_encoding
        ptr_size = cie.address_size
        code_align = cie.code_alignment_factor
        data_align = cie.data_alignment_factor
        pc = vma_base
        indent = " " * 4

        entries = []
        entries.append([pos, b"", "program", None, ""])
        try:
            while pos < pos_end:
                new_pos, opcode = self.read_1ubyte(data, pos)

                if opcode < self.DW_CFA_advance_loc:
                    if opcode == self.DW_CFA_nop:
                        entries.append([pos, data[pos:new_pos], indent + "nop", None, ""])
                    elif opcode == self.DW_CFA_set_loc:
                        new_pos, op1 = self.read_encoded(encoding, data, new_pos)
                        pc = vma_base + op1
                        entries.append([pos, data[pos:new_pos], indent + "set_loc {:#x} to {:#x}".format(op1, pc), None, ""])
                    elif opcode == self.DW_CFA_advance_loc1:
                        op1 = data[new_pos]
                        new_pos += 1
                        pc += op1 * code_align
                        entries.append([pos, data[pos:new_pos], indent + "advance_loc1 {:#x} to {:#x}".format(op1, pc), None, ""])
                    elif opcode == self.DW_CFA_advance_loc2:
                        new_pos, op1 = self.read_2ubyte(data, new_pos)
                        pc += op1 * code_align
                        entries.append([pos, data[pos:new_pos], indent + "advance_loc2 {:#x} to {:#x}".format(op1, pc), None, ""])
                    elif opcode == self.DW_CFA_advance_loc4:
                        new_pos, op1 = self.read_4ubyte(data, new_pos)
                        pc += op1 * code_align
                        entries.append([pos, data[pos:new_pos], indent + "advance_loc4 {:#x} to {:#x}".format(op1, pc), None, ""])
                    elif opcode == self.DW_CFA_offset_extended:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        new_pos, op2 = self.get_uleb128(data, new_pos)
                        regname = self.get_register_name(op1)
                        off = op2 * data_align
                        entries.append([pos, data[pos:new_pos], indent + "offset_extended r{:d} ({:s}) at cfa{:+#x}".format(op1, regname, off), None, ""])
                    elif opcode == self.DW_CFA_restore_extended:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        regname = self.get_register_name(op1)
                        entries.append([pos, data[pos:new_pos], indent + "restore_extended r{:d} ({:s})".fomart(op1, regname), None, ""])
                    elif opcode == self.DW_CFA_undefined:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        regname = self.get_register_name(op1)
                        entries.append([pos, data[pos:new_pos], indent + "undefined r{:d} ({:s})".format(op1, regname), None, ""])
                    elif opcode == self.DW_CFA_same_value:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        regname = self.get_register_name(op1)
                        entries.append([pos, data[pos:new_pos], indent + "same_value r{:d} ({:s})".format(op1, regname), None, ""])
                    elif opcode == self.DW_CFA_register:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        new_pos, op2 = self.get_uleb128(data, new_pos)
                        regname1 = self.get_register_name(op1)
                        regname2 = self.get_register_name(op2)
                        entries.append([pos, data[pos:new_pos], indent + "register r{:d} ({:s}) in r{:d} ({:s})".format(op1, regname1, op2, regname2), None, ""])
                    elif opcode == self.DW_CFA_remember_state:
                        entries.append([pos, data[pos:new_pos], indent + "remember_state", None, ""])
                    elif opcode == self.DW_CFA_restore_state:
                        entries.append([pos, data[pos:new_pos], indent + "restore_state", None, ""])
                    elif opcode == self.DW_CFA_def_cfa:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        new_pos, op2 = self.get_uleb128(data, new_pos)
                        regname = self.get_register_name(op1)
                        entries.append([pos, data[pos:new_pos], indent + "def_cfa r{:d} ({:s}) at offset {:#x}".format(op1, regname, op2), None, ""])
                    elif opcode == self.DW_CFA_def_cfa_register:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        regname = self.get_register_name(op1)
                        entries.append([pos, data[pos:new_pos], indent + "def_cfa_register r{:d} ({:s})".format(op1, regname), None, ""])
                    elif opcode == self.DW_CFA_def_cfa_offset:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        entries.append([pos, data[pos:new_pos], indent + "def_cfa_offset {:#x}".format(op1), None, ""])
                    elif opcode == self.DW_CFA_def_cfa_expression:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        entries.append([pos, data[pos:new_pos], indent + "def_cfa_expression {:#x}".format(op1), None, ""])
                        entries += self.parse_ops(version, ptr_size, op1, data, new_pos)
                        new_pos += op1
                    elif opcode == self.DW_CFA_expression:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        new_pos, op2 = self.get_uleb128(data, new_pos)
                        regname = self.get_register_name(op1)
                        entries.append([pos, data[pos:new_pos], indent + "expression r{:d} ({:s})".format(op1, regname), None, ""])
                        entries += self.parse_ops(version, ptr_size, op2, data, new_pos)
                        new_pos += op2
                    elif opcode == self.DW_CFA_offset_extended_sf:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        new_pos, op2 = self.get_uleb128(data, new_pos)
                        regname = self.get_register_name(op1)
                        off = op2 * data_align
                        entries.append([pos, data[pos:new_pos], indent + "offset_extended_sf r{:d} ({:s}) at cfa{:+#x}".format(op1, regname, off), None, ""])
                    elif opcode == self.DW_CFA_def_cfa_sf:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        new_pos, op2 = self.get_uleb128(data, new_pos)
                        regname = self.get_register_name(op1)
                        off = op2 * data_align
                        entries.append([pos, data[pos:new_pos], indent + "def_cfa_sf r{:d} ({:s}) at offset {:#x}".format(op1, regname, off), None, ""])
                    elif opcode == self.DW_CFA_def_cfa_offset_sf:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        entries.append([pos, data[pos:new_pos], indent + "def_cfa_offset_sf {:#x}".format(op1 * data_align), None, ""])
                    elif opcode == self.DW_CFA_val_offset:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        new_pos, op2 = self.get_uleb128(data, new_pos)
                        off = op2 * data_align
                        entries.append([pos, data[pos:new_pos], indent + "val_offset {:#x} at offset {:#x}".format(op1, off), None, ""])
                    elif opcode == self.DW_CFA_val_offset_sf:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        new_pos, op2 = self.get_uleb128(data, new_pos)
                        off = op2 * data_align
                        entries.append([pos, data[pos:new_pos], indent + "val_offset_sf {:#x} at offset {:#x}".format(op1, off), None, ""])
                    elif opcode == self.DW_CFA_val_expression:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        new_pos, op2 = self.get_uleb128(data, new_pos)
                        regname = self.get_register_name(op1)
                        entries.append([pos, data[pos:new_pos], indent + "val_expression r{:d} ({:s})".format(op1, regname), None, ""])
                        entries += self.parse_ops(version, ptr_size, op2, data, new_pos)
                        new_pos += op2
                    elif opcode == self.DW_CFA_MIPS_advance_loc8:
                        new_pos, op1 = self.read_8ubyte(data, new_pos)
                        pc += op1 * code_align
                        entries.append([pos, data[pos:new_pos], indent + "MIPS_advance_loc8 {:#x} to {:#x}".format(op1, pc), None, ""])
                    elif opcode == self.DW_CFA_GNU_window_save:
                        if self.elf.e_machine == Elf.EM_AARCH64:
                            entries.append([pos, data[pos:new_pos], indent + "AARCH64_negate_ra_state", None, ""])
                        else:
                            entries.append([pos, data[pos:new_pos], indent + "GNU_window_save", None, ""])
                    elif opcode == self.DW_CFA_GNU_args_size:
                        new_pos, op1 = self.get_uleb128(data, new_pos)
                        entries.append([pos, data[pos:new_pos], indent + "args_size {:#x}".format(op1), None, ""])
                    else:
                        entries.append([pos, data[pos:new_pos], indent + "??? {:#x}".format(opcode), None, ""])
                elif opcode < self.DW_CFA_offset:
                    op1 = opcode & 0x3f
                    pc += op1 * code_align
                    entries.append([pos, data[pos:new_pos], indent + "advance_loc {:d} to {:#x}".format(op1, pc), None, ""])
                elif opcode < self.DW_CFA_restore:
                    op1 = opcode & 0x3f
                    new_pos, op2 = self.get_uleb128(data, new_pos)
                    regname = self.get_register_name(op1)
                    off = op2 * data_align
                    entries.append([pos, data[pos:new_pos], indent + "offset r{:d} ({:s}) at cfa{:+#x}".format(op1, regname, off), None, ""])
                else:
                    op1 = opcode & 0x3f
                    regname = self.get_register_name(op1)
                    entries.append([pos, data[pos:new_pos], indent + "restore r{:d}".format(op1), None, ""])
                pos = new_pos
        except Exception:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            entries.append(["Parse Error\n{}".format(exc_value)])
        return entries

    DW_OP_addr                 = 0x03  # Constant address
    DW_OP_deref                = 0x06  #
    DW_OP_const1u              = 0x08  # Unsigned 1-byte constant
    DW_OP_const1s              = 0x09  # Signed 1-byte constant
    DW_OP_const2u              = 0x0a  # Unsigned 2-byte constant
    DW_OP_const2s              = 0x0b  # Signed 2-byte constant
    DW_OP_const4u              = 0x0c  # Unsigned 4-byte constant
    DW_OP_const4s              = 0x0d  # Signed 4-byte constant
    DW_OP_const8u              = 0x0e  # Unsigned 8-byte constant
    DW_OP_const8s              = 0x0f  # Signed 8-byte constant
    DW_OP_constu               = 0x10  # Unsigned LEB128 constant
    DW_OP_consts               = 0x11  # Signed LEB128 constant
    DW_OP_dup                  = 0x12  #
    DW_OP_drop                 = 0x13  #
    DW_OP_over                 = 0x14  #
    DW_OP_pick                 = 0x15  # 1-byte stack index
    DW_OP_swap                 = 0x16  #
    DW_OP_rot                  = 0x17  #
    DW_OP_xderef               = 0x18  #
    DW_OP_abs                  = 0x19  #
    DW_OP_and                  = 0x1a  #
    DW_OP_div                  = 0x1b  #
    DW_OP_minus                = 0x1c  #
    DW_OP_mod                  = 0x1d  #
    DW_OP_mul                  = 0x1e  #
    DW_OP_neg                  = 0x1f  #
    DW_OP_not                  = 0x20  #
    DW_OP_or                   = 0x21  #
    DW_OP_plus                 = 0x22  #
    DW_OP_plus_uconst          = 0x23  # Unsigned LEB128 addend
    DW_OP_shl                  = 0x24  #
    DW_OP_shr                  = 0x25  #
    DW_OP_shra                 = 0x26  #
    DW_OP_xor                  = 0x27  #
    DW_OP_bra                  = 0x28  # Signed 2-byte constant
    DW_OP_eq                   = 0x29  #
    DW_OP_ge                   = 0x2a  #
    DW_OP_gt                   = 0x2b  #
    DW_OP_le                   = 0x2c  #
    DW_OP_lt                   = 0x2d  #
    DW_OP_ne                   = 0x2e  #
    DW_OP_skip                 = 0x2f  # Signed 2-byte constant
    DW_OP_lit0                 = 0x30  # Literal 0
    DW_OP_lit1                 = 0x31  # Literal 1
    DW_OP_lit2                 = 0x32  # Literal 2
    DW_OP_lit3                 = 0x33  # Literal 3
    DW_OP_lit4                 = 0x34  # Literal 4
    DW_OP_lit5                 = 0x35  # Literal 5
    DW_OP_lit6                 = 0x36  # Literal 6
    DW_OP_lit7                 = 0x37  # Literal 7
    DW_OP_lit8                 = 0x38  # Literal 8
    DW_OP_lit9                 = 0x39  # Literal 9
    DW_OP_lit10                = 0x3a  # Literal 10
    DW_OP_lit11                = 0x3b  # Literal 11
    DW_OP_lit12                = 0x3c  # Literal 12
    DW_OP_lit13                = 0x3d  # Literal 13
    DW_OP_lit14                = 0x3e  # Literal 14
    DW_OP_lit15                = 0x3f  # Literal 15
    DW_OP_lit16                = 0x40  # Literal 16
    DW_OP_lit17                = 0x41  # Literal 17
    DW_OP_lit18                = 0x42  # Literal 18
    DW_OP_lit19                = 0x43  # Literal 19
    DW_OP_lit20                = 0x44  # Literal 20
    DW_OP_lit21                = 0x45  # Literal 21
    DW_OP_lit22                = 0x46  # Literal 22
    DW_OP_lit23                = 0x47  # Literal 23
    DW_OP_lit24                = 0x48  # Literal 24
    DW_OP_lit25                = 0x49  # Literal 25
    DW_OP_lit26                = 0x4a  # Literal 26
    DW_OP_lit27                = 0x4b  # Literal 27
    DW_OP_lit28                = 0x4c  # Literal 28
    DW_OP_lit29                = 0x4d  # Literal 29
    DW_OP_lit30                = 0x4e  # Literal 30
    DW_OP_lit31                = 0x4f  # Literal 31
    DW_OP_reg0                 = 0x50  # Register 0
    DW_OP_reg1                 = 0x51  # Register 1
    DW_OP_reg2                 = 0x52  # Register 2
    DW_OP_reg3                 = 0x53  # Register 3
    DW_OP_reg4                 = 0x54  # Register 4
    DW_OP_reg5                 = 0x55  # Register 5
    DW_OP_reg6                 = 0x56  # Register 6
    DW_OP_reg7                 = 0x57  # Register 7
    DW_OP_reg8                 = 0x58  # Register 8
    DW_OP_reg9                 = 0x59  # Register 9
    DW_OP_reg10                = 0x5a  # Register 10
    DW_OP_reg11                = 0x5b  # Register 11
    DW_OP_reg12                = 0x5c  # Register 12
    DW_OP_reg13                = 0x5d  # Register 13
    DW_OP_reg14                = 0x5e  # Register 14
    DW_OP_reg15                = 0x5f  # Register 15
    DW_OP_reg16                = 0x60  # Register 16
    DW_OP_reg17                = 0x61  # Register 17
    DW_OP_reg18                = 0x62  # Register 18
    DW_OP_reg19                = 0x63  # Register 19
    DW_OP_reg20                = 0x64  # Register 20
    DW_OP_reg21                = 0x65  # Register 21
    DW_OP_reg22                = 0x66  # Register 22
    DW_OP_reg23                = 0x67  # Register 24
    DW_OP_reg24                = 0x68  # Register 24
    DW_OP_reg25                = 0x69  # Register 25
    DW_OP_reg26                = 0x6a  # Register 26
    DW_OP_reg27                = 0x6b  # Register 27
    DW_OP_reg28                = 0x6c  # Register 28
    DW_OP_reg29                = 0x6d  # Register 29
    DW_OP_reg30                = 0x6e  # Register 30
    DW_OP_reg31                = 0x6f  # Register 31
    DW_OP_breg0                = 0x70  # Base register 0
    DW_OP_breg1                = 0x71  # Base register 1
    DW_OP_breg2                = 0x72  # Base register 2
    DW_OP_breg3                = 0x73  # Base register 3
    DW_OP_breg4                = 0x74  # Base register 4
    DW_OP_breg5                = 0x75  # Base register 5
    DW_OP_breg6                = 0x76  # Base register 6
    DW_OP_breg7                = 0x77  # Base register 7
    DW_OP_breg8                = 0x78  # Base register 8
    DW_OP_breg9                = 0x79  # Base register 9
    DW_OP_breg10               = 0x7a  # Base register 10
    DW_OP_breg11               = 0x7b  # Base register 11
    DW_OP_breg12               = 0x7c  # Base register 12
    DW_OP_breg13               = 0x7d  # Base register 13
    DW_OP_breg14               = 0x7e  # Base register 14
    DW_OP_breg15               = 0x7f  # Base register 15
    DW_OP_breg16               = 0x80  # Base register 16
    DW_OP_breg17               = 0x81  # Base register 17
    DW_OP_breg18               = 0x82  # Base register 18
    DW_OP_breg19               = 0x83  # Base register 19
    DW_OP_breg20               = 0x84  # Base register 20
    DW_OP_breg21               = 0x85  # Base register 21
    DW_OP_breg22               = 0x86  # Base register 22
    DW_OP_breg23               = 0x87  # Base register 23
    DW_OP_breg24               = 0x88  # Base register 24
    DW_OP_breg25               = 0x89  # Base register 25
    DW_OP_breg26               = 0x8a  # Base register 26
    DW_OP_breg27               = 0x8b  # Base register 27
    DW_OP_breg28               = 0x8c  # Base register 28
    DW_OP_breg29               = 0x8d  # Base register 29
    DW_OP_breg30               = 0x8e  # Base register 30
    DW_OP_breg31               = 0x8f  # Base register 31
    DW_OP_regx                 = 0x90  # Unsigned LEB128 register
    DW_OP_fbreg                = 0x91  # Signed LEB128 offset
    DW_OP_bregx                = 0x92  # ULEB128 register followed by SLEB128 off
    DW_OP_piece                = 0x93  # ULEB128 size of piece addressed
    DW_OP_deref_size           = 0x94  # 1-byte size of data retrieved
    DW_OP_xderef_size          = 0x95  # 1-byte size of data retrieved
    DW_OP_nop                  = 0x96  #
    DW_OP_push_object_address  = 0x97  #
    DW_OP_call2                = 0x98  #
    DW_OP_call4                = 0x99  #
    DW_OP_call_ref             = 0x9a  #
    DW_OP_form_tls_address     = 0x9b  # TLS offset to address in current thread
    DW_OP_call_frame_cfa       = 0x9c  # CFA as determined by CFI
    DW_OP_bit_piece            = 0x9d  # ULEB128 size and ULEB128 offset in bits
    DW_OP_implicit_value       = 0x9e  # DW_FORM_block follows opcode
    DW_OP_stack_value          = 0x9f  # No operands, special like DW_OP_piece
    #
    DW_OP_implicit_pointer     = 0xa0  #
    DW_OP_addrx                = 0xa1  #
    DW_OP_constx               = 0xa2  #
    DW_OP_entry_value          = 0xa3  #
    DW_OP_const_type           = 0xa4  #
    DW_OP_regval_type          = 0xa5  #
    DW_OP_deref_type           = 0xa6  #
    DW_OP_xderef_type          = 0xa7  #
    DW_OP_convert              = 0xa8  #
    DW_OP_reinterpret          = 0xa9  #
    # GNU extensions
    DW_OP_GNU_push_tls_address = 0xe0  #
    DW_OP_GNU_uninit           = 0xf0  #
    DW_OP_GNU_encoded_addr     = 0xf1  #
    DW_OP_GNU_implicit_pointer = 0xf2  #
    DW_OP_GNU_entry_value      = 0xf3  #
    DW_OP_GNU_const_type       = 0xf4  #
    DW_OP_GNU_regval_type      = 0xf5  #
    DW_OP_GNU_deref_type       = 0xf6  #
    DW_OP_GNU_convert          = 0xf7  #
    DW_OP_GNU_reinterpret      = 0xf9  #
    DW_OP_GNU_parameter_ref    = 0xfa  #
    # GNU Debug Fission extensions
    DW_OP_GNU_addr_index       = 0xfb  #
    DW_OP_GNU_const_index      = 0xfc  #
    DW_OP_GNU_variable_value   = 0xfd  #
    DW_OP_lo_user              = 0xe0  # Implementation-defined range start
    DW_OP_hi_user              = 0xff  # Implementation-defined range end # noqa: F841

    DWARF_ONE_KNOWN_DW_OP = {
        DW_OP_GNU_addr_index       : "GNU_addr_index",
        DW_OP_GNU_const_index      : "GNU_const_index",
        DW_OP_GNU_const_type       : "GNU_const_type",
        DW_OP_GNU_convert          : "GNU_convert",
        DW_OP_GNU_deref_type       : "GNU_deref_type",
        DW_OP_GNU_encoded_addr     : "GNU_encoded_addr",
        DW_OP_GNU_entry_value      : "GNU_entry_value",
        DW_OP_GNU_implicit_pointer : "GNU_implicit_pointer",
        DW_OP_GNU_parameter_ref    : "GNU_parameter_ref",
        DW_OP_GNU_push_tls_address : "GNU_push_tls_address",
        DW_OP_GNU_regval_type      : "GNU_regval_type",
        DW_OP_GNU_reinterpret      : "GNU_reinterpret",
        DW_OP_GNU_uninit           : "GNU_uninit",
        DW_OP_GNU_variable_value   : "GNU_variable_value",
        DW_OP_abs                  : "abs",
        DW_OP_addr                 : "addr",
        DW_OP_addrx                : "addrx",
        DW_OP_and                  : "and",
        DW_OP_bit_piece            : "bit_piece",
        DW_OP_bra                  : "bra",
        DW_OP_breg0                : "breg0",
        DW_OP_breg1                : "breg1",
        DW_OP_breg2                : "breg2",
        DW_OP_breg3                : "breg3",
        DW_OP_breg4                : "breg4",
        DW_OP_breg5                : "breg5",
        DW_OP_breg6                : "breg6",
        DW_OP_breg7                : "breg7",
        DW_OP_breg8                : "breg8",
        DW_OP_breg9                : "breg9",
        DW_OP_breg10               : "breg10",
        DW_OP_breg11               : "breg11",
        DW_OP_breg12               : "breg12",
        DW_OP_breg13               : "breg13",
        DW_OP_breg14               : "breg14",
        DW_OP_breg15               : "breg15",
        DW_OP_breg16               : "breg16",
        DW_OP_breg17               : "breg17",
        DW_OP_breg18               : "breg18",
        DW_OP_breg19               : "breg19",
        DW_OP_breg20               : "breg20",
        DW_OP_breg21               : "breg21",
        DW_OP_breg22               : "breg22",
        DW_OP_breg23               : "breg23",
        DW_OP_breg24               : "breg24",
        DW_OP_breg25               : "breg25",
        DW_OP_breg26               : "breg26",
        DW_OP_breg27               : "breg27",
        DW_OP_breg28               : "breg28",
        DW_OP_breg29               : "breg29",
        DW_OP_breg30               : "breg30",
        DW_OP_breg31               : "breg31",
        DW_OP_bregx                : "bregx",
        DW_OP_call2                : "call2",
        DW_OP_call4                : "call4",
        DW_OP_call_frame_cfa       : "call_frame_cfa",
        DW_OP_call_ref             : "call_ref",
        DW_OP_const1s              : "const1s",
        DW_OP_const1u              : "const1u",
        DW_OP_const2s              : "const2s",
        DW_OP_const2u              : "const2u",
        DW_OP_const4s              : "const4s",
        DW_OP_const4u              : "const4u",
        DW_OP_const8s              : "const8s",
        DW_OP_const8u              : "const8u",
        DW_OP_const_type           : "const_type",
        DW_OP_consts               : "consts",
        DW_OP_constu               : "constu",
        DW_OP_constx               : "constx",
        DW_OP_convert              : "convert",
        DW_OP_deref                : "deref",
        DW_OP_deref_size           : "deref_size",
        DW_OP_deref_type           : "deref_type",
        DW_OP_div                  : "div",
        DW_OP_drop                 : "drop",
        DW_OP_dup                  : "dup",
        DW_OP_entry_value          : "entry_value",
        DW_OP_eq                   : "eq",
        DW_OP_fbreg                : "fbreg",
        DW_OP_form_tls_address     : "form_tls_address",
        DW_OP_ge                   : "ge",
        DW_OP_gt                   : "gt",
        DW_OP_implicit_pointer     : "implicit_pointer",
        DW_OP_implicit_value       : "implicit_value",
        DW_OP_le                   : "le",
        DW_OP_lit0                 : "lit0",
        DW_OP_lit1                 : "lit1",
        DW_OP_lit2                 : "lit2",
        DW_OP_lit3                 : "lit3",
        DW_OP_lit4                 : "lit4",
        DW_OP_lit5                 : "lit5",
        DW_OP_lit6                 : "lit6",
        DW_OP_lit7                 : "lit7",
        DW_OP_lit8                 : "lit8",
        DW_OP_lit9                 : "lit9",
        DW_OP_lit10                : "lit10",
        DW_OP_lit11                : "lit11",
        DW_OP_lit12                : "lit12",
        DW_OP_lit13                : "lit13",
        DW_OP_lit14                : "lit14",
        DW_OP_lit15                : "lit15",
        DW_OP_lit16                : "lit16",
        DW_OP_lit17                : "lit17",
        DW_OP_lit18                : "lit18",
        DW_OP_lit19                : "lit19",
        DW_OP_lit20                : "lit20",
        DW_OP_lit21                : "lit21",
        DW_OP_lit22                : "lit22",
        DW_OP_lit23                : "lit23",
        DW_OP_lit24                : "lit24",
        DW_OP_lit25                : "lit25",
        DW_OP_lit26                : "lit26",
        DW_OP_lit27                : "lit27",
        DW_OP_lit28                : "lit28",
        DW_OP_lit29                : "lit29",
        DW_OP_lit30                : "lit30",
        DW_OP_lit31                : "lit31",
        DW_OP_lt                   : "lt",
        DW_OP_minus                : "minus",
        DW_OP_mod                  : "mod",
        DW_OP_mul                  : "mul",
        DW_OP_ne                   : "ne",
        DW_OP_neg                  : "neg",
        DW_OP_nop                  : "nop",
        DW_OP_not                  : "not",
        DW_OP_or                   : "or",
        DW_OP_over                 : "over",
        DW_OP_pick                 : "pick",
        DW_OP_piece                : "piece",
        DW_OP_plus                 : "plus",
        DW_OP_plus_uconst          : "plus_uconst",
        DW_OP_push_object_address  : "push_object_address",
        DW_OP_reg0                 : "reg0",
        DW_OP_reg1                 : "reg1",
        DW_OP_reg2                 : "reg2",
        DW_OP_reg3                 : "reg3",
        DW_OP_reg4                 : "reg4",
        DW_OP_reg5                 : "reg5",
        DW_OP_reg6                 : "reg6",
        DW_OP_reg7                 : "reg7",
        DW_OP_reg8                 : "reg8",
        DW_OP_reg9                 : "reg9",
        DW_OP_reg10                : "reg10",
        DW_OP_reg11                : "reg11",
        DW_OP_reg12                : "reg12",
        DW_OP_reg13                : "reg13",
        DW_OP_reg14                : "reg14",
        DW_OP_reg15                : "reg15",
        DW_OP_reg16                : "reg16",
        DW_OP_reg17                : "reg17",
        DW_OP_reg18                : "reg18",
        DW_OP_reg19                : "reg19",
        DW_OP_reg20                : "reg20",
        DW_OP_reg21                : "reg21",
        DW_OP_reg22                : "reg22",
        DW_OP_reg23                : "reg23",
        DW_OP_reg24                : "reg24",
        DW_OP_reg25                : "reg25",
        DW_OP_reg26                : "reg26",
        DW_OP_reg27                : "reg27",
        DW_OP_reg28                : "reg28",
        DW_OP_reg29                : "reg29",
        DW_OP_reg30                : "reg30",
        DW_OP_reg31                : "reg31",
        DW_OP_regval_type          : "regval_type",
        DW_OP_regx                 : "regx",
        DW_OP_reinterpret          : "reinterpret",
        DW_OP_rot                  : "rot",
        DW_OP_shl                  : "shl",
        DW_OP_shr                  : "shr",
        DW_OP_shra                 : "shra",
        DW_OP_skip                 : "skip",
        DW_OP_stack_value          : "stack_value",
        DW_OP_swap                 : "swap",
        DW_OP_xderef               : "xderef",
        DW_OP_xderef_size          : "xderef_size",
        DW_OP_xderef_type          : "xderef_type",
        DW_OP_xor                  : "xor",
    }

    def dwarf_locexpr_opcode_string(self, code):
        if code in self.DWARF_ONE_KNOWN_DW_OP:
            return self.DWARF_ONE_KNOWN_DW_OP[code]
        elif code >= self.DW_OP_lo_user:
            return "lo_user+{:#x}".format(code - self.DW_OP_lo_user)
        else:
            return "??? ({:#x})".format(code)

    def parse_ops(self, vers, addrsize, length, data, pos, indent_n=0):
        indent = " " * ((indent_n + 2) * 4)
        entries = []
        ref_size = addrsize if vers < 3 else 0

        if length == 0:
            entries.append([pos, b"", indent + "(empty)", None, ""])
            return entries

        offset = 0
        try:
            while length:
                new_pos, op = self.read_1ubyte(data, pos)
                op_name = self.dwarf_locexpr_opcode_string(op)

                if op in [self.DW_OP_addr]:
                    if addrsize == 4:
                        new_pos, d = self.read_4ubyte(data, new_pos)
                    elif addrsize == 8:
                        new_pos, d = self.read_8ubyte(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_call_ref, self.DW_OP_GNU_variable_value]:
                    if ref_size == 4:
                        new_pos, d = self.read_4ubyte(data, new_pos)
                    else:
                        new_pos, d = self.read_8ubyte(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, ""])
                elif op in [self.DW_OP_deref]:
                    typ = {4: "uint", 8: "ulong"}[addrsize]
                    extra_s = "pop; push *({:s}*)popped_value".format(typ)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, extra_s])
                elif op in [self.DW_OP_xderef]:
                    typ = {4: "uint", 8: "ulong"}[addrsize]
                    extra_s = "pop; pop; push *({:s}*)(popped_value2_as_segment:popped_value1)".format(typ)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, extra_s])
                elif op in [self.DW_OP_deref_size]:
                    new_pos, d = self.read_1ubyte(data, new_pos)
                    typ = {1: "uchar", 2: "ushort", 4: "uint", 8: "ulong"}[d]
                    extra_s = "pop; push *({:s}*)popped_value".format(typ)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_xderef_size]:
                    new_pos, d = self.read_1ubyte(data, new_pos)
                    typ = {1: "uchar", 2: "ushort", 4: "uint", 8: "ulong"}[d]
                    extra_s = "pop; pop; push *({:s}*)(popped_value2_as_segment:popped_value1)".forma(typ)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_pick]:
                    new_pos, d = self.read_1ubyte(data, new_pos)
                    extra_s = "push stack[{:d}]".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_const1u]:
                    new_pos, d = self.read_1ubyte(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_const2u]:
                    new_pos, d = self.read_2ubyte(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_const4u]:
                    new_pos, d = self.read_4ubyte(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_const8u]:
                    new_pos, d = self.read_8ubyte(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_const1s]:
                    new_pos, d = self.read_1sbyte(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_const2u]:
                    new_pos, d = self.read_2sbyte(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_const4s]:
                    new_pos, d = self.read_4sbyte(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_const8s]:
                    new_pos, d = self.read_8sbyte(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_piece, self.DW_OP_regx, self.DW_OP_plus_uconst]:
                    new_pos, d = self.get_uleb128(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, ""])
                elif op in [self.DW_OP_constu]:
                    new_pos, d = self.get_uleb128(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_consts]:
                    new_pos, d = self.get_sleb128(data, new_pos)
                    extra_s = "push {:#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_addrx, self.DW_OP_GNU_addr_index, self.DW_OP_constx, self.DW_OP_GNU_const_index]:
                    new_pos, d = self.get_uleb128(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} [{:#x}]".format(offset, op_name, d), None, ""])
                elif op in [self.DW_OP_bit_piece]:
                    new_pos, d1 = self.get_uleb128(data, new_pos)
                    new_pos, d2 = self.get_uleb128(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x},{:#x}".format(offset, op_name, d1, d2), None, ""])
                elif op in [self.DW_OP_lit0, self.DW_OP_lit1, self.DW_OP_lit2, self.DW_OP_lit3, self.DW_OP_lit4,
                            self.DW_OP_lit5, self.DW_OP_lit6, self.DW_OP_lit7, self.DW_OP_lit8, self.DW_OP_lit9,
                            self.DW_OP_lit10, self.DW_OP_lit11, self.DW_OP_lit12, self.DW_OP_lit13, self.DW_OP_lit14,
                            self.DW_OP_lit15, self.DW_OP_lit16, self.DW_OP_lit17, self.DW_OP_lit18, self.DW_OP_lit19,
                            self.DW_OP_lit20, self.DW_OP_lit21, self.DW_OP_lit22, self.DW_OP_lit23, self.DW_OP_lit24,
                            self.DW_OP_lit25, self.DW_OP_lit26, self.DW_OP_lit27, self.DW_OP_lit28, self.DW_OP_lit29,
                            self.DW_OP_lit30, self.DW_OP_lit31]:
                    extra_s = "push {:#x}".format(op - 0x30)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, extra_s])
                elif op in [self.DW_OP_reg0, self.DW_OP_reg1, self.DW_OP_reg2, self.DW_OP_reg3, self.DW_OP_reg4,
                            self.DW_OP_reg5, self.DW_OP_reg6, self.DW_OP_reg7, self.DW_OP_reg8, self.DW_OP_reg9,
                            self.DW_OP_reg10, self.DW_OP_reg11, self.DW_OP_reg12, self.DW_OP_reg13, self.DW_OP_reg14,
                            self.DW_OP_reg15, self.DW_OP_reg16, self.DW_OP_reg17, self.DW_OP_reg18, self.DW_OP_reg19,
                            self.DW_OP_reg20, self.DW_OP_reg21, self.DW_OP_reg22, self.DW_OP_reg23, self.DW_OP_reg24,
                            self.DW_OP_reg25, self.DW_OP_reg26, self.DW_OP_reg27, self.DW_OP_reg28, self.DW_OP_reg29,
                            self.DW_OP_reg30, self.DW_OP_reg31]:
                    regname = self.get_register_name(op - 0x50)
                    extra_s = "push {:s}".format(regname)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, extra_s])
                elif op in [self.DW_OP_breg0, self.DW_OP_breg1, self.DW_OP_breg2, self.DW_OP_breg3, self.DW_OP_breg4,
                            self.DW_OP_breg5, self.DW_OP_breg6, self.DW_OP_breg7, self.DW_OP_breg8, self.DW_OP_breg9,
                            self.DW_OP_breg10, self.DW_OP_breg11, self.DW_OP_breg12, self.DW_OP_breg13, self.DW_OP_breg14,
                            self.DW_OP_breg15, self.DW_OP_breg16, self.DW_OP_breg17, self.DW_OP_breg18, self.DW_OP_breg19,
                            self.DW_OP_breg20, self.DW_OP_breg21, self.DW_OP_breg22, self.DW_OP_breg23, self.DW_OP_breg24,
                            self.DW_OP_breg25, self.DW_OP_breg26, self.DW_OP_breg27, self.DW_OP_breg28, self.DW_OP_breg29,
                            self.DW_OP_breg30, self.DW_OP_breg31]:
                    new_pos, d = self.get_sleb128(data, new_pos)
                    regname = self.get_register_name(op - 0x70)
                    extra_s = "push {:s}{:+#x}".format(regname, d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_fbreg]:
                    new_pos, d = self.get_sleb128(data, new_pos)
                    regname = "push frame_base{:*#x}".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x}".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_bregx]:
                    new_pos, d1 = self.get_uleb128(data, new_pos)
                    new_pos, d2 = self.get_sleb128(data, new_pos)
                    regname = self.get_register_name(d1)
                    extra_s = "push {:s}{:+#x}".format(regname, d2)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x},{:#x}".format(offset, op_name, d1, d2), None, extra_s])
                elif op in [self.DW_OP_call2]:
                    new_pos, d = self.read_2ubyte(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} [{:#x}]".format(offset, op_name, d), None, ""])
                elif op in [self.DW_OP_call4]:
                    new_pos, d = self.read_4ubyte(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} [{:#x}]".format(offset, op_name, d), None, ""])
                elif op in [self.DW_OP_bra]:
                    new_pos, d = self.read_2sbyte(data, new_pos)
                    d += offset + 3
                    extra_s = "pop; jmp to [{:#x}] if popped_value != 0".format(d)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} [{:#x}]".format(offset, op_name, d), None, extra_s])
                elif op in [self.DW_OP_skip]:
                    new_pos, d = self.read_2sbyte(data, new_pos)
                    d += offset + 3
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} [{:#x}]".format(offset, op_name, d), None, ""])
                elif op in [self.DW_OP_implicit_value]:
                    new_pos, d = self.get_uleb128(data, new_pos)
                    block_s = " ".join(["{:02x}".format(x) for x in data[new_pos:new_pos + d]])
                    new_pos += d
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:s}".format(offset, op_name, block_s), None, ""])
                elif op in [self.DW_OP_implicit_pointer, self.DW_OP_GNU_implicit_pointer]:
                    if ref_size == 4:
                        new_pos, d1 = self.read_4ubyte(data, new_pos)
                    elif ref_size == 8:
                        new_pos, d1 = self.read_8ubyte(data, new_pos)
                    new_pos, d2 = self.get_sleb128(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} [{:#x}] {:+#x}".format(offset, op_name, d1, d2), None, ""])
                elif op in [self.DW_OP_entry_value, self.DW_OP_GNU_entry_value]:
                    new_pos, d = self.get_uleb128(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, ""])
                    entries += self.parse_ops(vers, addrsize, d, data, new_pos, indent=indent + 1)
                    new_pos += d
                elif op in [self.DW_OP_const_type, self.DW_OP_GNU_const_type]:
                    new_pos, d1 = self.get_uleb128(data, new_pos)
                    new_pos, d2 = self.read_1ubyte(data, new_pos)
                    block_s = " ".join(["{:02x}".format(x) for x in data[new_pos:new_pos + d2]])
                    new_pos += d2
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} [{:#x}] {:s}".format(offset, op_name, d1, block_s), None, ""])
                elif op in [self.DW_OP_regval_type, self.DW_OP_GNU_regval_type]:
                    new_pos, d1 = self.get_uleb128(data, new_pos)
                    new_pos, d2 = self.get_uleb128(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x} [{:#x}]".format(offset, op_name, d1, d2), None, ""])
                elif op in [self.DW_OP_deref_type, self.DW_OP_GNU_deref_type]:
                    new_pos, d1 = self.read_1ubyte(data, new_pos)
                    new_pos, d2 = self.get_uleb128(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x} [{:#x}]".format(offset, op_name, d1, d2), None, ""])
                elif op in [self.DW_OP_xderef_type]:
                    new_pos, d1 = self.read_1ubyte(data, new_pos)
                    new_pos, d2 = self.get_uleb128(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} {:#x} [{:#x}]".format(offset, op_name, d1, d2), None, ""])
                elif op in [self.DW_OP_convert, self.DW_OP_GNU_convert, self.DW_OP_reinterpret, self.DW_OP_GNU_reinterpret]:
                    new_pos, d = self.get_uleb128(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} [{:#x}]".format(offset, op_name, d), None, ""])
                elif op in [self.DW_OP_GNU_parameter_ref]:
                    new_pos, d = self.read_4ubyte(data, new_pos)
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s} [{:#x}]".format(offset, op_name, d), None, ""])
                elif op in [self.DW_OP_drop]:
                    extra_s = "pop"
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, extra_s])
                elif op in [self.DW_OP_dup]:
                    extra_s = "push stack[0]"
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, extra_s])
                elif op in [self.DW_OP_over]:
                    extra_s = "push stack[1]"
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, extra_s])
                elif op in [self.DW_OP_swap]:
                    extra_s = "stack[0],stack[1] = stack[1],stack[0]"
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, extra_s])
                elif op in [self.DW_OP_rot]:
                    extra_s = "stack[0],stack[1],stack[2] = stack[1],stack[2],stack[0]"
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, extra_s])
                else:
                    entries.append([pos, data[pos:new_pos], indent + "[{:#04x}] {:s}".format(offset, op_name), None, ""])
                length -= new_pos - pos
                offset += new_pos - pos
                pos = new_pos
        except Exception:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            entries.append(["Parse Error\n{}".format(exc_value)])
        return entries

    def parse_gcc_except_table(self, gcc_except_table, eh_frame_entries):
        def get_lsda_info(eh_frame_entries):
            dic = {}
            is_fde = False
            for entry in eh_frame_entries:
                if len(entry) != 5:
                    continue
                pos, raw_data, name, value, extra = entry
                if name == "cie_pointer":
                    is_fde = True
                    continue
                if name == "cie_id":
                    is_fde = False
                    continue
                if is_fde:
                    if name == "pc_begin":
                        pc_begin = value
                        continue
                    if name != "augmentation_data(L)":
                        continue
                    dic[value - load_base] = pc_begin + load_base
            return dic

        section_base = gcc_except_table.offset
        data = gcc_except_table.data
        shdr = self.elf.get_shdr(".gcc_except_table")
        load_base = self.elf.get_phdr(Elf.Phdr.PT_LOAD).p_vaddr
        ptr_size = 4 if self.elf.e_class == Elf.ELF_32_BITS else 8
        lsda_pos_info = get_lsda_info(eh_frame_entries)

        entries = []
        pos = 0
        lsda_table_cnt = 0

        try:
            lsda_pos_padding = 0
            while data[pos:]:
                # search LSDA start address
                if (section_base + pos) not in lsda_pos_info:
                    lsda_pos_padding += 1
                    pos += 1
                    continue

                # Found
                if lsda_pos_padding:
                    entries.append([pos - lsda_pos_padding, "Padding", ""])
                    entries.append([pos - lsda_pos_padding, data[pos - lsda_pos_padding:pos], "padding", "", ""])
                    lsda_pos_padding = 0

                entries.append([pos, "LSDA Table[{:4d}]".format(lsda_table_cnt), ""])
                lpstart = lsda_pos_info[section_base + pos]

                # parse lpstart_encoding
                new_pos, lpstart_encoding = self.read_1ubyte(data, pos)
                encoding_str = self.get_encoding_str(lpstart_encoding)
                entries.append([pos, data[pos:new_pos], "landing_pad_start_encoding", lpstart_encoding, "encoding: {:s}".format(encoding_str)])
                pos = new_pos

                # parse lpstart
                if lpstart_encoding != self.DW_EH_PE_omit:
                    new_pos, lpstart = self.read_encoded(lpstart_encoding, data, pos) # overwrite lpstart
                    entries.append([pos, data[pos:new_pos], "landing_pad_start", lpstart, ""])
                    pos = new_pos

                # parse ttype_encoding
                new_pos, ttype_encoding = self.read_1ubyte(data, pos)
                encoding_str = self.get_encoding_str(ttype_encoding)
                entries.append([pos, data[pos:new_pos], "ttype_encoding", ttype_encoding, "encoding: {:s}".format(encoding_str)])
                pos = new_pos

                # parse ttype_base_offset
                ttype_base = None
                if ttype_encoding != self.DW_EH_PE_omit:
                    new_pos, ttype_base_offset = self.get_uleb128(data, pos)
                    ttype_base = new_pos + ttype_base_offset
                    entries.append([pos, data[pos:new_pos], "ttype_base_offset", ttype_base_offset, "ttype_base: {:#x}".format(ttype_base)])
                    pos = new_pos

                # parse call_site_encoding
                new_pos, call_site_encoding = self.read_1ubyte(data, pos)
                encoding_str = self.get_encoding_str(call_site_encoding)
                entries.append([pos, data[pos:new_pos], "call_site_encoding", call_site_encoding, "encoding: {:s}".format(encoding_str)])
                pos = new_pos

                # parse call_site_table_len
                new_pos, call_site_table_len = self.get_uleb128(data, pos)
                entries.append([pos, data[pos:new_pos], "call_site_table_len", call_site_table_len, ""])
                pos = new_pos

                # parse call_site_table
                action_table_pos = pos + call_site_table_len
                table_cnt = 0
                max_action = 0
                while pos < action_table_pos:
                    entries.append([pos, "Call site table[{:4d}]".format(table_cnt), ""])

                    new_pos, call_site_start = self.read_encoded(call_site_encoding, data, pos)
                    if self.elf.is_pie():
                        extra_s = "try-start vma: $codebase+{:#x}".format(lpstart + call_site_start)
                    else:
                        extra_s = "try-start vma: {:#x}".format(lpstart + call_site_start)
                    entries.append([pos, data[pos:new_pos], "call_site_start", call_site_start, extra_s])
                    pos = new_pos

                    new_pos, call_site_length = self.read_encoded(call_site_encoding, data, pos)
                    if self.elf.is_pie():
                        extra_s = "try-end vma: $codebase+{:#x}".format(lpstart + call_site_start + call_site_length)
                    else:
                        extra_s = "try-end vma: {:#x}".format(lpstart + call_site_start + call_site_length)
                    entries.append([pos, data[pos:new_pos], "call_site_length", call_site_length, extra_s])
                    pos = new_pos

                    new_pos, call_site_lpad = self.read_encoded(call_site_encoding, data, pos)
                    if call_site_lpad == 0:
                        extra_s = ""
                    elif self.elf.is_pie():
                        extra_s = "catch vma: $codebase+{:#x}".format(lpstart + call_site_lpad)
                    else:
                        extra_s = "catch vma: {:#x}".format(lpstart + call_site_lpad)
                    entries.append([pos, data[pos:new_pos], "landing_pad", call_site_lpad, extra_s])
                    pos = new_pos

                    new_pos, action = self.get_uleb128(data, pos)
                    max_action = max(action, max_action)
                    if action == 0:
                        extra_s = "no action"
                    else:
                        extra_s = "action: {:#x}".format(action_table_pos + action - 1)
                    entries.append([pos, data[pos:new_pos], "action", action, extra_s])
                    pos = new_pos

                    table_cnt += 1

                # parse action_table
                max_ar_filter = 0
                table_cnt = 0
                if max_action:
                    action_table_end_pos = action_table_pos + max_action + 1
                    while pos < action_table_end_pos:
                        entries.append([pos, "Action table[{:4d}]".format(table_cnt), ""])

                        new_pos, ar_filter = self.get_sleb128(data, pos)
                        if ar_filter == 0:
                            extra_s = "cleanup"
                        else:
                            enc_size = self.encoded_ptr_size(ttype_encoding, ptr_size)
                            extra_s = "catch typeinfo: {:#x}".format(ttype_base - ar_filter * enc_size)
                        entries.append([pos, data[pos:new_pos], "action_record_filter", ar_filter, extra_s])
                        max_ar_filter = max(ar_filter, max_ar_filter)
                        pos = new_pos

                        new_pos, ar_disp = self.get_sleb128(data, pos)
                        if ar_disp & 1:
                            extra_s = "-> Action Table[{:4d}]".format(table_cnt + (ar_disp + 1) // 2)
                        elif ar_disp:
                            extra_s = "-> ???"
                        else:
                            extra_s = "list end"
                        entries.append([pos, data[pos:new_pos], "action_record_next", ar_disp, extra_s])
                        pos = new_pos

                        table_cnt += 1

                # parse ttype_table
                if max_ar_filter > 0 and ttype_base is not None:
                    enc_size = self.encoded_ptr_size(ttype_encoding, ptr_size)
                    new_pos = ttype_base - max_ar_filter * enc_size
                    if pos != new_pos:
                        entries.append([pos, "Padding", ""])
                        entries.append([pos, data[pos:new_pos], "padding", "", ""])
                        pos = new_pos
                    current_ar_filter = max_ar_filter
                    while pos < ttype_base:
                        entries.append([pos, "TType table[{:4d}]".format(current_ar_filter), ""])
                        new_pos, ttype = self.read_encoded(ttype_encoding, data, pos)
                        if (ttype_encoding & 0x70) == self.DW_EH_PE_pcrel:
                            ttype_pointer = shdr.sh_offset + pos + ttype
                            if ttype:
                                if self.elf.is_pie():
                                    extra_s = "TType pointer vma: $codebase+{:#x}".format(load_base + ttype_pointer)
                                else:
                                    extra_s = "TType pointer vma: {:#x}".format(load_base + ttype_pointer)
                            else:
                                extra_s = ""
                            entries.append([pos, data[pos:new_pos], "ttype", ttype, extra_s])
                        else:
                            entries.append([pos, data[pos:new_pos], "ttype", ttype, "TType pointer"])
                        pos = new_pos
                        current_ar_filter -= 1
                if ttype_base is not None:
                    entries.append([ttype_base, "TType table base (Stored upwards)", ""])

                # next LSDA
                if ttype_base is None:
                    pass
                else:
                    pos = ttype_base
                lsda_table_cnt += 1
        except Exception:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            entries.append(["Parse Error\n{}".format(exc_value)])
        return entries

    def read_section(self, section_name):
        shdr = self.elf.get_shdr(section_name)
        if shdr is None:
            err("Not found {} section".format(section_name))
            return None

        f = open(self.elf.filename, "rb")
        f.seek(shdr.sh_offset)
        data = f.read(shdr.sh_size)
        f.close()
        info("Found {} section".format(section_name))

        dic = {"name": section_name, "offset": shdr.sh_offset, "data": data}
        Section = collections.namedtuple("Section", dic.keys())
        return Section(*dic.values())

    @parse_args
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        local_filepath = None
        remote_filepath = None
        tmp_filepath = None
        self.hexdump = args.hexdump

        if args.remote:
            if not is_remote_debug():
                err("-r option is allowed only remote debug.")
                return

            if args.file:
                remote_filepath = args.file # if specified, assume it is remote
            elif gdb.current_progspace().filename:
                f = gdb.current_progspace().filename
                if f.startswith("target:"): # gdbserver
                    f = f[7:]
                remote_filepath = f
            elif Pid.get_pid(remote=True):
                remote_filepath = "/proc/{:d}/exe".format(Pid.get_pid(remote=True))
            else:
                err("File name could not be determined.")
                return

            data = Path.read_remote_file(remote_filepath, as_byte=True) # qemu-user is failed here, it is ok
            if not data:
                err("Failed to read remote filepath")
                return
            tmp_fd, tmp_filepath = tempfile.mkstemp(dir=GEF_TEMP_DIR, suffix=".elf", prefix="dwarf-exception-handler-")
            os.fdopen(tmp_fd, "wb").write(data)
            local_filepath = tmp_filepath
            del data

        elif args.file:
            local_filepath = args.file

        elif args.file is None:
            if is_qemu_system():
                err("Argument-less calls are unsupported under qemu-system.")
                return
            local_filepath = Path.get_filepath()

        if local_filepath is None:
            err("File name could not be determined.")
            return

        self.elf = Elf.get_elf(local_filepath)
        if self.elf is None or not self.elf.is_valid():
            err("Failed to parse elf.")
            if tmp_filepath and os.path.exists(tmp_filepath):
                os.unlink(tmp_filepath)
            return

        # read section
        eh_frame_hdr = self.read_section(".eh_frame_hdr")
        if eh_frame_hdr is None:
            if tmp_filepath and os.path.exists(tmp_filepath):
                os.unlink(tmp_filepath)
            return
        eh_frame = self.read_section(".eh_frame")
        if eh_frame is None:
            if tmp_filepath and os.path.exists(tmp_filepath):
                os.unlink(tmp_filepath)
            return
        gcc_except_table = self.read_section(".gcc_except_table")
        if gcc_except_table is None:
            if tmp_filepath and os.path.exists(tmp_filepath):
                os.unlink(tmp_filepath)
            return

        # parse section
        out = []
        eh_frame_hdr_entries = self.parse_eh_frame_hdr(eh_frame_hdr)
        out += self.format_entry(eh_frame_hdr, eh_frame_hdr_entries)
        eh_frame_entries = self.parse_eh_frame(eh_frame)
        out += self.format_entry(eh_frame, eh_frame_entries)
        gcc_except_table_entries = self.parse_gcc_except_table(gcc_except_table, eh_frame_entries)
        out += self.format_entry(gcc_except_table, gcc_except_table_entries)

        # print
        gef_print("\n".join(out), less=not args.no_pager)

        if tmp_filepath and os.path.exists(tmp_filepath):
            os.unlink(tmp_filepath)
        return


@register_command
class MainBreakCommand(GenericCommand):
    """Set a breakpoint at the beginning of main with or without symbols, then continue."""
    _cmdline_ = "main-break"
    _category_ = "01-b. Debugging Support - Breakpoint"

    parser = argparse.ArgumentParser(prog=_cmdline_, add_help=False)
    _syntax_ = parser.format_help()

    def get_libc_start_main(self):
        try:
            return AddressUtil.parse_address("__libc_start_main")
        except gdb.error:
            pass

        ret = gdb.execute("got --no-pager --quiet __libc_start_main", to_string=True)
        ret = ret.strip()
        if not ret:
            err("Failed to resolve __libc_start_main")
            return None
        elem = Color.remove_color(ret).splitlines()[0].split()
        if elem[-1].endswith(">"):
            return int(elem[-2], 16)
        else:
            return int(elem[-1], 16)

    def search_main(self):
        libc_start_main = self.get_libc_start_main()
        if libc_start_main is None:
            return None

        if libc_start_main == 0:
            elf = Elf.get_elf()
            entry = elf.e_entry
            if elf.is_pie():
                codebase = ProcessMap.get_section_base_address(Path.get_filepath(append_proc_root_prefix=False))
                if codebase is None:
                    codebase = ProcessMap.get_section_base_address(Path.get_filepath_from_info_proc())
                if codebase is None:
                    return None
                entry += codebase
            EntryBreakBreakpoint("*{:#x}".format(entry))
            ContextCommand.hide_context()
            gdb.execute("c") # use c wrapper
            ContextCommand.unhide_context()
            libc_start_main = self.get_libc_start_main()

        if libc_start_main == 0:
            # something is wrong
            return None

        EntryBreakBreakpoint("*{:#x}".format(libc_start_main))
        ContextCommand.hide_context()
        gdb.execute("c") # use c wrapper
        ContextCommand.unhide_context()

        # get first arg when break at __libc_start_main
        _, val = current_arch.get_ith_parameter(0)
        return val

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        try:
            main_address = AddressUtil.parse_address("main")
        except gdb.error:
            main_address = self.search_main()

        if main_address is None:
            err("Failed to set a breakpoint to main.")
            return

        EntryBreakBreakpoint("*{:#x}".format(main_address))
        ContextCommand.hide_context()
        try:
            gdb.execute("c") # use c wrapper
        except gdb.error as e:
            err(str(e))
            ContextCommand.unhide_context()
            return
        ContextCommand.unhide_context()
        gdb.execute("context")
        return


class EntryBreakBreakpoint(gdb.Breakpoint):
    """Breakpoint used internally to stop execution at the most convenient entry point."""
    def __init__(self, location):
        super().__init__(location, gdb.BP_BREAKPOINT, internal=True, temporary=True)
        self.silent = True
        return

    def stop(self):
        EventHandler.__gef_check_disabled_bp__ = True
        self.enabled = False

        Cache.reset_gef_caches()
        return True


@register_command
class EntryPointBreakCommand(GenericCommand):
    """Try to find best entry point and set a temporary breakpoint on it."""
    _cmdline_ = "entry-break"
    _category_ = "01-b. Debugging Support - Breakpoint"
    _aliases_ = ["start"]

    parser = argparse.ArgumentParser(prog=_cmdline_, add_help=False)
    _syntax_ = parser.format_help()

    def __init__(self, *args, **kwargs):
        super().__init__(complete=gdb.COMPLETE_FILENAME)
        self.add_setting(
            "entrypoint_symbols",
            " ".join([
                "main", # glibc
                "__libc_start_main", # glibc
                "__uClibc_main", # uClibc
                "_start", # glibc
                "__start", # used by MIPS
                "'main.main'", # golang
                "'start._start'", # zig
            ]),
            "Possible symbols for entry points",
        )
        return

    # Need not @parse_args because argparse can't stop interpreting argument for start.
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, argv):
        if is_alive():
            if is_remote_debug():
                err("Unsupported gdb mode")
                return
            gdb.execute("kill", to_string=True)

        fpath = Path.get_filepath()
        if fpath is None:
            warn("No executable to debug, use `file` to load a binary")
            return

        if not os.access(fpath, os.X_OK):
            warn("The file '{}' is not executable.".format(fpath))
            return

        # use symbol if loaded
        entrypoints = Config.get_gef_setting("entry_break.entrypoint_symbols").split()
        for sym in entrypoints:
            try:
                value = AddressUtil.parse_address(sym)
            except gdb.error:
                continue

            # symbol found
            info("Breaking at {:#x} ({:s})".format(value, sym))
            EntryBreakBreakpoint(sym)
            gdb.execute("run {}".format(" ".join(argv)))
            return

        # no symbols. use elf entry point
        # non-PIE
        if not Elf.get_elf(fpath).is_pie():
            entry = Elf.get_elf().e_entry
            info("Breaking at entry-point: {:#x}".format(entry))
            EntryBreakBreakpoint("*{:#x}".format(entry))
            gdb.execute("run {}".format(" ".join(argv)))
            return

        # PIE
        warn("PIC binary detected, retrieving text base address")
        # Some ELF does not use ld. (e.g.: ELF built by zig)
        # So use gef_on_new_hook (use gdb.events.new_objfile internally),
        # instead of `set stop-on-solib-events 1` because shared object are never loaded.
        # At least gdb 10.1 (Ubuntu 18.04) supports gdb.events.new_objfile.
        ContextCommand.hide_context()
        EventHooking.gef_on_new_hook(EntryPointBreakCommand.stop_callback)
        gdb.execute("run {}".format(" ".join(argv)))
        return

    @staticmethod
    def stop_callback(_):
        # unhook
        EventHooking.gef_on_new_unhook(EntryPointBreakCommand.stop_callback)
        ContextCommand.unhide_context()

        # get section
        fpath = Path.get_filepath()
        executable_section = ProcessMap.process_lookup_path(fpath, perm_mask=Permission.EXECUTE)

        if executable_section.page_start <= current_arch.pc < executable_section.page_end:
            # already stopped around entry point.
            # However, it automatically resumes execution, so we need a breakpoint.
            next_insn = get_insn_next(current_arch.pc)
            info("Breaking at: {:#x}".format(next_insn.address))
            EntryBreakBreakpoint("*{:#x}".format(next_insn.address))
        else:
            # stopped in ld, so continue to entry-point.
            base_address = ProcessMap.process_lookup_path(fpath).page_start
            entry_address = base_address + Elf.get_elf().e_entry
            info("Breaking at entry-point: {:#x}".format(entry_address))
            EntryBreakBreakpoint("*{:#x}".format(entry_address))

        # automatically continue
        return


class NamedBreakpoint(gdb.Breakpoint):
    """Breakpoint which shows a specified name."""
    def __init__(self, location, name):
        super().__init__(location, gdb.BP_BREAKPOINT, internal=False, temporary=False)
        self.name = name
        self.loc = location

        return

    def stop(self):
        Cache.reset_gef_caches()
        msg = "Hit breakpoint {} ({})".format(self.loc, Color.colorify(self.name, "bold red"))
        ContextCommand.push_context_message("info", msg)
        return True


@register_command
class NamedBreakCommand(GenericCommand):
    """Set a breakpoint and assigns a name to it, which will be shown if hit."""
    _cmdline_ = "named-break"
    _category_ = "01-b. Debugging Support - Breakpoint"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("name", metavar="NAME", help="the name to assign.")
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the address to set breakpoint. (default: current_arch.pc)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} main 0x4008a9".format(_cmdline_)

    @parse_args
    def do_invoke(self, args):
        if args.location is not None:
            location = "*{:#x}".format(args.location)
        else:
            location = "*{:#x}".format(current_arch.pc)
        NamedBreakpoint(location, args.name)
        return


class CommandBreakpoint(gdb.Breakpoint):
    """Breakpoint which executes user defined command silently and continue."""
    def __init__(self, loc, cmd):
        super().__init__("*{:#x}".format(loc), gdb.BP_BREAKPOINT, internal=False, temporary=False)
        self.loc = loc
        self.cmd = cmd
        return

    def stop(self):
        Cache.reset_gef_caches()
        gdb.execute(self.cmd)
        return False


@register_command
class CommandBreakCommand(GenericCommand):
    """Set a breakpoint which executes user defined command silently and continue, if hit."""
    _cmdline_ = "command-break"
    _category_ = "01-b. Debugging Support - Breakpoint"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the address to set breakpoint. (default: current_arch.pc)")
    parser.add_argument("command", metavar="COMMAND", type=str, help="the command executed if breakpoint is hit.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} 0x55555555aab9 "hexdump -n $sp+0x120"'.format(_cmdline_)

    @parse_args
    def do_invoke(self, args):
        location = args.location
        if location is None:
            location = current_arch.pc
        CommandBreakpoint(location, args.command)
        return


class TakenOrNotBreakpoint(gdb.Breakpoint):
    """Breakpoint which only branch is taken or not."""
    def __init__(self, loc, taken, is_hwbp):
        if is_hwbp:
            bp_type = gdb.BP_HARDWARE_BREAKPOINT
        else:
            bp_type = gdb.BP_BREAKPOINT
        super().__init__("*{:#x}".format(loc), bp_type, internal=False)
        self.loc = loc
        self.taken = taken
        return

    def stop(self):
        Cache.reset_gef_caches()
        insn = get_insn()

        if not current_arch.is_conditional_branch(insn):
            return False # continue

        taken, _ = current_arch.is_branch_taken(insn)
        if self.taken:
            return taken
        else:
            return not taken


@register_command
class BreakIfTakenCommand(GenericCommand):
    """Set a breakpoint which breaks if branch is taken."""
    _cmdline_ = "break-if-taken"
    _category_ = "01-b. Debugging Support - Breakpoint"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the address to set breakpoint.")
    parser.add_argument("--hw", action="store_true", help="use hardware breakpoint.")
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        TakenOrNotBreakpoint(args.location, True, args.hw)
        return


@register_command
class BreakIfNotTakenCommand(GenericCommand):
    """Set a breakpoint which breaks if branch is not taken."""
    _cmdline_ = "break-if-not-taken"
    _category_ = "01-b. Debugging Support - Breakpoint"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the address to set breakpoint.")
    parser.add_argument("--hw", action="store_true", help="use hardware breakpoint.")
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        TakenOrNotBreakpoint(args.location, False, args.hw)
        return


@register_command
class ContextCommand(GenericCommand):
    """Display various information every time GDB hits a breakpoint."""
    _cmdline_ = "context"
    _category_ = "01-a. Debugging Support - Context"
    _aliases_ = ["ctx"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("commands", nargs="*", default=[],
                        choices=[[], "legend", "regs", "stack", "code", "args", "memory",
                                "source", "trace", "threads", "extra", "on", "off"],
                        metavar="{legend,regs,stack,code,args,memory,source,trace,threads,extra}|{on,off}",
                        help="specifies which context to display. "
                             "The on/off are syntax sugars of `gef config context.enable True/False`.")
    _syntax_ = parser.format_help()

    old_registers = {}
    context_hidden = False
    context_comments = {}
    context_messages = []
    context_extra_commands = []

    @staticmethod
    def hide_context():
        ContextCommand.context_hidden = True
        return

    @staticmethod
    def unhide_context():
        ContextCommand.context_hidden = False
        return

    @staticmethod
    def push_context_message(level, message):
        """Push the message to be displayed the next time the context is invoked."""
        if level not in ("error", "warn", "ok", "info"):
            err("Invalid level '{}', discarding message".format(level))
            return
        ContextCommand.context_messages.append((level, message))
        return

    def __init__(self):
        super().__init__()
        self.add_setting("enable", True, "Enable/disable printing the context when breaking")
        self.add_setting("show_source_code_variable_values", True, "Show extra PC context info in the source code")
        self.add_setting("show_stack_raw", False, "Show the stack pane as raw hexdump (no dereference)")
        self.add_setting("show_registers_raw", False, "Show the registers pane with raw values (no dereference)")
        self.add_setting("show_opcodes_size", 8, "Number of bytes of opcodes to display next to the disassembly")
        self.add_setting("peek_calls", True, "Peek into calls")
        self.add_setting("peek_ret", True, "Peek at return address")
        self.add_setting("nb_lines_stack", 8, "Number of line in the stack pane")
        self.add_setting("nb_guessed_arguments", 6, "Number to display when guessing functions arguments")
        self.add_setting("nb_lines_backtrace", 10, "Number of line in the backtrace pane")
        self.add_setting("nb_lines_backtrace_before", 2, "Number of line in the backtrace pane before selected frame")
        self.add_setting("nb_lines_threads", -1, "Number of line in the threads pane")
        self.add_setting("nb_lines_code", 6, "Number of instruction after $pc")
        self.add_setting("nb_lines_code_prev", 3, "Number of instruction before $pc")
        self.add_setting("nb_max_string_length", 0x40, "Number of bytes of strings to show")
        self.add_setting("ignore_registers", "", "Space-separated list of registers not to display (e.g. '$cs $ds $gs')")
        self.add_setting("clear_screen", True, "Clear the screen before printing the context")
        default_legend = "legend regs stack code args source memory threads trace extra"
        self.add_setting("layout", default_legend, "Change the order/presence of the context sections")
        self.add_setting("smart_cpp_function_name", False, "Print cpp function name without args if demangled")
        self.add_setting("use_native_x_command", False, "Use x/16i instead of Disasm.gef_disassemble")
        self.add_setting("use_capstone", False, "Use capstone as disassembler in the code pane (instead of GDB)")
        self.add_setting("enable_auto_switch_for_i8086", True, "Enable auto architecture switching for i8086 <-> x86-32.")

        self.layout_mapping = {
            "legend" : self.show_legend,
            "regs"   : self.context_regs,
            "stack"  : self.context_stack,
            "code"   : self.context_code,
            "args"   : self.context_args,
            "memory" : self.context_memory,
            "source" : self.context_source,
            "trace"  : self.context_trace,
            "threads": self.context_threads,
            "extra"  : self.context_additional_information,
        }
        return

    def post_load(self):
        EventHooking.gef_on_continue_hook(self.update_registers)
        EventHooking.gef_on_continue_hook(self.empty_extra_messages)
        self.previous_extra_regs = {}
        return

    def show_legend(self):
        # use cache
        if Cache.cached_context_legend is not None:
            if Cache.cached_context_legend:
                gef_print(Cache.cached_context_legend)
            return

        # slow path
        if is_qemu_system() or is_kgdb() or is_vmware():
            Cache.cached_context_legend = False
            return

        if Config.get_gef_setting("gef.disable_color") is True:
            Cache.cached_context_legend = False
            return

        legend = "[ Legend: {} | {} | {} | {} | {} | {} | {} | {} | {} ]".format(
            Color.colorify("Modified register", Config.get_gef_setting("theme.registers_value_changed")),
            Color.colorify("Code", Config.get_gef_setting("theme.address_code")),
            Color.colorify("Heap", Config.get_gef_setting("theme.address_heap")),
            Color.colorify("Stack", Config.get_gef_setting("theme.address_stack")),
            Color.colorify("Writable", Config.get_gef_setting("theme.address_writable")),
            Color.colorify("ReadOnly", Config.get_gef_setting("theme.address_readonly")),
            Color.colorify("None", Config.get_gef_setting("theme.address_valid_but_none")),
            Color.colorify("RWX", Config.get_gef_setting("theme.address_rwx")),
            Color.colorify("String", Config.get_gef_setting("theme.dereference_string")),
        )
        gef_print(legend)
        Cache.cached_context_legend = legend
        return

    def context_title(self, m):
        line_color = Config.get_gef_setting("theme.context_title_line")
        msg_color = Config.get_gef_setting("theme.context_title_message")

        if not m:
            gef_print(Color.colorify(HORIZONTAL_LINE * self.tty_columns, line_color))
            return

        trail_len = len(m) + 6
        width = max(self.tty_columns - trail_len, 0)
        title = ""
        title += Color.colorify(HORIZONTAL_LINE * width + " ", line_color)
        title += Color.colorify(m, msg_color)
        title += Color.colorify(" " + HORIZONTAL_LINE * 4, line_color)
        gef_print(title)
        return

    def context_regs(self):
        self.context_title("registers")
        ignored_registers = set(Config.get_gef_setting("context.ignore_registers").split())

        if current_arch is None and is_remote_debug():
            err("Missing info about architecture. Please set: `file /path/to/target_binary`")
            return

        if Config.get_gef_setting("context.show_registers_raw") is False:
            regs = set(current_arch.all_registers)
            printable_registers = " ".join(list(regs - ignored_registers))
            gdb.execute("registers {}".format(printable_registers))
            self.context_extra_regs()
            return

        widest = x = current_arch.get_aliased_registers_name_max()
        x += 5
        x += current_arch.ptrsize * 2
        nb = GefUtil.get_terminal_size()[1] // x
        i = 1
        line = ""
        changed_color = Config.get_gef_setting("theme.registers_value_changed")
        regname_color = Config.get_gef_setting("theme.registers_register_name")

        for regname in current_arch.all_registers:
            if regname in ignored_registers:
                continue

            padreg = current_arch.get_aliased_registers()[regname].ljust(widest, " ")

            new_value = get_register(regname)
            old_value = self.old_registers.get(regname, 0)

            if new_value == old_value:
                line += "{}: ".format(Color.colorify(padreg, regname_color))
            else:
                line += "{}: ".format(Color.colorify(padreg, changed_color))
            line += "{:s} ".format(ProcessMap.lookup_address(new_value).long_fmt())

            if i % nb == 0:
                gef_print(line)
                line = ""
            i += 1

        if line:
            gef_print(line)

        if current_arch.flag_register:
            gef_print("Flags: {:s}".format(current_arch.flag_register_to_human()))

        self.context_extra_regs()
        return

    RE_SUB_OPERAND1 = re.compile(r"<.*?>")
    RE_SUB_OPERAND2 = re.compile(r"\[.*?\]")
    RE_FINDALL_SSE = re.compile(r"(xmm\d+)")
    RE_FINDALL_AVX = re.compile(r"(ymm\d+)")
    RE_FINDALL_MMX = re.compile(r"([^xy]mm\d+)")
    RE_FINDALL_FPU = re.compile(r"(st\(\d\))")

    def context_extra_regs(self):
        if not is_x86():
            return

        try:
            insn = get_insn()
            insn_prev = get_insn_prev()
        except gdb.MemoryError:
            self.previous_extra_regs = {}
            return

        if insn is None:
            return

        if insn_prev is None:
            return

        operands = ", ".join(insn.operands)
        operands = self.RE_SUB_OPERAND1.sub("", operands)
        operands = self.RE_SUB_OPERAND2.sub("", operands)

        if self.previous_extra_regs:
            if self.previous_extra_regs["pc"] != insn_prev.address:
                self.previous_extra_regs = {}

        printed_extra_regs = {"pc": current_arch.pc}

        # sse register
        to_save_regs = self.RE_FINDALL_SSE.findall(operands)
        to_print_regs = to_save_regs + self.previous_extra_regs.get("xmm", [])
        if to_print_regs:
            to_print_regs = sorted(set(to_print_regs))
            lines = gdb.execute("xmm", to_string=True).splitlines()
            for reg in to_print_regs:
                for line in lines:
                    if ("$" + reg) in line.split(":")[0]:
                        gef_print(line)
                        if reg in to_save_regs:
                            printed_extra_regs["xmm"] = printed_extra_regs.get("xmm", []) + [reg]
                        break

        # avx register
        to_save_regs = self.RE_FINDALL_AVX.findall(operands)
        to_print_regs = to_save_regs + self.previous_extra_regs.get("ymm", [])
        if to_print_regs:
            to_print_regs = sorted(set(to_print_regs))
            lines = gdb.execute("ymm", to_string=True).splitlines()
            for reg in to_print_regs:
                for line in lines:
                    if ("$" + reg) in line.split(":")[0]:
                        gef_print(line)
                        if reg in to_save_regs:
                            printed_extra_regs["ymm"] = printed_extra_regs.get("ymm", []) + [reg]
                        break

        # mmx register
        to_save_regs = self.RE_FINDALL_MMX.findall(operands)
        to_print_regs = to_save_regs + self.previous_extra_regs.get("mmx", [])
        if to_print_regs:
            to_print_regs = sorted(set(to_print_regs))
            lines = gdb.execute("mmx", to_string=True).splitlines()
            for reg in to_print_regs:
                for line in lines:
                    if ("$" + reg) in line.split(":")[0]:
                        gef_print(line)
                        if reg in to_save_regs:
                            printed_extra_regs["mmx"] = printed_extra_regs.get("mmx", []) + [reg]
                        break

        # fpu register
        if insn.mnemonic[0] == "f":
            to_save_regs = self.RE_FINDALL_FPU.findall(operands)
            to_print_regs = to_save_regs + self.previous_extra_regs.get("fpu", [])
            if to_print_regs:
                to_print_regs = sorted(set(to_print_regs))
                lines = gdb.execute("fpu", to_string=True).splitlines()
                for reg in to_print_regs:
                    for line in lines:
                        if ("$" + re.sub(r"[()]", reg, "")) in line.split(":")[0]:
                            gef_print(line)
                            if reg in to_save_regs:
                                printed_extra_regs["fpu"] = printed_extra_regs.get("fpu", []) + [reg]
                            break

        self.previous_extra_regs = printed_extra_regs
        return

    def context_stack(self):
        self.context_title("stack")

        show_raw = Config.get_gef_setting("context.show_stack_raw")
        nb_lines = Config.get_gef_setting("context.nb_lines_stack")

        if current_arch is None and is_remote_debug():
            err("Missing info about architecture. Please set: `file /path/to/target_binary`")
            return

        sp = current_arch.sp

        if sp is None:
            err("Failed to get value of $SP")
            return

        if show_raw is True:
            try:
                mem = read_memory(sp, 0x10 * nb_lines)
                gef_print(hexdump(mem, base=sp))
            except gdb.MemoryError:
                err("Cannot read memory from $SP (corrupted stack pointer?)")
        else:
            if not current_arch.stack_grow_down:
                gdb.execute("dereference {:#x} {:d} --no-pager".format(sp, nb_lines))
            else:
                gdb.execute("dereference {:#x} -{:d} --no-pager".format(sp, nb_lines))
        return

    def get_breakpoints(self):
        breakpoints = gdb.breakpoints()
        if not breakpoints:
            return []
        bp_locations = []
        for b in breakpoints:
            if hasattr(b, "locations"): # gdb 13.1~
                for bl in b.locations:
                    if bl and bl.address is not None:
                        bp_locations.append(bl.address)
            else: # for old gdb
                if b.location and b.location.startswith("*"):
                    pos = b.location.lstrip("*")
                    try:
                        x = int(pos, 16)
                        bp_locations.append(x)
                    except ValueError:
                        pass
        return bp_locations

    def context_code(self):
        use_native_x_command = Config.get_gef_setting("context.use_native_x_command")
        nb_insn = Config.get_gef_setting("context.nb_lines_code")
        nb_insn_prev = Config.get_gef_setting("context.nb_lines_code_prev")
        show_opcodes_size = Config.get_gef_setting("context.show_opcodes_size")
        past_lines_color = Config.get_gef_setting("theme.context_code_past")
        future_lines_color = Config.get_gef_setting("theme.context_code_future")
        use_capstone = Config.get_gef_setting("context.use_capstone")
        padding = " " * len(RIGHT_ARROW[1:])

        if current_arch is None and is_remote_debug():
            self.context_title("code")
            err("Missing info about architecture. Please set: `file /path/to/target_binary`")
            return

        pc = current_arch.pc
        bp_locations = self.get_breakpoints()

        try:
            frame = gdb.selected_frame()
            arch_name = "{}:{}".format(current_arch.arch.lower(), current_arch.mode)
        except gdb.error:
            # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
            frame = None
            arch_name = "{}:{}".format(current_arch.arch.lower(), "???")

        if use_native_x_command:
            arch_name += " (gdb-native)"
        elif use_capstone:
            arch_name += " (capstone)"
        else:
            arch_name += " (gdb-native)"

        self.context_title("code: {}".format(arch_name))
        if use_native_x_command:
            gdb.execute("x/16i {:#x}".format(current_arch.pc))
            return

        for insn in Disasm.gef_disassemble(pc, nb_insn, nb_prev=nb_insn_prev):
            line = ""
            is_taken = False
            target = None
            delay_slot = None

            # bp prefix
            if insn.address in bp_locations:
                bp_prefix = Color.redify(BP_GLYPH)
            else:
                bp_prefix = " "

            # insn to string with coloring by address against pc
            if insn.address < pc:
                text = "{:{}o}".format(insn, show_opcodes_size)
                if past_lines_color:
                    text = Color.remove_color(text)
                    text = Color.colorify(text, past_lines_color)
            elif insn.address == pc:
                text = "{:{}O}".format(insn, show_opcodes_size)
            else:
                text = "{:{}o}".format(insn, show_opcodes_size)
                if future_lines_color:
                    text = Color.remove_color(text)
                    text = Color.colorify(text, future_lines_color)

            # bp prefix and branch info
            if insn.address != pc:
                line += "{}{}{}".format(bp_prefix, padding, text)

            elif insn.address == pc:
                line += "{}{}{}".format(bp_prefix, RIGHT_ARROW[1:], text)

                # branch info
                if current_arch.is_conditional_branch(insn):
                    is_taken, reason = current_arch.is_branch_taken(insn)
                    if is_taken:
                        target = self.get_branch_addr(insn)
                        reason = "[Reason: {:s}]".format(reason) if reason else ""
                        line += "\t" + Color.colorify("TAKEN {:s}".format(reason), "bold green")
                        delay_slot = current_arch.has_delay_slot
                    else:
                        reason = "[Reason: !({:s})]".format(reason) if reason else ""
                        line += "\t" + Color.colorify("NOT taken {:s}".format(reason), "bold red")
                elif current_arch.is_jump(insn):
                    target = self.get_branch_addr(insn)
                    delay_slot = current_arch.has_delay_slot
                elif current_arch.is_call(insn) and Config.get_gef_setting("context.peek_calls") is True:
                    target = self.get_branch_addr(insn)
                    delay_slot = current_arch.has_delay_slot
                elif current_arch.is_ret(insn) and Config.get_gef_setting("context.peek_ret") is True:
                    target = current_arch.get_ra(insn, frame)
                    delay_slot = current_arch.has_ret_delay_slot

                if is_arc32() or is_arc64():
                    delay_slot = insn.mnemonic.endswith(".d") or insn.mnemonic.endswith(".d.nt")

            # comment
            if insn.address in ContextCommand.context_comments:
                line += "\t\t" + Color.grayify("// " + "; ".join(ContextCommand.context_comments[insn.address]))

            gef_print(line)

            # add extra branch info
            if target:
                # for delay slot
                try:
                    if delay_slot:
                        next_insn = list(Disasm.gef_disassemble(insn.address, 2))[-1]
                        text = "{:{}o}".format(next_insn, show_opcodes_size)
                        text = "{}{}{}\t{}".format(bp_prefix, padding, text, Color.colorify("Maybe delay-slot", "bold yellow"))
                        gef_print(text)
                except Exception:
                    pass

                # branch target address
                try:
                    for i, tinsn in enumerate(Disasm.gef_disassemble(target, nb_insn)):
                        text = "{:{}o}".format(tinsn, show_opcodes_size)
                        if i == 0:
                            gef_print("") # need blank line
                            text = "   {} {}".format(RIGHT_ARROW[1:-1], text)
                        else:
                            text = "   {} {}".format("  ", text)
                        gef_print(text)
                    gef_print("") # need blank line
                except Exception:
                    pass

        self.context_memory_access()
        self.context_memory_access2() # for x86/x64 - fs/gs
        self.context_memory_access3() # for x86/x64 - cs/ss/ds/es
        return

    RE_SUB_OPERAND3 = re.compile(r"<.*?>")
    RE_FINDALL_SEG1 = re.compile(r"[^:](\[.+?\])")
    RE_MATCH_REG1 = re.compile(r"r\d+d?")
    RE_MATCH_REG2 = re.compile(r"r\d+")
    RE_MATCH_REG3 = re.compile(r"[xw]\d+")

    def context_memory_access(self):
        if not (is_x86() or is_arm32() or is_arm64()):
            return

        inst_iter = Disasm.gef_disassemble(current_arch.pc, 2)
        try:
            insn_here = inst_iter.__next__()
        except StopIteration:
            return

        if insn_here.operands == []:
            return
        if insn_here.mnemonic == "nop":
            return

        insn = ",".join(insn_here.operands)
        insn = self.RE_SUB_OPERAND3.sub("", insn)
        r = self.RE_FINDALL_SEG1.findall(str(insn)) # Unsupported: seg:[reg]
        if not r:
            return

        insn_next = inst_iter.__next__()
        codesize = insn_next.address - insn_here.address

        for code in r:
            code = code[1:-1] # skip "[" and "]"

            if is_x86():
                # add "$" to resiter
                code = code.replace("+", " + ")
                code = code.replace("-", " - ")
                code = code.replace("*", " * ")
                code = code.replace("eiz", " 0 ") # $eiz is always 0x0
                code = code.split()
                code = ["$" + x if x.isalpha() or self.RE_MATCH_REG1.match(x) else x for x in code]
                code = "".join(code)
                # $rip/$eip points next instruction
                code_orig, code = code, code.replace("$rip", "$rip+{:#x}".format(codesize))

            elif is_arm32():
                # add "$" to resiter
                code = code.replace(" ", "")
                code = code.replace("#", "")
                code = code.replace("lsl", "<<")
                code = code.split(",")
                code = ["$" + x if x.isalpha() or self.RE_MATCH_REG2.match(x) else x for x in code]
                if "<<" in code[-1]:
                    code = code[:-2] + ["(" + code[-2] + code[-1] + ")"]
                code = "+".join(code)
                # $pc points next next instruction
                code_orig, code = code, code.replace("$pc", "$pc+{:#x}".format(codesize * 2))

            elif is_arm64():
                # add "$" to resiter
                code = code.replace(" ", "")
                code = code.replace("#", "")
                code = code.replace("lsl", "<<").replace("sxtw", "<<").replace("uxtw", "<<")
                code = code.replace("xzr", " 0 ") # $xzr is always 0x0
                code = code.replace("wzr", " 0 ") # $wzr is always 0x0
                code = code.replace("wsp", " ($sp&0xffff) ") # $wsp is a half of $sp
                code = code.split(",")
                code = ["$" + x if x.isalpha() or self.RE_MATCH_REG3.match(x) else x for x in code]
                if "<<" == code[-1]:
                    code[-1] += "0"
                if "<<" in code[-1]:
                    code = code[:-2] + ["(" + code[-2] + code[-1] + ")"]
                code = "+".join(code)
                # $pc points next next instruction
                code_orig, code = code, code.replace("$pc", "$pc+{:#x}".format(codesize * 2))

            # print
            try:
                code = code.replace("$", "(long)$")
                addr = AddressUtil.parse_address(code)
            except gdb.error:
                # some binary fails to resolve "(long)"
                try:
                    addr = AddressUtil.parse_address(code_orig)
                except gdb.error:
                    return
            self.context_title("memory access: {:s} = {:#x}".format(code_orig, addr))
            gdb.execute("dereference {:#x} 4 --no-pager".format(addr))
        return

    RE_FINDALL_SEG2 = re.compile(r"((fs|gs):\[?([^,\]]+)\]?)")
    RE_MATCH_REG4 = re.compile(r"r\d+d?")

    def context_memory_access2(self):
        if not is_x86():
            return

        inst_iter = Disasm.gef_disassemble(current_arch.pc, 2)
        try:
            insn_here = inst_iter.__next__()
        except StopIteration:
            return

        if insn_here.operands == []:
            return

        insn = ",".join(insn_here.operands)
        insn = re.sub(r"<.+>", "", insn)

        try:
            insn_next = inst_iter.__next__()
        except StopIteration:
            return
        codesize = insn_next.address - insn_here.address

        r = self.RE_FINDALL_SEG2.findall(str(insn))
        if r:
            code, fsgs, offset = r[0][0], r[0][1], r[0][2]
            if fsgs == "fs":
                fsgs_val = current_arch.get_fs()
            else:
                fsgs_val = current_arch.get_gs()
            if fsgs_val is None:
                return
            offset = offset.replace("+", " + ")
            offset = offset.replace("-", " - ")
            offset = offset.replace("*", " * ")
            offset = offset.replace("eiz", " 0 ") # $eiz is always 0x0
            offset = offset.split()
            offset = ["$" + x if x.isalpha() or self.RE_MATCH_REG4.match(x) else x for x in offset]
            offset = "".join(offset)
            # $rip/$eip points next instruction
            offset = offset.replace("$rip", "$rip+{:#x}".format(codesize))
            offset = AddressUtil.parse_address(offset)
            addr = AddressUtil.align_address(fsgs_val + offset)
            self.context_title("memory access: {:s} = {:#x}".format(code, addr))
            gdb.execute("dereference {:#x} 4 --no-pager".format(addr))
        return

    RE_FINDALL_SEG3 = re.compile(r"((es|ds|ss|cs):\[?([^,\]]+)\]?)")
    RE_MATCH_REG5 = re.compile(r"r\d+d?")

    def context_memory_access3(self):
        if not is_x86():
            return

        inst_iter = Disasm.gef_disassemble(current_arch.pc, 1)
        try:
            insn_here = inst_iter.__next__()
        except StopIteration:
            return

        if insn_here.operands == []:
            return

        insn = ",".join(insn_here.operands)
        insn = re.sub(r"<.+>", "", insn)

        r = self.RE_FINDALL_SEG3.findall(str(insn))
        for rr in r:
            code, addr = rr[0], rr[2]
            addr = addr.replace("+", " + ")
            addr = addr.replace("-", " - ")
            addr = addr.replace("*", " * ")
            addr = addr.replace("eiz", " 0 ") # $eiz is always 0x0
            addr = addr.split()
            addr = ["$" + x if x.isalpha() or self.RE_MATCH_REG5.match(x) else x for x in addr]
            addr = AddressUtil.parse_address("".join(addr))
            self.context_title("memory access: {:s} = {:#x}".format(code, addr))
            gdb.execute("dereference {:#x} 4 --no-pager".format(addr))
        return

    RE_SUB_BRANCH_ADDR1 = re.compile(r".*# (0x[a-fA-F0-9]+).*")
    RE_SUB_BRANCH_ADDR2 = re.compile(r".*# (0x[a-fA-F0-9]+).*")
    RE_SUB_BRANCH_ADDR3 = re.compile(r".* (PTR|ptr) \[(.+?)\].*")
    RE_SUB_BRANCH_ADDR4 = re.compile(r".* (PTR|ptr) fs:\[?(0x[a-fA-F0-9]+)\]?.*")
    RE_SUB_BRANCH_ADDR5 = re.compile(r".* (PTR|ptr) gs:\[?(0x[a-fA-F0-9]+)\]?.*")
    RE_SUB_BRANCH_ADDR6 = re.compile(r"^.*\s+([-0-9]+)$")
    RE_SUB_BRANCH_ADDR7 = re.compile(r".*(0x[a-fA-F0-9]+).*")

    @staticmethod
    def get_branch_addr(insn, to_str=False):
        ops = " ".join(insn.operands)
        ops = re.sub(r"<.*?>", "", ops)

        # is there an evaluated immediate value?
        #   x86/x64 (default): call ... [rip+0x1111] # 0xAABBCCDD
        if " # 0x" in ops and not is_loongarch64():
            addr = ContextCommand.RE_SUB_BRANCH_ADDR1.sub(r"\1", ops)
            ptr = to_unsigned_long(gdb.parse_and_eval(addr))
            try:
                if to_str:
                    return "{:#x}".format(read_int_from_memory(ptr))
                else:
                    return read_int_from_memory(ptr)
            except gdb.MemoryError:
                if to_str:
                    return "*{:#x}".format(ptr)
                else:
                    return None

        # is there an evaluated immediate value?
        #   loongarch64: bnez $t1, -8 (0x7ffff8) # 0x120000868
        if " # 0x" in ops and is_loongarch64():
            addr = ContextCommand.RE_SUB_BRANCH_ADDR2.sub(r"\1", ops)
            ptr = to_unsigned_long(gdb.parse_and_eval(addr))
            if to_str:
                return "{:#x}".format(ptr)
            else:
                return ptr

        # is there a memory reference by register?
        #   x86/x64 (default): call ... PTR [rbx]
        #   x86/x64 (capstone): call ... ptr [rbx]
        #   x64 (capstone): call ... ptr [rip + 0x1111]
        if is_x86():
            if " PTR [" in ops or " ptr [" in ops:
                addr = ContextCommand.RE_SUB_BRANCH_ADDR3.sub(r"\2", ops)
                for gr in current_arch.gpr_registers:
                    addr = addr.replace(gr.replace("$", ""), gr)
                if is_x86_64():
                    addr = addr.replace("$rip", "$rip+{:#x}".format(len(insn.opcodes)))
                try:
                    ptr = to_unsigned_long(gdb.parse_and_eval(addr))
                except gdb.error:
                    return None
                try:
                    if to_str:
                        return "{:#x}".format(read_int_from_memory(ptr))
                    else:
                        return read_int_from_memory(ptr)
                except gdb.MemoryError:
                    if to_str:
                        return "*{:#x}".format(ptr)
                    else:
                        return None

        # is there a segment relative?
        #   x64 (default): call ... PTR fs:0x10
        #   x64 (capstone): call ... ptr fs:[0x10]
        if is_x86_64():
            if " PTR fs:" in ops or " ptr fs:" in ops:
                ofs = ContextCommand.RE_SUB_BRANCH_ADDR4.sub(r"\2", ops)
                ofs = to_unsigned_long(gdb.parse_and_eval(ofs))
                fs = current_arch.get_fs()
                try:
                    if to_str:
                        return "{:#x}".format(read_int_from_memory(fs + ofs))
                    else:
                        return read_int_from_memory(fs + ofs)
                except gdb.MemoryError:
                    if to_str:
                        return "*{:#x}".format(fs + ofs)
                    else:
                        return None

        # is there a segment relative?
        #   x86 (default): call ... PTR gs:0x10
        #   x86 (capstone): call ... ptr gs:[0x10]
        if is_x86_32():
            if " PTR gs:" in ops or " ptr gs:" in ops:
                ofs = ContextCommand.RE_SUB_BRANCH_ADDR5.sub(r"\2", ops)
                ofs = to_unsigned_long(gdb.parse_and_eval(ofs))
                gs = current_arch.get_gs()
                try:
                    if to_str:
                        return "{:#x}".format(read_int_from_memory(gs + ofs))
                    else:
                        return read_int_from_memory(gs + ofs)
                except gdb.MemoryError:
                    if to_str:
                        return "*{:#x}".format(gs + ofs)
                    else:
                        return None

        # is there a relative immediate?
        #   microblaze:  brlid  r15, -136
        #   microblaze:  bneid  r4, -8    // 3ffe9848
        if is_microblaze():
            addr = ContextCommand.RE_SUB_BRANCH_ADDR6.sub(r"\1", ops.split("//")[0].strip())
            try:
                addr = int(addr) + insn.address
                if to_str:
                    return "{:#x}".format(addr)
                else:
                    return addr
            except Exception:
                pass

        # is there a absolute immediate value (with segment)?
        #   x86_16:  ljmp   0xf000:0xe05b
        if is_x86_16() and ":0x" in ops:
            seg, val = [int(x, 16) for x in ops.split(":")]
            if ops.startswith("0x"):
                addr = current_arch.real2phys(seg, val)
            else:
                addr = val
            if to_str:
                return "{:#x}".format(addr)
            else:
                return addr

        # is there a absolute immediate value?
        #   s390x:   bra    0x3ffdfc60
        #   s390x:   brasl  %r14, 0x1020b50
        #   RISCV:   jal    ra, 0x13894
        #   RISCV:   bgeu   t1, a2, 0x10350
        if "0x" in ops:
            addr = ContextCommand.RE_SUB_BRANCH_ADDR7.sub(r"\1", ops)
            if to_str:
                return "{:#x}".format(to_unsigned_long(gdb.parse_and_eval(addr)))
            else:
                return to_unsigned_long(gdb.parse_and_eval(addr))

        # is there register(s)?
        #   x86/x64: call   rax
        #   s390x:   basr   %lr, %r1
        #   sh4:     jsr    @r1
        #   alpha:   jmp    (t0)
        maybe_reg = insn.operands[-1].split()[0]
        if len(maybe_reg) <= 5 and maybe_reg[0] == "(" and maybe_reg[-1] == ")":
            maybe_reg = maybe_reg[1:-1]
        ptr = get_register(maybe_reg)
        if ptr is not None:
            if to_str:
                return "{:#x}".format(ptr)
            else:
                return ptr

        return None

    RE_SUB_ARGS_SYMBOL = re.compile(r".*<([^\(\)\ \>]*?)>.*")

    def context_args(self):
        if current_arch is None and is_remote_debug():
            err("Missing info about architecture. Please set: `file /path/to/target_binary`")
            return

        try:
            insn = get_insn()
        except gdb.MemoryError:
            return

        if insn is None:
            return

        if current_arch.is_syscall(insn):
            self.context_title("arguments")
            gdb.execute("syscall-args")
            return

        if not current_arch.is_call(insn):
            return

        def get_sym_obj(insn):
            # insn -> addr
            addr = self.get_branch_addr(insn)
            if addr is None:
                return None

            # addr -> sym_str
            ret = Symbol.gdb_get_location(addr)
            if not ret:
                return None
            sym_str, _ = ret

            # If it's a PLT call, it should resolve the symbol for the actual function.
            # e.g.: puts@plt -> puts
            if sym_str.endswith("@plt"):
                sym_str = sym_str[:-4]

            # weak symbol -> real symbol
            # e.g.: puts -> __GI__IO_puts
            try:
                ret = gdb.execute("p '{:s}'".format(sym_str), to_string=True).strip()
                real_sym_str = self.RE_SUB_ARGS_SYMBOL.sub(r"\1", ret)
            except gdb.error:
                # Some functions do not have PLT names.
                # e.g.: *ABS*+0xXXXX
                return None

            # If it resolves the real symbol, it may not be the beginning of the function. This is not the symbol I want.
            # To determine whether it is the beginning of a function, use whether a "+" symbol is included.
            # Another option is to check whether AddressUtil.parse_address(real_symbol) returns the original address.
            # However, this cannot be used in cases where addresses exceeding the PLT are handled, so this should not be used.
            if "+" not in real_sym_str:
                sym_str = real_sym_str
            else:
                # e.g.: ptmalloc_init -> __GI___libc_malloc+528
                pass

            # sym_str -> sym_obj
            sym_obj = gdb.lookup_symbol(sym_str)[0]
            if sym_obj is None:
                # There are cases where the symbol string is found but the symbol object is not.
                # e.g.: __do_global_dtors_aux
                return None
            if sym_obj.type.code != gdb.TYPE_CODE_FUNC:
                return None

            # found
            return sym_obj, sym_str

        ret = get_sym_obj(insn)
        if ret:
            # okay, it has a symbol
            self.print_arguments_from_symbol(*ret)
            return

        # no, try extract target address
        function_name = self.get_branch_addr(insn, to_str=True)
        if function_name is None:
            # failed, use raw operands
            function_name = " ".join(insn.operands)
        self.print_guessed_arguments(function_name)
        return

    def print_arguments_from_symbol(self, sym_obj, function_name):
        """If symbols were found, parse them and print the argument adequately."""
        args = []

        # In gdb, there is no way to get the argument names of a function before call the function.
        # You can get the argument names with `info args`, but only after the function is called.
        # Also, the arguments obtained with info args may differ from the source code due to
        # optimization reasons. (e.g.: _int_malloc)
        # Since only the type of the argument can be obtained, only the type information is used.

        size2type = {
            1: "BYTE",
            2: "WORD",
            4: "DWORD",
            8: "QWORD",
        }

        for i, f in enumerate(sym_obj.type.fields()):
            _value = current_arch.get_ith_parameter(i, in_func=False)[1]
            if _value is None:
                break
            _value = AddressUtil.recursive_dereference_to_string(_value)
            _name = f.name or "var_{}".format(i)
            _type = f.type.name or size2type[f.type.sizeof]
            args.append("{} {} = {}".format(_type, _name, _value))

        self.context_title("arguments")

        if not args:
            gef_print("{} (<void>)".format(function_name))
            return

        gef_print("{} (".format(function_name))
        gef_print("   " + ",\n   ".join(args))
        gef_print(")")
        return

    def print_guessed_arguments(self, function_name):
        """When no symbol, print six arguments."""
        arg_key_color = Config.get_gef_setting("theme.registers_register_name")
        nb_argument = Config.get_gef_setting("context.nb_guessed_arguments")
        _arch_mode = "{}_{}".format(current_arch.arch.lower(), current_arch.mode)
        _function_name = None
        if function_name.endswith("@plt"):
            _function_name = function_name.split("@")[0]

        args = []
        for i in range(nb_argument):
            try:
                _key, _value = current_arch.get_ith_parameter(i, in_func=False)
                _value = AddressUtil.recursive_dereference_to_string(_value)
            except Exception:
                break
            args.append("{} = {}".format(Color.colorify(_key, arg_key_color), _value))

        self.context_title("arguments (guessed)")
        gef_print("{:s}{:s} (".format(function_name, Symbol.get_symbol_string(function_name, nosymbol_string=" <NO_SYMBOL>")))
        if args:
            gef_print("   " + ",\n   ".join(args))
        gef_print(")")
        return

    def get_source_breakpoints(self, file_base_name):
        breakpoints = gdb.breakpoints()
        if not breakpoints:
            return []
        bp_locations = []
        for b in breakpoints:
            if hasattr(b, "locations"):
                for bl in b.locations:
                    if bl.source:
                        bp_locations.append("{:s}:{:d}".format(bl.source[0], bl.source[1]))
            else: # for old gdb
                bp_locations.append(b.location)
        return bp_locations

    def line_has_breakpoint(self, file_name, line_number, bp_locations):
        filename_line = "{}:{}".format(file_name, line_number)
        return any(filename_line in loc for loc in bp_locations)

    def context_source(self):
        try:
            pc = current_arch.pc
            symtabline = gdb.find_pc_line(pc)
            symtab = symtabline.symtab
            line_num = symtabline.line - 1 # we subtract one because line number returned by gdb start at 1
            if not symtab.is_valid():
                return
            fpath = symtab.fullname()
            with open(fpath, "r") as f:
                lines = [x.rstrip() for x in f.readlines()]
        except Exception:
            return

        file_base_name = os.path.basename(symtab.filename)
        bp_locations = self.get_source_breakpoints(file_base_name)
        past_lines_color = Config.get_gef_setting("theme.context_code_past")
        future_lines_color = Config.get_gef_setting("theme.context_code_future")

        nb_line = Config.get_gef_setting("context.nb_lines_code")
        cur_line_color = Config.get_gef_setting("theme.source_current_line")
        self.context_title("source: {}+{}".format(os.path.normpath(symtab.filename), line_num + 1))
        show_extra_info = Config.get_gef_setting("context.show_source_code_variable_values")

        for i in range(line_num - nb_line + 1, line_num + nb_line):
            if i < 0:
                continue

            if self.line_has_breakpoint(file_base_name, i + 1, bp_locations):
                bp_prefix = Color.redify(BP_GLYPH)
            else:
                bp_prefix = " "

            if i < line_num:
                past_line = "{:4d}   {:s}".format(i + 1, lines[i])
                past_line = Color.colorify(past_line, past_lines_color)
                gef_print("{:1s}{:2s}{:s}".format(bp_prefix, "", past_line))

            elif i == line_num:
                prefix = "{:1s}{:2s}{:4d}   ".format(bp_prefix, RIGHT_ARROW[1:-1], i + 1)
                leading = len(lines[i]) - len(lines[i].lstrip())
                if show_extra_info:
                    extra_info = self.get_pc_context_info(pc, lines[i])
                    for ext in extra_info:
                        gef_print("{}// {}".format(" " * (len(prefix) + leading), ext))
                gef_print(Color.colorify("{}{:s}".format(prefix, lines[i]), cur_line_color))

            elif i > line_num:
                try:
                    future_line = "{:4d}   {:s}".format(i + 1, lines[i])
                    future_line = Color.colorify(future_line, future_lines_color)
                    gef_print("{:1s}{:2s}{:s}".format(bp_prefix, "", future_line))
                except IndexError:
                    break
        return

    def get_pc_context_info(self, pc, line):
        try:
            current_block = gdb.block_for_pc(pc)
        except gdb.error:
            return []

        if not current_block or not current_block.is_valid():
            return []

        m = []
        seen_symbol = []
        while current_block and not current_block.is_static:
            for sym in current_block:
                if sym.is_function:
                    continue
                if re.search(r"\W{}\W".format(sym.name), line):
                    try:
                        val = gdb.parse_and_eval(sym.name)
                    except gdb.error:
                        continue
                    if val.type.code in (gdb.TYPE_CODE_PTR, gdb.TYPE_CODE_ARRAY):
                        if val.address is None:
                            continue
                        addr = int(val.address)
                        val = AddressUtil.recursive_dereference_to_string(addr)
                    elif val.type.code == gdb.TYPE_CODE_INT:
                        try:
                            val = hex(int(val))
                        except gdb.error:
                            continue
                    else:
                        continue

                    if sym.name not in seen_symbol:
                        seen_symbol.append(sym.name)
                        msg = "{} = {}".format(Color.yellowify(sym.name), val)
                        m.append(msg)
            current_block = current_block.superblock
        return m

    def context_trace(self):
        self.context_title("trace")

        nb_backtrace = Config.get_gef_setting("context.nb_lines_backtrace")
        if nb_backtrace <= 0:
            return

        try:
            orig_frame = gdb.selected_frame()
            current_frame = gdb.newest_frame()
        except gdb.error:
            # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
            err("Failed to get frame information.")
            return

        frames = [current_frame]
        while current_frame != orig_frame:
            current_frame = current_frame.older()
            frames.append(current_frame)

        nb_backtrace_before = Config.get_gef_setting("context.nb_lines_backtrace_before")
        level = max(len(frames) - nb_backtrace_before - 1, 0)
        current_frame = frames[level]

        while current_frame and nb_backtrace:
            current_frame.select()
            if not current_frame.is_valid():
                break

            # address and symbol
            pc = current_frame.pc()
            if is_x86_16():
                pc = current_arch.real2phys("$cs", pc)
            sym = Symbol.get_symbol_string(pc, nosymbol_string=" <NO_SYMBOL>")

            # frame name
            """
            Frame names (= current_frmae.name()) and symbols (= Symbol.get_symbol_string(current_frame.pc()))
            usually match, but sometimes they don't. This is an example.

            gef> bt
            #0  __futex_abstimed_wait_common64
            #1  __futex_abstimed_wait_common
            #2  __GI___futex_abstimed_wait_cancelable64
            #3  0x00007f0635e93f1b in __pthread_cond_wait_common
            #4  ___pthread_cond_timedwait64

            gef> context trace
            [#0] 0x7f0635e9119d <__futex_abstimed_wait_cancelable64+0xed>
            [#1] 0x7f0635e9119d <__futex_abstimed_wait_cancelable64+0xed>
            [#2] 0x7f0635e9119d <__futex_abstimed_wait_cancelable64+0xed>
            [#3] 0x7f0635e93f1b <pthread_cond_timedwait+0x23b>
            [#4] 0x7f0635e93f1b <pthread_cond_timedwait+0x23b>

            This probably happens in cases where each symbol exists, but is inlined by optimization into a single function.
            Therefore, I will display the frame name too if different.
            """
            try:
                ret = Symbol.gdb_get_location(pc)
                if ret is None:
                    frame_name = None
                elif ret[0] == current_frame.name():
                    frame_name = None
                else:
                    frame_name = Instruction.smartify_text(current_frame.name())
            except (ValueError, gdb.error):
                frame_name = None

            # current index coloring
            if current_frame == orig_frame:
                idx = Color.colorify("#{}".format(level), "bold green")
                arrow = "-> "
            else:
                idx = Color.colorify("#{}".format(level), "bold magenta")
                arrow = "   "

            # print
            if frame_name:
                frame_name = Color.colorify(frame_name, "bold yellow")
                gef_print("{:s}[{}] {!s}{:s} (frame name: {:s})".format(
                    arrow, idx, ProcessMap.lookup_address(pc), sym, frame_name,
                ))
            else:
                gef_print("{:s}[{}] {!s}{:s}".format(
                    arrow, idx, ProcessMap.lookup_address(pc), sym,
                ))

            # go next frame
            try:
                current_frame = current_frame.older()
            except gdb.error:
                break
            level += 1
            nb_backtrace -= 1

        if nb_backtrace == 0:
            if current_frame:
                gef_print("   [..]")

        orig_frame.select()
        return

    def context_threads(self):
        def reason():
            try:
                res = gdb.execute("info program", to_string=True).splitlines()
            except gdb.error:
                return "STOPPED"

            if not res:
                return "NOT RUNNING"

            for line in res:
                line = line.strip()
                if line.startswith("It stopped with signal "):
                    return line.replace("It stopped with signal ", "").split(",", 1)[0]
                if line == "The program being debugged is not being run.":
                    return "NOT RUNNING"
                if line == "It stopped at a breakpoint that has since been deleted.":
                    return "TEMPORARY BREAKPOINT"
                if line.startswith("It stopped at breakpoint "):
                    return "BREAKPOINT"
                if line == "It stopped after being stepped.":
                    return "SINGLE STEP"

            return "STOPPED"

        if is_kgdb():
            return

        nb_lines_threads = Config.get_gef_setting("context.nb_lines_threads")
        threads = gdb.selected_inferior().threads()[::-1]

        if nb_lines_threads < 0:
            shown_threads = len(threads)
        else:
            shown_threads = nb_lines_threads
        self.context_title("threads: {:d}/{:d}".format(shown_threads, len(threads)))

        if nb_lines_threads > 0:
            threads = threads[:nb_lines_threads]
        elif nb_lines_threads == 0:
            return

        if not threads:
            err("No thread selected")
            return

        selected_thread = gdb.selected_thread()
        try:
            selected_frame = gdb.selected_frame()
        except gdb.error:
            # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
            selected_frame = None

        lines = []
        for thread in threads:
            tid = str(thread.ptid[1]) or str(thread.ptid[2]) or "???"
            if thread == selected_thread:
                line = "[{:s}] ".format(Color.colorify("Thread Id:{:d}, tid:{:s}".format(thread.num, tid), "bold green"))
            else:
                line = "[{:s}] ".format(Color.colorify("Thread Id:{:d}, tid:{:s}".format(thread.num, tid), "bold magenta"))

            if thread.name:
                line += 'Name: "{:s}", '.format(thread.name)

            if thread.is_running():
                line += Color.colorify("running", "bold green")
            elif thread.is_exited():
                line += Color.colorify("exited", "bold yellow")
            elif thread.is_stopped():
                line += Color.colorify("stopped", "bold red")
                try:
                    thread.switch()
                except Exception:
                    line += " - Failed to switch to this thread"
                    gef_print(line)
                    continue
                try:
                    frame = gdb.selected_frame()
                    pc = frame.pc()
                except gdb.error:
                    # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
                    # if failed, print thread information without frame (but with $pc).
                    pc = get_register("$pc")
                sym = Symbol.get_symbol_string(pc, nosymbol_string=" <NO_SYMBOL>")
                line += " at {!s}{:s}".format(ProcessMap.lookup_address(pc), sym)
                line += ", reason: {}".format(Color.colorify(reason(), "bold magenta"))
            lines.append([thread.num, line])

        for _, line in sorted(lines):
            gef_print(line)

        selected_thread.switch()
        if selected_frame is not None:
            try:
                selected_frame.select()
                # A gdb.error will occur if the user patches a range that includes the ret instruction.
            except gdb.error:
                pass
        return

    def context_additional_information(self):
        if not ContextCommand.context_messages and not ContextCommand.context_extra_commands:
            return

        self.context_title("extra")

        for level, text in ContextCommand.context_messages:
            if level == "error":
                err(text)
            elif level == "warn":
                warn(text)
            elif level == "success":
                ok(text)
            else:
                info(text)

        for command in ContextCommand.context_extra_commands:
            gef_print(titlify(command))
            gdb.execute(command)
        return

    def context_memory(self):
        for address, opt in sorted(MemoryWatchCommand.mem_watches.items()):
            count, fmt = opt[0:2]
            self.context_title("memory:{:#x}".format(address))
            if fmt == "pointers":
                gdb.execute("dereference {:#x} {:d} --no-pager".format(address, count))
            else:
                gdb.execute("hexdump {:s} {:#x} {:d} --no-pager".format(fmt, address, count))
        return

    @classmethod
    def update_registers(cls, _event):
        try:
            for reg in current_arch.all_registers:
                try:
                    cls.old_registers[reg] = get_register(reg)
                except Exception:
                    cls.old_registers[reg] = 0
            return
        except Exception:
            return

    def empty_extra_messages(self, _event):
        ContextCommand.context_messages = []
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if gdb.selected_thread().is_running():
            return

        if is_qemu_system() and get_arch() == "i8086":
            if Config.get_gef_setting("context.enable_auto_switch_for_i8086"):
                # check whether protected mode or not.
                # even if `CR0.PE=1`, it will not switch until `ljmp`.
                # so it is better to judge whether `$cs=0x8` or not.
                # https://wiki.osdev.org/Protected_Mode
                cs = get_register("$cs")
                if cs is None or cs == 8:
                    set_arch("x86")
                else:
                    set_arch("i8086")

        if "on" in args.commands:
            gdb.execute("gef config context.enable True")
            return
        if "off" in args.commands:
            gdb.execute("gef config context.enable False")
            return

        if not Config.get_gef_setting("context.enable") or ContextCommand.context_hidden:
            return

        if len(args.commands) > 0:
            current_layout = args.commands
        else:
            current_layout = Config.get_gef_setting("context.layout").strip().split()

        if not current_layout:
            return

        self.tty_rows, self.tty_columns = GefUtil.get_terminal_size()

        if Config.get_gef_setting("context.clear_screen") and len(args.commands) == 0:
            # this is more faster than executing "shell clear -x"
            print("\x1b[H\x1b[2J", end="")

        for section in current_layout:
            if not is_alive():
                break
            if section[0] == "-":
                continue
            try:
                self.layout_mapping[section]()
                ## debug code for profiling of context command
                #from cProfile import Profile
                #import pstats
                #pr = Profile()
                #pr.runcall(self.layout_mapping[section])
                #stats = pstats.Stats(pr)
                #stats.sort_stats("tottime")
                #stats.print_stats(10)
            except gdb.MemoryError as e:
                # a MemoryError will happen when $pc is corrupted (invalid address)
                err(str(e))
        self.context_title("")
        return


@register_command
class MemoryCommand(GenericCommand):
    """The base command to watch the memory."""
    _cmdline_ = "memory"
    _category_ = "01-f. Debugging Support - Context Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("watch")
    subparsers.add_parser("unwatch")
    subparsers.add_parser("reset")
    subparsers.add_parser("list")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=True)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        self.usage()
        return


@register_command
class MemoryWatchCommand(GenericCommand):
    """Add address ranges to the memory view."""
    _cmdline_ = "memory watch"
    _category_ = "01-f. Debugging Support - Context Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="the memory address to register for display in `context memory`.")
    parser.add_argument("count", metavar="COUNT", nargs="?", type=lambda x: int(x, 0), default=0x10,
                        help="the count of displayed units. (default: %(default)s)")
    parser.add_argument("unit", nargs="?", default="pointers",
                        choices=["byte", "word", "dword", "qword", "pointers"],
                        help="the size of unit. (default: %(default)s)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0x603000 0x100 byte\n".format(_cmdline_)
    _example_ += "{:s} $sp".format(_cmdline_)

    mem_watches = {}

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        MemoryWatchCommand.mem_watches[args.address] = (args.count, args.unit)
        ok("Adding memwatch to {:#x}".format(args.address))
        return


@register_command
class MemoryUnwatchCommand(GenericCommand):
    """Remove address ranges to the memory view."""
    _cmdline_ = "memory unwatch"
    _category_ = "01-f. Debugging Support - Context Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="the memory address to deregister for display in `context memory`.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0x603000\n".format(_cmdline_)
    _example_ += "{:s} $sp".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        res = MemoryWatchCommand.mem_watches.pop(args.address, None)
        if not res:
            warn("You weren't watching {:#x}".format(args.address))
        else:
            ok("Removed memwatch of {:#x}".format(args.address))
        return


@register_command
class MemoryWatchResetCommand(GenericCommand):
    """Remove all watchpoints."""
    _cmdline_ = "memory reset"
    _category_ = "01-f. Debugging Support - Context Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        MemoryWatchCommand.mem_watches.clear()
        ok("Memory watches cleared")
        return


@register_command
class MemoryWatchListCommand(GenericCommand):
    """List all watchpoints to display in context layout."""
    _cmdline_ = "memory list"
    _category_ = "01-f. Debugging Support - Context Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if not MemoryWatchCommand.mem_watches:
            info("No memory watches")
            return

        info("Memory watches:")
        for address, opt in sorted(MemoryWatchCommand.mem_watches.items()):
            gef_print("- {:#x} ({}, {})".format(address, opt[0], opt[1]))
        return


@register_command
class HexdumpCommand(GenericCommand):
    """Display the hexdump from the memory location specified."""
    _cmdline_ = "hexdump"
    _category_ = "03-b. Memory - View"
    _repeat_ = True
    _aliases_ = ["xxd", "hd"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("format", choices=["byte", "word", "dword", "qword", "b", "w", "d", "q"], nargs="?", default="byte",
                        help="dump mode. It also works if you specify the first character. (default: %(default)s)")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the memory address to dump.")
    parser.add_argument("count", metavar="COUNT", nargs="?", type=lambda x: int(x, 0), default=0x100,
                        help="the count of displayed units. (default: %(default)s)")
    parser.add_argument("--phys", action="store_true", help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("-r", "--reverse", action="store_true", help="display in reverse order line by line.")
    parser.add_argument("-f", "--full", action="store_true", help="display the same line without omitting.")
    parser.add_argument("-s", "--symbol", action="store_true", help="display the symbol.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    @staticmethod
    def merge_lines(lines_unmerged, nb_skip_merge=1):
        lines = []
        keep_asterisk = 0

        for i, line in enumerate(lines_unmerged):
            # about first line
            if i < nb_skip_merge:
                lines.append(line)
                continue
            # don't merge error string etc.
            if "    " not in lines[-1] or "    " not in line:
                lines.append(line)
                continue
            # check if mergeable
            if re.split("    +", lines[-1])[1] == re.split("    +", line)[1]:
                keep_asterisk += 1
                prev_line = line
                continue
            # append line
            if keep_asterisk == 1:
                lines.append(prev_line)
                keep_asterisk = 0
            elif keep_asterisk > 1:
                lines.append("*")
                keep_asterisk = 0
            lines.append(line)

        # final process
        if keep_asterisk == 1:
            lines.append(prev_line)
        elif keep_asterisk > 1:
            lines.append("*")
        return lines

    def read_memory(self, read_from, read_len):
        if read_len > 0x1000000: # Too large
            return None

        try:
            if self.phys_mode:
                mem = read_physmem(read_from, read_len)
            else:
                mem = read_memory(read_from, read_len)
            return mem
        except (gdb.MemoryError, ValueError, OverflowError):
            pass

        # If you get an error, you probably read outside a valid memory page.
        # Read in page size units.
        read_end = read_from + read_len
        read_end &= gef_getpagesize_mask_high()
        while read_end - read_from > 0:
            try:
                if self.phys_mode:
                    mem = read_physmem(read_from, read_end - read_from)
                else:
                    mem = read_memory(read_from, read_end - read_from)
                return mem
            except (gdb.MemoryError, ValueError, OverflowError):
                pass
            read_end -= gef_getpagesize()
        return None

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.phys:
            if not is_qemu_system() and not is_vmware() and not is_kgdb():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return
        self.phys_mode = args.phys

        from_idx = args.count * self.repeat_count
        to_idx = args.count * (self.repeat_count + 1)
        if args.reverse:
            from_idx *= -1
            from_idx += 0x10
            to_idx *= -1
            to_idx += 0x10

        memalign_size = None
        if is_x86_16():
            memalign_size = 2.5

        read_from = AddressUtil.align_address(args.location, memalign_size=memalign_size) + min(from_idx, to_idx)
        mem = self.read_memory(read_from, args.count)
        if mem is None:
            err("cannot access memory")
            return

        unit = {"byte": 1, "word": 2, "dword": 4, "qword": 8, "b": 1, "w": 2, "d": 4, "q": 8}[args.format]
        lines = hexdump(mem, show_symbol=args.symbol, base=read_from, unit=unit).splitlines()

        if not args.full:
            lines = HexdumpCommand.merge_lines(lines)

        if args.reverse:
            lines.reverse()

        if lines:
            gef_print("\n".join(lines), less=not args.no_pager)
        return


@register_command
class HexdumpFlexibleCommand(GenericCommand):
    """Display the hexdump with user defined format."""
    _cmdline_ = "hexdump-flexible"
    _category_ = "03-b. Memory - View"
    _aliases_ = ["xxdf", "hdf"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("format", metavar="FORMAT", help="dump format.")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the memory address to dump.")
    parser.add_argument("count", metavar="COUNT", nargs="?", type=lambda x: int(x, 0), default=1,
                        help="the count of displayed units. (default: %(default)s)")
    parser.add_argument("--phys", action="store_true",
                        help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")

    _example_ = '{:s} "2Q2I2H2B" $rsp 4  # "Show qword*2, dword*2, short*2, byte*2" from $rsp and repeat 4 times\n'.format(_cmdline_)
    _example_ += '{:s} "4Q-2Q" $rsp 4     # "Show qword*4 and skip qword*2" from $rsp and repeat 4 times'.format(_cmdline_)

    def extract_each_type(self, fmt):
        out = []
        repeat = 1
        for r in re.split(r"(-?\d+|)", fmt):
            if r == "":
                continue
            try:
                repeat = int(r)
                continue
            except ValueError:
                if 0 < repeat:
                    out.extend([r] * repeat)
                else:
                    out.extend(["-" + r] * -repeat)
                repeat = 1
        return out

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.phys:
            if not is_qemu_system() and not is_vmware() and not is_kgdb():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return

        fmt = args.format
        if not fmt.startswith(("<", ">")):
            fmt = Endian.endian_str() + fmt
        try:
            size = struct.calcsize(fmt.replace("-", ""))
        except struct.error:
            err("format error")
            return

        each_type = self.extract_each_type(args.format)
        base_address_color = Config.get_gef_setting("theme.dereference_base_address")

        self.out = []
        for i in range(args.count):
            address = args.location + size * i
            try:
                if args.phys:
                    data = read_physmem(address, size)
                else:
                    data = read_memory(address, size)
            except (gdb.MemoryError, ValueError, OverflowError):
                err("Failed to read memory")
                break

            values = struct.unpack(fmt.replace("-", ""), data)
            colored_address = Color.colorify(AddressUtil.format_address(address), base_address_color)
            line_elem = ["{:s}|{:+#06x}|{:+04d}:   ".format(colored_address, size * i, i)]
            for t, v in zip(each_type, values):
                if t.startswith("-"):
                    continue
                if t in "BHILQ":
                    line_elem.append("{:#0{:d}x}".format(v, 2 + struct.calcsize(t) * 2))
                elif t in "bhilq":
                    line_elem.append("{:+#0{:d}x}".format(v, 2 + struct.calcsize(t) * 2 + 1))
                elif t in "fd":
                    line_elem.append("{:20e}".format(v))
                else:
                    err("Unsupported format: {:s}".format(t))
                    return
            self.out.append(" ".join(line_elem))

        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class PatchCommand(GenericCommand):
    """The base command to write specified values to the specified address."""
    _cmdline_ = "patch"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("byte")
    subparsers.add_parser("word")
    subparsers.add_parser("dword")
    subparsers.add_parser("qword")
    subparsers.add_parser("string")
    subparsers.add_parser("hex")
    subparsers.add_parser("pattern")
    subparsers.add_parser("nop")
    subparsers.add_parser("inf")
    subparsers.add_parser("trap")
    subparsers.add_parser("ret")
    subparsers.add_parser("syscall")
    subparsers.add_parser("history")
    subparsers.add_parser("revert")
    _syntax_ = parser.format_help()

    patch_history = []

    def __init__(self, *args, **kwargs):
        prefix = kwargs.get("prefix", True)
        complete_type = kwargs.get("complete", gdb.COMPLETE_NONE)
        super().__init__(prefix=prefix, complete=complete_type)
        self.format = None
        return

    @staticmethod
    def patch_insert(history_info):
        assert isinstance(history_info, dict)
        assert "addr" in history_info
        assert "before_data" in history_info
        assert "after_data" in history_info
        if "physmode" not in history_info:
            history_info["physmode"] = "virt"
        elif isinstance(history_info["physmode"], bool):
            if history_info["physmode"]:
                history_info["physmode"] = "phys"
            else:
                history_info["physmode"] = "virt"
        PatchCommand.patch_history.insert(0, history_info)
        ok("Inserted to patch history")
        return

    def patch(self, addr, data, length):
        try:
            before_data = read_memory(addr, length)
            write_memory(addr, data)
            after_data = read_memory(addr, length)
        except gdb.MemoryError:
            err("Failed to access memory")
            return
        except Exception as e:
            err(e)
            return
        history_info = {
            "addr": addr,
            "before_data": before_data,
            "after_data": after_data,
            "physmode": QemuMonitor.get_current_mmu_mode(),
        }
        PatchCommand.patch_history.insert(0, history_info)
        ok("Patching {:d} bytes from {!s}".format(length, ProcessMap.lookup_address(addr)))
        return

    # for qword, dword, word, byte sub-commands
    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    def do_invoke(self, args):
        SUPPORTED_SIZES = {
            "qword": (8, "Q"),
            "dword": (4, "L"),
            "word": (2, "H"),
            "byte": (1, "B"),
        }
        if self.format not in SUPPORTED_SIZES:
            self.usage()
            return

        if args.phys:
            if not is_qemu_system():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return
            orig_mode = QemuMonitor.get_current_mmu_mode()

            if orig_mode == "virt":
                enable_phys()

        try:
            addr = args.location
            size, fcode = SUPPORTED_SIZES[self.format]

            if args.endian_reverse is False:
                d = "<" if Endian.is_little_endian() else ">"
            else:
                d = ">" if Endian.is_little_endian() else "<"

            for value in args.values:
                value = AddressUtil.parse_address(value) & ((1 << size * 8) - 1)
                vstr = struct.pack(d + fcode, value)
                self.patch(addr, vstr, size)
                addr += size
        except Exception:
            self.usage()

        finally:
            if args.phys:
                if orig_mode == "virt":
                    disable_phys()
        return


@register_command
class PatchQwordCommand(PatchCommand):
    """Write specified QWORD to the specified address."""
    _cmdline_ = "patch qword"
    _category_ = "03-c. Memory - Patch"
    _aliases_ = ["patch q"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-e", dest="endian_reverse", action="store_true", help="reverse endian.")
    parser.add_argument("--phys", action="store_true",
                        help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the memory address to patch.")
    parser.add_argument("values", metavar="QWORD", nargs="*", help="the value to patch.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}    $rip 0x4142434445464748 # write `HGFEDCBA` to [rip]\n".format(_cmdline_)
    _example_ += "{:s} -e $rip 0x4142434445464748 # write `ABCDEFGH` to [rip]".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        self.format = "qword"
        return


@register_command
class PatchDwordCommand(PatchCommand):
    """Write specified DWORD to the specified address."""
    _cmdline_ = "patch dword"
    _category_ = "03-c. Memory - Patch"
    _aliases_ = ["patch d"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-e", dest="endian_reverse", action="store_true", help="reverse endian.")
    parser.add_argument("--phys", action="store_true",
                        help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the memory address to patch.")
    parser.add_argument("values", metavar="DWORD", nargs="*", help="the value to patch.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}    $rip 0x41424344 # write `DCBA` to [rip]\n".format(_cmdline_)
    _example_ += "{:s} -e $rip 0x41424344 # write `ABCD` to [rip]".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        self.format = "dword"
        return


@register_command
class PatchWordCommand(PatchCommand):
    """Write specified WORD to the specified address."""
    _cmdline_ = "patch word"
    _category_ = "03-c. Memory - Patch"
    _aliases_ = ["patch w"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-e", dest="endian_reverse", action="store_true", help="reverse endian.")
    parser.add_argument("--phys", action="store_true",
                        help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the memory address to patch.")
    parser.add_argument("values", metavar="WORD", nargs="*", help="the value to patch.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}    $rip 0x4142 # write `BA` to [rip]\n".format(_cmdline_)
    _example_ += "{:s} -e $rip 0x4142 # write `AB` to [rip]".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        self.format = "word"
        return


@register_command
class PatchByteCommand(PatchCommand):
    """Write specified BYTE to the specified address."""
    _cmdline_ = "patch byte"
    _category_ = "03-c. Memory - Patch"
    _aliases_ = ["patch b"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-e", dest="endian_reverse", action="store_true", help="reverse endian.")
    parser.add_argument("--phys", action="store_true",
                        help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the memory address to patch.")
    parser.add_argument("values", metavar="BYTE", nargs="*", help="the value to patch.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}    $rip 0x41 0x41 0x41 0x41 0x41\n".format(_cmdline_)
    _example_ += "{:s} -e $rip 0x41 0x41 0x41 0x41 0x41 # -e is ignored".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        self.format = "byte"
        return


@register_command
class PatchStringCommand(PatchCommand):
    """Write specified string to the specified memory address."""
    _cmdline_ = "patch string"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true",
                        help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the memory address to patch.")
    parser.add_argument("vstr", metavar='"double backslash-escaped string"', type=lambda x: codecs.escape_decode(x)[0],
                        help="the string to patch.")
    parser.add_argument("length", metavar="LENGTH", nargs="?",
                        type=lambda x: int(x, 0), help="the length of repeat. (default: %(default)s)")
    _syntax_ = parser.format_help()

    _example_ = '{:s} $sp "AAAABBBB"\n'.format(_cmdline_)
    _example_ += '{:s} $sp "\\\\x41\\\\x41\\\\x41\\\\x41\\\\x42\\\\x42\\\\x42\\\\x42"'.format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    def do_invoke(self, args):
        if args.phys:
            if not is_qemu_system():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return
            orig_mode = QemuMonitor.get_current_mmu_mode()

            if orig_mode == "virt":
                enable_phys()

        if args.length:
            vstr = args.vstr * (args.length // len(args.vstr) + 1)
            vstr = vstr[:args.length]
        else:
            vstr = args.vstr

        self.patch(args.location, vstr, len(vstr))

        if args.phys:
            if orig_mode == "virt":
                disable_phys()
        return


@register_command
class PatchHexCommand(PatchCommand):
    """Write specified hex string to the specified address."""
    _cmdline_ = "patch hex"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true",
                        help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the memory address to patch.")
    parser.add_argument("hstr", metavar='"hex-string"', type=lambda x: bytes.fromhex(x),
                        help="the string to patch.")
    parser.add_argument("length", metavar="LENGTH", nargs="?",
                        type=lambda x: int(x, 0), help="the length of repeat. (default: %(default)s)")
    _syntax_ = parser.format_help()

    _example_ = '{:s} $sp "4141414142424242"'.format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    def do_invoke(self, args):
        if args.phys:
            if not is_qemu_system():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return
            orig_mode = QemuMonitor.get_current_mmu_mode()

            if orig_mode == "virt":
                enable_phys()

        if args.length:
            hstr = args.hstr * (args.length // len(args.hstr) + 1)
            hstr = hstr[:args.length]
        else:
            hstr = args.hstr

        self.patch(args.location, hstr, len(hstr))

        if args.phys:
            if orig_mode == "virt":
                disable_phys()
        return


@register_command
class PatchPatternCommand(PatchCommand):
    """Write a pattern string to the specified memory address."""
    _cmdline_ = "patch pattern"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true",
                        help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("-c", "--charset", help="the charset of pattern. (default: abc..z)")
    parser.add_argument("-d", "--dry-run", action="store_true", help="only generates patterns.")
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the memory address to patch.")
    parser.add_argument("length", metavar="LENGTH", type=lambda x: int(x, 0),
                        help="the length of repeat. (default: %(default)s)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $sp 128".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    def do_invoke(self, args):
        if args.phys:
            if not is_qemu_system():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return
            orig_mode = QemuMonitor.get_current_mmu_mode()

            if orig_mode == "virt":
                enable_phys()

        pats = bytes(PatternCreateCommand.generate_cyclic_pattern(args.length, args.charset))
        if args.dry_run:
            info("Generated pattern: {}".format(pats))
            return

        self.patch(args.location, pats, len(pats))

        if args.phys:
            if orig_mode == "virt":
                disable_phys()
        return


@register_command
class PatchNopCommand(PatchCommand):
    """Patch the instruction(s) pointed by parameters with NOP."""
    _cmdline_ = "patch nop"
    _category_ = "03-c. Memory - Patch"
    _aliases_ = ["nop"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true",
                        help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the memory address to patch. (default: current_arch.pc)")
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-b", dest="byte_length", type=lambda x: int(x, 0),
                       help="the patch length of byte (mutually exclusive with `-i`). (default: %(default)s)")
    group.add_argument("-i", dest="inst_count", type=lambda x: int(x, 0), default=1,
                       help="the patch length of instruction (mutually exclusive with `-b`). (default: 1)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $pc -i 2".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        return

    def get_insns_size(self, addr, num_insts):
        addr_after_n = Disasm.gef_instruction_n(addr, num_insts)
        return addr_after_n.address - addr

    def patch_nop(self, addr, num_bytes):
        if num_bytes == 0:
            info("Not patching since num_bytes == 0")
            return

        if is_arm32() and current_arch.is_thumb() and addr & 1:
            addr -= 1

        nop_op_len = len(current_arch.nop_insn)

        if nop_op_len > num_bytes:
            err("Cannot patch instruction at {:#x} (nop_size is:{:d},insn_size is:{:d})".format(addr, nop_op_len, num_bytes))
            return

        count = num_bytes // nop_op_len
        patch_bytes = nop_op_len * count

        if patch_bytes != num_bytes:
            err("Cannot patch instruction at {:#x} (nop instruction does not evenly fit in requested size)".format(addr))
            return

        if Endian.is_big_endian():
            insn = current_arch.nop_insn[::-1]
        else:
            insn = current_arch.nop_insn

        self.patch(addr, insn * count, patch_bytes)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    def do_invoke(self, args):
        if current_arch.nop_insn is None:
            err("This command cannot work under this architecture.")
            return

        if args.phys:
            if not is_qemu_system():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return
            orig_mode = QemuMonitor.get_current_mmu_mode()

            if orig_mode == "virt":
                enable_phys()

        if args.location is None:
            location = current_arch.pc
        else:
            location = args.location

        try:
            if args.inst_count:
                num_bytes = self.get_insns_size(location, args.inst_count)
            else:
                num_bytes = args.byte_length
        except Exception:
            err("Failed to get patch bytes.")
            if args.phys:
                if orig_mode == "virt":
                    disable_phys()
            return

        try:
            self.patch_nop(location, num_bytes)
        except Exception:
            err("Failed to patch.")

        if args.phys:
            if orig_mode == "virt":
                disable_phys()
        return


@register_command
class PatchInfloopCommand(PatchCommand):
    """Patch the instruction(s) pointed by parameters with infinity loop."""
    _cmdline_ = "patch inf"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true", help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the memory address to patch. (default: current_arch.pc)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $pc".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        return

    def patch_infloop(self, addr):
        if is_arm32() and current_arch.is_thumb() and addr & 1:
            addr -= 1

        if Endian.is_big_endian():
            insn = current_arch.infloop_insn[::-1]
            if current_arch.has_delay_slot:
                insn += current_arch.nop_insn[::-1]
        else:
            insn = current_arch.infloop_insn
            if is_arc32() or is_arc64():
                if addr % 4 == 2:
                    insn = current_arch.infloop_insn2
            else:
                if current_arch.has_delay_slot:
                    insn += current_arch.nop_insn

        self.patch(addr, insn, len(insn))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    def do_invoke(self, args):
        if current_arch.infloop_insn is None:
            err("This command cannot work under this architecture.")
            return

        if args.phys:
            if not is_qemu_system():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return
            orig_mode = QemuMonitor.get_current_mmu_mode()

            if orig_mode == "virt":
                enable_phys()

        if args.location is None:
            location = current_arch.pc
        else:
            location = args.location

        try:
            self.patch_infloop(location)
        except Exception:
            err("Failed to patch.")

        if args.phys:
            if orig_mode == "virt":
                disable_phys()
        return


@register_command
class PatchTrapCommand(PatchCommand):
    """Patch the instruction(s) pointed by parameters with breakpoint or trap (if available)."""
    _cmdline_ = "patch trap"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true", help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the memory address to patch. (default: current_arch.pc)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $pc".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        return

    def patch_trap(self, addr):
        if is_arm32() and current_arch.is_thumb() and addr & 1:
            addr -= 1

        if Endian.is_big_endian():
            insn = current_arch.trap_insn[::-1]
            if current_arch.has_delay_slot:
                insn += current_arch.nop_insn[::-1]
        else:
            insn = current_arch.trap_insn
            if current_arch.has_delay_slot:
                insn += current_arch.nop_insn

        self.patch(addr, insn, len(insn))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    def do_invoke(self, args):
        if current_arch.trap_insn is None:
            err("This command cannot work under this architecture.")
            return

        if args.phys:
            if not is_qemu_system():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return
            orig_mode = QemuMonitor.get_current_mmu_mode()

            if orig_mode == "virt":
                enable_phys()

        if args.location is None:
            location = current_arch.pc
        else:
            location = args.location

        try:
            self.patch_trap(location)
        except Exception:
            err("Failed to patch.")

        if args.phys:
            if orig_mode == "virt":
                disable_phys()
        return


@register_command
class PatchRetCommand(PatchCommand):
    """Patch the instruction(s) pointed by parameters with return."""
    _cmdline_ = "patch ret"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true", help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the memory address to patch. (default: current_arch.pc)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $pc".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        return

    def patch_ret(self, addr):
        if is_arm32() and current_arch.is_thumb() and addr & 1:
            addr -= 1

        if Endian.is_big_endian():
            insn = current_arch.ret_insn[::-1]
            if current_arch.has_delay_slot:
                insn += current_arch.nop_insn[::-1]
        else:
            insn = current_arch.ret_insn
            if current_arch.has_delay_slot:
                insn += current_arch.nop_insn

        self.patch(addr, insn, len(insn))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    def do_invoke(self, args):
        if current_arch.ret_insn is None:
            err("This command cannot work under this architecture.")
            return

        if args.phys:
            if not is_qemu_system():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return
            orig_mode = QemuMonitor.get_current_mmu_mode()

            if orig_mode == "virt":
                enable_phys()

        if args.location is None:
            location = current_arch.pc
        else:
            location = args.location

        try:
            self.patch_ret(location)
        except Exception:
            err("Failed to patch.")

        if args.phys:
            if orig_mode == "virt":
                disable_phys()
        return


@register_command
class PatchSyscallCommand(PatchCommand):
    """Patch the instruction(s) pointed by parameters with syscall."""
    _cmdline_ = "patch syscall"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true", help="treat the address as physical memory (only qemu-system).")
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the memory address to patch. (default: current_arch.pc)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $pc".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_LOCATION)
        return

    def patch_syscall(self, addr):
        if is_arm32() and current_arch.is_thumb() and addr & 1:
            addr -= 1

        if Endian.is_big_endian():
            insn = current_arch.syscall_insn[::-1]
            if current_arch.has_syscall_delay_slot:
                insn += current_arch.nop_insn[::-1]
        else:
            insn = current_arch.syscall_insn
            if current_arch.has_syscall_delay_slot:
                insn += current_arch.nop_insn

        self.patch(addr, insn, len(insn))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr", "wine"))
    def do_invoke(self, args):
        if current_arch.syscall_insn is None:
            err("This command cannot work under this architecture.")
            return

        if args.phys:
            if not is_qemu_system():
                err("Unsupported. Check qemu version (at least: 4.1.0-rc0~, recommend: 5.x~)")
                return
            orig_mode = QemuMonitor.get_current_mmu_mode()

            if orig_mode == "virt":
                enable_phys()

        if args.location is None:
            location = current_arch.pc
        else:
            location = args.location

        try:
            self.patch_syscall(location)
        except Exception:
            err("Failed to patch.")

        if args.phys:
            if orig_mode == "virt":
                disable_phys()
        return


@register_command
class PatchHistoryCommand(PatchCommand):
    """Display the patch history."""
    _cmdline_ = "patch history"
    _category_ = "03-c. Memory - Patch"
    _aliases_ = ["patch list"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=False)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    def do_invoke(self, args):
        if PatchCommand.patch_history:
            gef_print("[NEW]")
            for i, hist in enumerate(PatchCommand.patch_history):
                b = " ".join(["{:02x}".format(x) for x in hist["before_data"][:0x10]])
                if len(hist["before_data"]) > 0x10:
                    b += " ..."
                a = " ".join(["{:02x}".format(x) for x in hist["after_data"][:0x10]])
                if len(hist["after_data"]) > 0x10:
                    a += " ..."
                sym = Symbol.get_symbol_string(hist["addr"])
                i_str = Color.boldify("{:d}".format(i))
                gef_print("[{:s}] {:#x}{:s}: {:s}{:s}{:s}".format(i_str, hist["addr"], sym, b, RIGHT_ARROW, a))
            gef_print("[OLD]")
        else:
            info("Patch history is empty.")
        return


@register_command
class PatchRevertCommand(PatchCommand):
    """Revert patch from the patch history."""
    _cmdline_ = "patch revert"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("revert_target", metavar="REVERT_TARGET_HISTORY", nargs="?", type=int,
                        help="the history index number to revert.")
    group.add_argument("--all", action="store_true", help="revert all patches")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0 # revert to patch history stack[0]\n".format(_cmdline_)
    _example_ += "{:s} 3 # revert to patch history stack[3] ([0]-[2] are also reverted)".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    def do_invoke(self, args):
        if len(PatchCommand.patch_history) == 0:
            info("Patch history is empty.")
            return

        if args.all:
            revert_count = len(PatchCommand.patch_history)
        else:
            if not (0 <= args.revert_target < len(PatchCommand.patch_history)):
                err("Invalid target index")
                gef_print(titlify("Patch history"))
                gdb.execute("patch history")
                return
            revert_count = args.revert_target + 1

        while PatchCommand.patch_history and revert_count > 0:
            hist = PatchCommand.patch_history.pop(0)
            b = " ".join(["{:02x}".format(x) for x in hist["before_data"][:0x10]])
            if len(hist["before_data"]) > 0x10:
                b += " ..."
            a = " ".join(["{:02x}".format(x) for x in hist["after_data"][:0x10]])
            if len(hist["after_data"]) > 0x10:
                a += " ..."
            sym = Symbol.get_symbol_string(hist["addr"])
            info("revert {:#x}{:s}: {:s}{:s}{:s}".format(hist["addr"], sym, a, RIGHT_ARROW, b))

            if is_supported_physmode():
                orig_mode = QemuMonitor.get_current_mmu_mode()
                if orig_mode == "virt" and hist["physmode"] == "phys":
                    enable_phys()
                elif orig_mode == "phys" and hist["physmode"] == "virt":
                    disable_phys()

            write_memory(hist["addr"], hist["before_data"])

            if is_supported_physmode():
                if orig_mode == "virt" and QemuMonitor.get_current_mmu_mode() == "phys":
                    disable_phys()
                elif orig_mode == "phys" and QemuMonitor.get_current_mmu_mode() == "virt":
                    enable_phys()

            revert_count -= 1
        return


@register_command
class DereferenceCommand(GenericCommand):
    """Dereference recursively from an address and display information."""
    _cmdline_ = "dereference"
    _category_ = "01-a. Debugging Support - Context"
    _repeat_ = True
    _aliases_ = ["telescope"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the memory address to dump. (default: current_arch.sp)")
    parser.add_argument("nb_lines", metavar="NB_LINES", nargs="?", type=lambda x: int(x, 0),
                        help="the count of lines.")
    parser.add_argument("-s", "--slab-contains", action="store_true", help="display slab_cache name if available.")
    parser.add_argument("-S", "--slab-contains-unaligned", action="store_true",
                        help="display slab_cache name (allow unaligned) if available.")
    parser.add_argument("-l", "--list-head", action="store_true", help="display list_head or not.")
    parser.add_argument("-p", "--phys", action="store_true", help="treat ADDRESS as a physical address.")
    parser.add_argument("-u", "--uniq", action="store_true", help="display with uniq.")
    parser.add_argument("-a", "--is-addr", action="store_true", help="display only valid address.")
    parser.add_argument("-A", "--is-not-addr", action="store_true", help="display only invalid address.")
    parser.add_argument("-t", "--tag", nargs=2, action="append", metavar=("IDX", "TAG"), help="display with tag.")
    parser.add_argument("-d", "--depth", default=1, type=int, help="depth of reference. (default: %(default)s)")
    parser.add_argument("-r", "--reverse", action="store_true", help="display in reverse order line by line.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}                             # dereference $sp 64\n".format(_cmdline_)
    _example_ += "{:s} $sp 20                      # specify location and number of elements to display\n".format(_cmdline_)
    _example_ += "{:s} $sp -20                     # display memory backwards\n".format(_cmdline_)
    _example_ += "{:s} --reverse $sp 20            # display reverse order\n".format(_cmdline_)
    _example_ += "{:s} --depth 2 $sp 20            # display recursively if valid aligned address\n".format(_cmdline_)
    _example_ += "{:s} --is-addr $sp 20            # display elements which is valid address\n".format(_cmdline_)
    _example_ += "{:s} --slab-contains $sp 20      # display with slab-contains result (available under qemu-system)\n".format(_cmdline_)
    _example_ += "{:s} --tag 0 A --tag 1 B $sp 20  # display with tags".format(_cmdline_)

    _note_ = "Use blacklist feature if reading the address causes process crash.\n"
    _note_ += 'e.g.: `gef config dereference.blacklist "[ [0xffffffffc9000000, 0xffffffffc9001000], ]"`, then `gef save`'

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        self.add_setting("max_recursion", 4, "Maximum level of pointer recursion")
        self.add_setting("blacklist", "[]", 'Dereference black list address ranges (e.g.: "[ [start1, end1], [start2, end2], ]")')
        self.add_setting("nb_lines", 64, "Number of lines to display")
        return

    @staticmethod
    @Cache.cache_until_next
    def get_frame_pcs():
        frames = []
        try:
            frame = gdb.newest_frame()
            no_ret_addr = [0, 0xffffffff, 0xffffffffffffffff]
            while frame:
                pc = frame.pc()
                if pc in no_ret_addr:
                    break
                if pc in frames:
                    break
                frames.append(pc)
                frame = frame.older()
        except gdb.error:
            pass
        return frames

    @staticmethod
    @Cache.cache_this_session
    def get_target_registers():
        regs = []
        for reg in current_arch.all_registers:
            # skip if not ggeneral registers
            if current_arch.flag_register == reg:
                continue
            if current_arch.special_registers and reg in current_arch.special_registers:
                continue
            regs.append(reg)
        return regs

    @staticmethod
    @Cache.cache_until_next
    def get_target_registers_value():
        regs = []
        for regname in DereferenceCommand.get_target_registers():
            regvalue = get_register(regname)
            if regvalue is None:
                continue
            regs.append((regname, regvalue))
        return regs

    @staticmethod
    def pprint_dereferenced(addr, idx, tag=None, phys=False):
        base_address_color = Config.get_gef_setting("theme.dereference_base_address")
        registers_color = Config.get_gef_setting("theme.dereference_register_value")
        memalign = current_arch.ptrsize
        offset = idx * memalign

        # used as first element
        memalign_size = None
        if is_x86_16():
            memalign_size = 2.5

        current_address = AddressUtil.align_address(addr + offset, memalign_size=memalign_size)

        addrs, error = AddressUtil.recursive_dereference(current_address, phys=phys)
        if len(addrs) == 1 and not error: # cannot access this area
            raise

        # create address link list
        link = AddressUtil.recursive_dereference_to_string(current_address, skip_idx=1, phys=phys)

        # create line of one entry
        addr_colored = Color.colorify(AddressUtil.format_address(addrs[0], memalign_size=memalign_size), base_address_color)
        if tag:
            line = f"{addr_colored}{VERTICAL_LINE}{offset:+#07x}{VERTICAL_LINE}{idx:+04d}: {tag:s}: {link:{memalign * 2 + 2}s}"
        else:
            line = f"{addr_colored}{VERTICAL_LINE}{offset:+#07x}{VERTICAL_LINE}{idx:+04d}: {link:{memalign * 2 + 2}s}"

        if len(addrs) == 1:
            return line

        # add extra info (retaddr, canary, cookie, register)
        extra = []
        current_address_value = addrs[1]

        # retaddr info
        for i, frame_pc in enumerate(DereferenceCommand.get_frame_pcs()):
            if not is_valid_addr(frame_pc):
                continue
            if current_address_value == frame_pc:
                extra.append("retaddr[{:d}]".format(i))
                break

        # canary info
        if not is_qemu_system() and not is_vmware() and not is_kgdb():
            res = CanaryCommand.gef_read_canary()
            if res:
                canary, location = res
                if canary != 0: # when golang binary, canary is 0
                    if current_address_value == canary:
                        extra.append("canary")

        # mangle cookie
        if not is_qemu_system() and not is_vmware() and not is_kgdb():
            res = PtrDemangleCommand.get_cookie()
            if res:
                cookie = res
                if cookie != 0:
                    if current_address_value == cookie:
                        extra.append("PTR_MANGLE cookie")

        # register info
        if not phys: # for the physical address, 0x0 may be valid, which tends to clutter the result, so skip
            if is_valid_addr(current_address_value):
                for regname, regvalue in DereferenceCommand.get_target_registers_value():
                    if current_address_value == regvalue:
                        extra.append(regname)

        # add extra to end of line
        if extra:
            extra_str = " {:s} {:s}".format(LEFT_ARROW, ", ".join(extra))
            line += Color.colorify(extra_str, registers_color)
        return line

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.slab_contains or args.slab_contains_unaligned or args.phys:
            if not (is_qemu_system() or is_kgdb() or is_vmware()):
                err("Unsupported gdb mode")
                return

        if (args.slab_contains or args.slab_contains_unaligned) and args.phys:
            err("Unsupported option pairs")
            return

        if args.tag:
            tags_dict = {}
            max_tag_width = 0
            for tag_idx, tag in args.tag:
                try:
                    tags_dict[int(tag_idx, 0)] = tag
                except ValueError:
                    err("Invalid tag idx")
                    return
                max_tag_width = max(max_tag_width, len(tag))

        if args.phys:
            unpack = u32 if is_32bit() else u64
            _read_int_from_memory = lambda x: unpack(read_physmem(x, current_arch.ptrsize))
        else:
            _read_int_from_memory = read_int_from_memory

        if args.location is None:
            start_address = current_arch.sp
        else:
            start_address = args.location

        nb_lines = args.nb_lines or Config.get_gef_setting("dereference.nb_lines")
        from_idx = nb_lines * self.repeat_count
        to_idx = nb_lines * (self.repeat_count + 1)

        if from_idx <= to_idx:
            step = 1
        else:
            step = -1
            if args.depth > 1:
                err("Unsupported using together -NB_LINES and -d DEPTH")
                return

        # dereference line by line
        out = []
        seen = []
        for idx in range(from_idx, to_idx, step):
            current_address = start_address + idx * current_arch.ptrsize
            try:
                # uniq filtering
                if args.uniq:
                    v = _read_int_from_memory(current_address)
                    if v in seen:
                        if out == [] or out[-1] != "*":
                            out.append("*")
                        continue
                    seen.append(v)

                # valid address filtering
                if args.is_addr:
                    v = _read_int_from_memory(current_address)
                    if not is_valid_addr(v):
                        continue

                # invalid address filtering
                if args.is_not_addr:
                    v = _read_int_from_memory(current_address)
                    if is_valid_addr(v):
                        continue

                # tags
                if args.tag:
                    tag = tags_dict.get(idx, "").ljust(max_tag_width)
                    line = DereferenceCommand.pprint_dereferenced(start_address, idx, tag=tag, phys=args.phys)
                else:
                    line = DereferenceCommand.pprint_dereferenced(start_address, idx, phys=args.phys)

                # register info
                regs_info = []
                for regname, regvalue in DereferenceCommand.get_target_registers_value():
                    if current_address == regvalue:
                        regs_info.append(regname)
                regs_info_str = regs_info[0] if regs_info else ""
                regs_info_ex = "+" if len(regs_info) > 1 else " "
                line = "{:>{:d}s}{:s} {:s}".format(regs_info_str, current_arch.get_registers_name_max(), regs_info_ex, line)

                out.append(line)
            except (RuntimeError, gdb.MemoryError):
                # e.g.: nop DWORD PTR [rax+rax*1+0x0]
                msg = "Cannot access memory at address {:#x}".format(current_address)
                out.append("{} {}".format(Color.colorify("[!]", "bold red"), msg))
                break

            # dump slab cache
            if args.slab_contains or args.slab_contains_unaligned:
                v = read_int_from_memory(current_address)
                ret = Kernel.get_slab_contains(v, allow_unaligned=args.slab_contains_unaligned, keep_color=True)
                if ret:
                    out.append("  {:#x}: {:s}".format(v, ret))

            # link list
            if args.list_head:
                # next
                if is_double_link_list(current_address):
                    out.append(Color.colorify("  list_head.next", "bold magenta"))
                # prev
                if is_double_link_list(start_address + (idx - 1) * current_arch.ptrsize):
                    out.append(Color.colorify("  list_head.prev", "bold magenta"))

            # multiple level dump
            if args.depth - 1 > 0:
                v = _read_int_from_memory(current_address)
                if v % current_arch.ptrsize == 0 and is_valid_addr(v):
                    cmd = "dereference --depth {:d} --no-pager {:#x} {:#x}".format(args.depth - 1, v, nb_lines)
                    ret = gdb.execute(cmd, to_string=True)
                    for line in ret.splitlines():
                        out.append("    " + line)

        if args.reverse:
            out.reverse()

        gef_print("\n".join(out), less=not args.no_pager)
        return


@register_command
class ASLRCommand(GenericCommand):
    """View / modify the ASLR setting of GDB."""
    _cmdline_ = "aslr"
    _category_ = "02-f. Process Information - Security"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("command", nargs="?", default=None, choices=[None, "on", "off"], metavar="{on,off}",
                        help="set gdb aslr settings.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_target_local
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        if is_attach() or is_remote_debug():
            warn("ASLR setting is ignored because it is remote or attached process")

        if args.command is None:
            aslr = gdb.parameter("disable-randomization")
            if aslr:
                msg = "ASLR is currently " + Color.redify("disabled")
            else:
                msg = "ASLR is currently " + Color.greenify("enabled")
            gef_print(msg)
        elif args.command == "on":
            info("Enabling ASLR")
            gdb.execute("set disable-randomization off")
        elif args.command == "off":
            info("Disabling ASLR")
            gdb.execute("set disable-randomization on")
        return


@register_command
class FollowCommand(GenericCommand):
    """View / modify the follow-fork-mode setting of GDB."""
    _cmdline_ = "follow"
    _category_ = "01-g. Debugging Support - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("command", nargs="?", default=None, choices=[None, "child", "parent"],
                        metavar="{child,parent}", help="set gdb follow settings.")
    _syntax_ = parser.format_help()

    @parse_args
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        if args.command is None:
            follow = gdb.parameter("follow-fork-mode")
            if follow == "child":
                msg = "follow " + Color.redify("Child")
            else:
                msg = "follow " + Color.redify("Parent")
            gef_print(msg)
        elif args.command == "child":
            info("Follow child")
            gdb.execute("set follow-fork-mode child")
        elif args.command == "parent":
            info("Follow parent")
            gdb.execute("set follow-fork-mode parent")
        return


@register_command
class SmartCppFunctionNameCommand(GenericCommand):
    """Toggle the setting of `context.smart_cpp_function_name`."""
    _cmdline_ = "smart-cpp-function-name"
    _category_ = "01-f. Debugging Support - Context Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        setting = gdb.execute("gef config context.smart_cpp_function_name", to_string=True)
        if "False" in setting:
            gdb.execute("gef config context.smart_cpp_function_name true", to_string=True)
        else:
            gdb.execute("gef config context.smart_cpp_function_name false", to_string=True)
        return


@register_command
class ContextExtraCommand(GenericCommand):
    """The base command to add, remove, list or clear user specified command to context-extra."""
    _cmdline_ = "context-extra"
    _category_ = "01-f. Debugging Support - Context Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("add")
    subparsers.add_parser("remove")
    subparsers.add_parser("list")
    subparsers.add_parser("clear")
    _syntax_ = parser.format_help()

    def __init__(self, *args, **kwargs):
        prefix = kwargs.get("prefix", True)
        super().__init__(prefix=prefix)
        return

    @parse_args
    def do_invoke(self, args):
        self.usage()
        return


@register_command
class ContextExtraAddCommand(ContextExtraCommand):
    """Add user specified command to execute when each step."""
    _cmdline_ = "context-extra add"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["context-extra set"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("cmd", metavar="CMD", nargs="+", help="the command to execute when each step.")
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        ContextCommand.context_extra_commands.append(" ".join(args.cmd))
        return


@register_command
class ContextExtraListCommand(ContextExtraCommand):
    """List user specified command to execute when each step."""
    _cmdline_ = "context-extra list"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["context-extra ls"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        if not ContextCommand.context_extra_commands:
            warn("Nothing to display")
            return
        for i, command in enumerate(ContextCommand.context_extra_commands):
            gef_print("[{:3d}] {:s}".format(i, command))
        return


@register_command
class ContextExtraRemoveCommand(ContextExtraCommand):
    """Remove user specified command to execute when each step."""
    _cmdline_ = "context-extra remove"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["context-extra del", "context-extra unset", "context-extra rm"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("index", metavar="INDEX", type=int,
                        help="the index of command to remove from automatically execution each step.")
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        if args.index < len(ContextCommand.context_extra_commands):
            ContextCommand.context_extra_commands.pop(args.index)
        else:
            err("Out of index")
        return


@register_command
class ContextExtraClearCommand(ContextExtraCommand):
    """clear all user specified commands to execute when each step."""
    _cmdline_ = "context-extra clear"
    _category_ = "01-f. Debugging Support - Context Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()
    _aliases_ = ["context-extra reset"]

    @parse_args
    def do_invoke(self, args):
        ContextCommand.context_extra_commands = []
        return


@register_command
class CommentCommand(GenericCommand):
    """The base command to add, remove, list or clear the comment."""
    _cmdline_ = "comment"
    _category_ = "01-f. Debugging Support - Context Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("add")
    subparsers.add_parser("remove")
    subparsers.add_parser("list")
    subparsers.add_parser("clear")
    _syntax_ = parser.format_help()

    _note_ = "Comments are temporary only. Note that it will be deleted when GDB exits."

    def __init__(self, *args, **kwargs):
        prefix = kwargs.get("prefix", True)
        super().__init__(prefix=prefix)
        return

    @parse_args
    def do_invoke(self, args):
        self.usage()
        return


@register_command
class CommentAddCommand(CommentCommand):
    """Add a comment to specific address."""
    _cmdline_ = "comment add"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["comment set"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the address for comment.")
    parser.add_argument("comment", metavar="COMMENT", help="the comment to print when hit.")
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        comms = ContextCommand.context_comments.get(args.location, [])
        ContextCommand.context_comments[args.location] = comms + [args.comment]
        return


@register_command
class CommentLsCommand(CommentCommand):
    """List the comments."""
    _cmdline_ = "comment list"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["comment ls"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        if not ContextCommand.context_comments:
            warn("Nothing to display")
            return
        for loc, comms in sorted(ContextCommand.context_comments.items()):
            for i, comm in enumerate(comms):
                gef_print("{:#x}: [{:3d}] {:s}".format(loc, i, comm))
        return


@register_command
class CommentRemoveCommand(CommentCommand):
    """Remove the specified comment."""
    _cmdline_ = "comment remove"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["comment del", "comment unset", "comment rm"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the address for comment.")
    parser.add_argument("index", metavar="INDEX", nargs="?", type=int,
                        help="the index of comment to remove. If omitted, all comments for that address will be deleted.")
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        if args.location not in ContextCommand.context_comments:
            err("Invalid location")
            return
        if args.index is None:
            del ContextCommand.context_comments[args.location]
        else:
            if args.index >= len(ContextCommand.context_comments[args.location]):
                err("Out of index")
                return
            ContextCommand.context_comments[args.location].pop(args.index)
            if len(ContextCommand.context_comments[args.location]) == 0:
                del ContextCommand.context_comments[args.location]
        return


@register_command
class CommentClearCommand(CommentCommand):
    """Clear all comments."""
    _cmdline_ = "comment clear"
    _category_ = "01-f. Debugging Support - Context Extension"
    _aliases_ = ["comment reset"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        ContextCommand.context_comments = {}
        return


@register_command
class VMMapCommand(GenericCommand, BufferingOutput):
    """Display a comprehensive layout of the virtual memory mapping."""
    _cmdline_ = "vmmap"
    _category_ = "02-c. Process Information - Memory/Section"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--outer", action="store_true",
                        help="display qemu-user's memory map instead of emulated process's memory map.")
    parser.add_argument("filter", metavar="FILTER", nargs="?", help="filter string.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} libc             # show only lines containing the string `libc`\n".format(_cmdline_)
    _example_ += "{:s} binary           # 'binary' means the area executable itself\n".format(_cmdline_)
    _example_ += "{:s} 0x555555577ab0   # show only lines included specified address\n".format(_cmdline_)
    _example_ += "{:s} --outer          # show qemu-user memory map; only valid in qemu-user mode".format(_cmdline_)

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("kgdb",))
    def do_invoke(self, args):
        if is_qemu_system() or is_vmware():
            info("Redirect to pagewalk (args are ignored)")
            gdb.execute("pagewalk")
            return

        if args.outer and not is_qemu_user():
            err("Unsupported `--outer` option in this gdb mode")
            return

        if is_qemu_user():
            # the memory map may be changed, so retry memory exploring in get_process_maps()
            Cache.reset_gef_caches(all=True)

        vmmap = ProcessMap.get_process_maps(args.outer)
        if not vmmap:
            for line in gdb.execute("info files", to_string=True).splitlines():
                if line.startswith("Symbols from"):
                    break
            else:
                err("Missing info about architecture. Please set: `file /path/to/target_binary`")
            err("No address mapping information found")
            return

        self.out = []
        if not Config.get_gef_setting("gef.disable_color"):
            self.show_legend()

        headers = ["Start", "End", "Size", "Offset", "Perm", "Path"]
        memalign_size = 8 if args.outer else AddressUtil.get_memory_alignment()
        legend = "{:{w}s} {:{w}s} {:{w}s} {:{w}s} {:4s} {:s}".format(*headers, w=memalign_size * 2 + 2)
        self.out.append(Color.colorify(legend, Config.get_gef_setting("theme.table_heading")))

        for entry in vmmap:
            if not args.filter:
                self.dump_entry(entry, args.outer)
                continue
            if args.filter == "binary" and Path.get_filepath(append_proc_root_prefix=False) == entry.path:
                self.dump_entry(entry, args.outer)
            elif args.filter in entry.path:
                self.dump_entry(entry, args.outer)
            elif self.is_integer(args.filter):
                addr = int(args.filter, 0)
                if addr >= entry.page_start and addr < entry.page_end:
                    self.dump_entry(entry, args.outer)

        if is_qemu_user() and not args.outer:
            if ProcessMap.__gef_use_info_proc_mappings__ is False:
                self.info("Searched from auxv, registers and stack values. There may be areas that cannot be detected.")
                self.info("Permission is based on ELF header or default value `rw-`. Dynamic permission changes cannot be detected.")

        self.print_output(args, term=True)
        return

    def dump_entry(self, entry, outer):
        line_color = ""
        if entry.path.startswith("[stack]"):
            line_color = Config.get_gef_setting("theme.address_stack")
        elif entry.path.startswith("[heap]"):
            line_color = Config.get_gef_setting("theme.address_heap")
        elif entry.permission.value & Permission.EXECUTE:
            line_color = Config.get_gef_setting("theme.address_code")
        elif entry.permission.value & Permission.WRITE:
            line_color = Config.get_gef_setting("theme.address_writable")
        elif entry.permission.value & Permission.READ:
            line_color = Config.get_gef_setting("theme.address_readonly")
        elif entry.permission.value == Permission.NONE:
            line_color = Config.get_gef_setting("theme.address_valid_but_none")

        if entry.permission.value == (Permission.READ | Permission.WRITE | Permission.EXECUTE):
            line_color += " " + Config.get_gef_setting("theme.address_rwx")

        lines = []
        # if qemu-xxx(32bit arch) runs on x86-64 machine, memalign_size does not match
        # AddressUtil.get_memory_alignment()
        memalign_size = 8 if outer else None
        lines.append(Color.colorify(AddressUtil.format_address(entry.page_start, memalign_size, long_fmt=True), line_color))
        lines.append(Color.colorify(AddressUtil.format_address(entry.page_end, memalign_size, long_fmt=True), line_color))
        lines.append(Color.colorify(AddressUtil.format_address(entry.size, memalign_size, long_fmt=True), line_color))
        lines.append(Color.colorify(AddressUtil.format_address(entry.offset, memalign_size, long_fmt=True), line_color))
        lines.append(Color.colorify(str(entry.permission), line_color))
        lines.append(Color.colorify(entry.path, line_color))
        line = " ".join(lines)

        # register info
        register_hints = []
        for regname in current_arch.all_registers:
            regvalue = get_register(regname)
            if entry.page_start <= regvalue < entry.page_end:
                register_hints.append(regname)
        if register_hints:
            m = " {:s} {:s}".format(LEFT_ARROW, ", ".join(list(register_hints)))
            registers_color = Config.get_gef_setting("theme.dereference_register_value")
            line += Color.colorify(m, registers_color)

        self.out.append(line)
        return

    def show_legend(self):
        self.out.append("[ Legend:  {} | {} | {} | {} | {} | {} | {} ]".format(
            Color.colorify("Code", Config.get_gef_setting("theme.address_code")),
            Color.colorify("Heap", Config.get_gef_setting("theme.address_heap")),
            Color.colorify("Stack", Config.get_gef_setting("theme.address_stack")),
            Color.colorify("Writable", Config.get_gef_setting("theme.address_writable")),
            Color.colorify("ReadOnly", Config.get_gef_setting("theme.address_readonly")),
            Color.colorify("None", Config.get_gef_setting("theme.address_valid_but_none")),
            Color.colorify("RWX", Config.get_gef_setting("theme.address_rwx")),
        ))
        return

    def is_integer(self, n):
        try:
            int(n, 0)
        except ValueError:
            return False
        return True


@register_command
class XFilesCommand(GenericCommand):
    """Display all libraries (and sections) loaded by binary."""
    _cmdline_ = "xfiles"
    _category_ = "02-c. Process Information - Memory/Section"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("filter", metavar="FILTER", nargs="*", help="regex filter string.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} libc\n".format(_cmdline_)
    _example_ += "{:s} got plt\n".format(_cmdline_)
    _example_ += "{:s} IO_vtables".format(_cmdline_)

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        headers = ["Start", "End", "Name", "File"]
        width = AddressUtil.get_format_address_width()
        legend = "{:{w:d}s} {:{w:d}s} {:<21s} {:s}".format(*headers, w=width)
        gef_print(Color.colorify(legend, Config.get_gef_setting("theme.table_heading")))

        for xfile in ProcessMap.get_info_files():
            lines = []
            lines.append(str(ProcessMap.lookup_address(xfile.zone_start)))
            lines.append(str(ProcessMap.lookup_address(xfile.zone_end)))
            lines.append("{:<21s}".format(xfile.name))
            lines.append(xfile.filename)
            line = " ".join(lines)

            if not args.filter:
                gef_print(line)
            else:
                for filt in args.filter:
                    if re.search(filt, line):
                        gef_print(line)
                        break
        return


@register_command
class XInfoCommand(GenericCommand):
    """Retrieve and display runtime information for the location(s) given as parameter."""
    _cmdline_ = "xinfo"
    _category_ = "02-c. Process Information - Memory/Section"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", nargs="*", type=AddressUtil.parse_address,
                        help="the memory address to show the information. (default: current_arch.pc)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $pc".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def xinfo(self, address):
        addr = ProcessMap.lookup_address(address)
        if not addr.valid:
            warn("Cannot reach {:#x} in memory space".format(address))
            return

        gdb.execute("vmmap {:#x}".format(address))

        if addr.section:
            page_start = ProcessMap.lookup_address(addr.section.page_start)
            gef_print("Offset (from mapped):  {!s} + {:#x}".format(page_start, addr.value - addr.section.page_start))

            if addr.section.path and addr.section.path.startswith("/"):
                base_start = ProcessMap.lookup_address(ProcessMap.get_section_base_address(addr.section.path))
                gef_print("Offset (from base):    {!s} + {:#x}".format(base_start, addr.value - base_start.section.page_start))

        if addr.info:
            zone_start = ProcessMap.lookup_address(addr.info.zone_start)
            gef_print("Offset (from segment): {!s} ({:s}) + {:#x}".format(zone_start, addr.info.name, addr.value - addr.info.zone_start))

        sym = Symbol.get_symbol_string(address)
        if sym:
            msg = "Symbol:                {:s}".format(sym.strip())
            gef_print(msg)

        if addr.section and addr.section.inode:
            gef_print("Inode:                 {:d}".format(addr.section.inode))

        return

    def xinfo_kernel(self, address):
        ret = gdb.execute("pagewalk --vrange {:#x} --no-pager --quiet".format(address), to_string=True)
        ret = [x for x in ret.splitlines() if not Color.remove_color(x).startswith(("---", "[+]"))]

        if not ret:
            err("Not found")
            return

        gef_print("\n".join(ret))

        if ret[-1].startswith("0x"):
            virt, phys, *_ = ret[-1].split()
            vstart = int(virt.split("-")[0], 16)
            pstart = int(phys.split("-")[0], 16)
            offset = address - vstart
            gef_print("Offset (from virt mapped):  {:#x} + {:#x}".format(vstart, offset))
            gef_print("Offset (from phys mapped):  {:#x} + {:#x}".format(pstart, offset))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("kgdb",))
    def do_invoke(self, args):
        if args.location == []:
            locations = [current_arch.pc]
        else:
            locations = args.location

        # kernel xinfo
        if is_qemu_system() or is_vmware():
            for location in locations:
                gef_print(titlify("xinfo: {:#x}".format(location)))
                self.xinfo_kernel(location)
            return

        # userland xinfo
        for location in locations:
            try:
                gef_print(titlify("xinfo: {:#x}".format(location)))
                self.xinfo(location)
            except gdb.error as gdb_error:
                err(str(gdb_error))
        return


@register_command
class XorMemoryCommand(GenericCommand):
    """The base command to XOR a block of memory."""
    _cmdline_ = "xor-memory"
    _category_ = "03-d. Memory - Calculation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("display")
    subparsers.add_parser("patch")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=True)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        self.usage()
        return


@register_command
class XorMemoryDisplayCommand(GenericCommand):
    """Display a block of memory by xor-ing each byte with specified key."""
    _cmdline_ = "xor-memory display"
    _category_ = "03-d. Memory - Calculation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the address of data to xor.")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address,
                        help="the size of data to xor.")
    parser.add_argument("key", metavar="KEY", type=lambda x: bytes.fromhex(x),
                        help="the data to xor as key.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $sp 16 41414141".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        start_addr = args.location
        end_addr = args.location + args.size
        try:
            block = read_memory(start_addr, args.size)
        except gdb.MemoryError:
            err("Failed to read memory")
            return
        info("Displaying XOR-ing {:#x}-{:#x} with {:s}".format(start_addr, end_addr, repr(args.key)))

        gef_print(titlify("Original block"))
        gef_print(hexdump(block, base=start_addr))

        gef_print(titlify("XOR-ed block"))
        xored_block = xor(block, args.key)
        gef_print(hexdump(xored_block, base=start_addr))
        return


@register_command
class XorMemoryPatchCommand(GenericCommand):
    """Patch a block of memory by xor-ing each byte with specified key."""
    _cmdline_ = "xor-memory patch"
    _category_ = "03-d. Memory - Calculation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the address of data to xor.")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address,
                        help="the size of data to xor.")
    parser.add_argument("key", metavar="KEY", type=lambda x: bytes.fromhex(x),
                        help="the data to xor as key.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $sp 16 41414141".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        start_addr = args.location
        end_addr = args.location + args.size
        try:
            block = read_memory(start_addr, args.size)
        except gdb.MemoryError:
            err("Failed to read memory")
            return
        info("Patching XOR-ing {:#x}-{:#x} with '{:s}'".format(start_addr, end_addr, repr(args.key)))
        xored_block = xor(block, args.key)
        gdb.execute("patch hex {:#x} {:s}".format(start_addr, xored_block.hex()))
        return


@register_command
class PatternCommand(GenericCommand):
    """The base command to create or search a De Bruijn cyclic pattern (used pwntools)."""
    _cmdline_ = "pattern"
    _category_ = "09-c. Misc - Generation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("create")
    subparsers.add_parser("search")
    _syntax_ = parser.format_help()

    def __init__(self, *args, **kwargs):
        super().__init__(prefix=True)
        self.add_setting("length", 1024, "Initial length of a cyclic buffer to generate")
        return

    @parse_args
    def do_invoke(self, args):
        self.usage()
        return


@register_command
class PatternCreateCommand(GenericCommand):
    """Generate a de Bruijn cyclic pattern."""
    _cmdline_ = "pattern create"
    _category_ = "09-c. Misc - Generation"
    _aliases_ = ["pattc"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-c", "--charset", help="the charset of pattern. (default: abc..z)")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address, nargs="?",
                        help="the size of pattern. (default: 1024)")
    _syntax_ = parser.format_help()

    @staticmethod
    def de_bruijn(alphabet, n):
        """De Bruijn sequence for alphabet and subsequences of length n (for compat. w/ pwnlib)."""
        k = len(alphabet)
        a = [0] * k * n

        def db(t, p):
            if t > n:
                if n % p == 0:
                    for j in range(1, p + 1):
                        yield alphabet[a[j]]
            else:
                a[t] = a[t - p]
                for c in db(t + 1, p):
                    yield c

                for j in range(a[t - p] + 1, k):
                    a[t] = j
                    for c in db(t + 1, t):
                        yield c

        return db(1, 1)

    @staticmethod
    def generate_cyclic_pattern(length, charset=None):
        """Create a `length` byte bytearray of a de Bruijn cyclic pattern."""
        if charset is None:
            charset = bytearray(b"abcdefghijklmnopqrstuvwxyz")
        elif isinstance(charset, str):
            charset = String.str2bytes(charset)

        cycle = AddressUtil.get_memory_alignment()
        return bytearray(itertools.islice(PatternCreateCommand.de_bruijn(charset, cycle), length))

    @parse_args
    def do_invoke(self, args):
        if args.size is None:
            size = Config.get_gef_setting("pattern.length")
        else:
            size = args.size

        info("Generating a pattern of {:d} bytes".format(size))
        pattern_str = String.gef_pystring(PatternCreateCommand.generate_cyclic_pattern(size, args.charset))
        gef_print(pattern_str)
        ok("Saved as '{:s}'".format(GefUtil.gef_convenience(pattern_str)))
        return


@register_command
class PatternSearchCommand(GenericCommand):
    """Search for the cyclic de Bruijn pattern generated by the `pattern create` command."""
    _cmdline_ = "pattern search"
    _category_ = "09-c. Misc - Generation"
    _aliases_ = ["patto"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-c", "--charset", help="the charset of pattern. (default: abc..z)")
    parser.add_argument("pattern", metavar="PATTERN", help="the pattern to offset search.")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address, nargs="?",
                        help="the size of pattern. (default: 0x10000)")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $pc\n".format(_cmdline_)
    _example_ += "{:s} 0x61616164\n".format(_cmdline_)
    _example_ += "{:s} aaab".format(_cmdline_)

    def search(self, tag, cyclic_pattern, pattern):
        gef_print(titlify(tag))

        def search_pattern(pattern):
            info("Searching {}".format(pattern))
            found = 0
            off = 0
            while found < 10:
                off = cyclic_pattern.find(pattern, off)
                if off == -1:
                    break
                ok("Found at offset {:d} ({:#x})".format(off, off))
                found += 1
                off += 1

            if found == 0:
                err("Not found")

            if found == 10:
                ok("...")
            return

        # little endian
        search_pattern(pattern)

        # big endian
        inv_pattern = pattern[::-1]
        if pattern != inv_pattern:
            search_pattern(inv_pattern)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.size is None:
            size = Config.get_gef_setting("pattern.length") * 64
        else:
            size = args.size

        cyclic_pattern = PatternCreateCommand.generate_cyclic_pattern(size, args.charset)
        pack = p32 if is_32bit() else p64

        # 1. check if it's a symbol (like "$sp")
        try:
            address = AddressUtil.parse_address(args.pattern)
            value = read_int_from_memory(address)
            self.search("As symbol (with dereference)", cyclic_pattern, pack(value))
        except gdb.error:
            pass

        # 2. check if it's a not symbol, but value (like "0x1337")
        try:
            value = AddressUtil.parse_address(args.pattern)
            self.search("As value (without dereference)", cyclic_pattern, pack(value))
        except gdb.error:
            pass

        # 3. plain text
        pattern = String.str2bytes(args.pattern)
        if set(pattern) - set(cyclic_pattern) == set():
            self.search("As string", cyclic_pattern, pattern)
        return


@register_command
class SigreturnCommand(GenericCommand):
    """Display stack values for sigreturn syscall."""
    _cmdline_ = "sigreturn"
    _category_ = "03-b. Memory - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the address interpreted as the beginning of a sigframe. (default: current_arch.sp)")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("wine",))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    def do_invoke(self, args):
        if args.location is None:
            base = current_arch.sp
        else:
            base = args.location

        if is_x86_64():
            sigreturn_defines = [
                "rt_sigframe.pretcode",
                "rt_sigframe.uc.uc_flags",
                "rt_sigframe.uc.uc_link",
                "rt_sigframe.uc.uc_stack.ss_sp",
                "rt_sigframe.uc.uc_stack.ss_flags|ss_size",
                "rt_sigframe.uc.uc_mcontext.r8",
                "rt_sigframe.uc.uc_mcontext.r9",
                "rt_sigframe.uc.uc_mcontext.r10",
                "rt_sigframe.uc.uc_mcontext.r11",
                "rt_sigframe.uc.uc_mcontext.r12",
                "rt_sigframe.uc.uc_mcontext.r13",
                "rt_sigframe.uc.uc_mcontext.r14",
                "rt_sigframe.uc.uc_mcontext.r15",
                "rt_sigframe.uc.uc_mcontext.rdi",
                "rt_sigframe.uc.uc_mcontext.rsi",
                "rt_sigframe.uc.uc_mcontext.rbp",
                "rt_sigframe.uc.uc_mcontext.rbx",
                "rt_sigframe.uc.uc_mcontext.rdx",
                "rt_sigframe.uc.uc_mcontext.rax",
                "rt_sigframe.uc.uc_mcontext.rcx",
                "rt_sigframe.uc.uc_mcontext.rsp",
                "rt_sigframe.uc.uc_mcontext.rip",
                "rt_sigframe.uc.uc_mcontext.rflags",
                "rt_sigframe.uc.uc_mcontext.cs|gs|fs|__pad0",
                "rt_sigframe.uc.uc_mcontext.err",
                "rt_sigframe.uc.uc_mcontext.trapno",
                "rt_sigframe.uc.uc_mcontext.oldmask",
                "rt_sigframe.uc.uc_mcontext.cr2",
                "rt_sigframe.uc.uc_mcontext.fpstate",
                "rt_sigframe.uc.uc_mcontext.reserved[8]",
                "rt_sigframe.uc.uc_sigmask",
                "rt_sigframe.info",
            ]
        elif is_x86_32():
            sigreturn_defines = [
                "sigframe.sc.gs",
                "sigframe.sc.fs",
                "sigframe.sc.es",
                "sigframe.sc.ds",
                "sigframe.sc.edi",
                "sigframe.sc.esi",
                "sigframe.sc.ebp",
                "sigframe.sc.esp",
                "sigframe.sc.ebx",
                "sigframe.sc.edx",
                "sigframe.sc.ecx",
                "sigframe.sc.eax",
                "sigframe.sc.trapno",
                "sigframe.sc.err",
                "sigframe.sc.eip",
                "sigframe.sc.cs",
                "sigframe.sc.eflags",
                "sigframe.sc.esp_at_signal",
                "sigframe.sc.ss",
                "sigframe.sc.fpstate",
                "sigframe.sc.oldmask",
                "sigframe.sc.cr2",
            ]
        elif is_arm32():
            sigreturn_defines = [
                "sigframe.uc.uc_flags",
                "sigframe.uc.uc_link",
                "sigframe.uc.uc_stack.ss_sp",
                "sigframe.uc.uc_stack.ss_flags",
                "sigframe.uc.uc_stack.ss_size",
                "sigframe.uc.uc_mcontext.trapno",
                "sigframe.uc.uc_mcontext.error_code",
                "sigframe.uc.uc_mcontext.oldmask",
                "sigframe.uc.uc_mcontext.arm_r0",
                "sigframe.uc.uc_mcontext.arm_r1",
                "sigframe.uc.uc_mcontext.arm_r2",
                "sigframe.uc.uc_mcontext.arm_r3",
                "sigframe.uc.uc_mcontext.arm_r4",
                "sigframe.uc.uc_mcontext.arm_r5",
                "sigframe.uc.uc_mcontext.arm_r6",
                "sigframe.uc.uc_mcontext.arm_r7",
                "sigframe.uc.uc_mcontext.arm_r8",
                "sigframe.uc.uc_mcontext.arm_r9",
                "sigframe.uc.uc_mcontext.arm_r10",
                "sigframe.uc.uc_mcontext.arm_fp",
                "sigframe.uc.uc_mcontext.arm_ip",
                "sigframe.uc.uc_mcontext.arm_sp",
                "sigframe.uc.uc_mcontext.arm_lr",
                "sigframe.uc.uc_mcontext.arm_pc",
                "sigframe.uc.uc_mcontext.arm_cpsr",
                "sigframe.uc.uc_mcontext.fault_address",
                "sigframe.uc.uc_sigmask",
            ]
        elif is_arm64():
            sigreturn_defines = [
                "rt_sigframe.info+0x00",
                "rt_sigframe.info+0x08",
                "rt_sigframe.info+0x10",
                "rt_sigframe.info+0x18",
                "rt_sigframe.info+0x20",
                "rt_sigframe.info+0x28",
                "rt_sigframe.info+0x30",
                "rt_sigframe.info+0x38",
                "rt_sigframe.info+0x40",
                "rt_sigframe.info+0x48",
                "rt_sigframe.info+0x50",
                "rt_sigframe.info+0x58",
                "rt_sigframe.info+0x60",
                "rt_sigframe.info+0x68",
                "rt_sigframe.info+0x70",
                "rt_sigframe.info+0x78",
                "rt_sigframe.uc.uc_flags",
                "rt_sigframe.uc.uc_link",
                "rt_sigframe.uc.uc_stack.ss_sp",
                "rt_sigframe.uc.uc_stack.ss_flags",
                "rt_sigframe.uc.uc_stack.ss_size",
                "rt_sigframe.uc.uc_stack.__unused",
                "rt_sigframe.uc.uc_sigmask",
                "rt_sigframe.uc.__unused[120]+0x00",
                "rt_sigframe.uc.__unused[120]+0x08",
                "rt_sigframe.uc.__unused[120]+0x10",
                "rt_sigframe.uc.__unused[120]+0x18",
                "rt_sigframe.uc.__unused[120]+0x20",
                "rt_sigframe.uc.__unused[120]+0x28",
                "rt_sigframe.uc.__unused[120]+0x30",
                "rt_sigframe.uc.__unused[120]+0x38",
                "rt_sigframe.uc.__unused[120]+0x40",
                "rt_sigframe.uc.__unused[120]+0x48",
                "rt_sigframe.uc.__unused[120]+0x50",
                "rt_sigframe.uc.__unused[120]+0x58",
                "rt_sigframe.uc.__unused[120]+0x60",
                "rt_sigframe.uc.__unused[120]+0x68",
                "rt_sigframe.uc.__unused[120]+0x70",
                "rt_sigframe.uc.uc_mcontext.fault_address",
                "rt_sigframe.uc.uc_mcontext.regs[31].x0",
                "rt_sigframe.uc.uc_mcontext.regs[31].x1",
                "rt_sigframe.uc.uc_mcontext.regs[31].x2",
                "rt_sigframe.uc.uc_mcontext.regs[31].x3",
                "rt_sigframe.uc.uc_mcontext.regs[31].x4",
                "rt_sigframe.uc.uc_mcontext.regs[31].x5",
                "rt_sigframe.uc.uc_mcontext.regs[31].x6",
                "rt_sigframe.uc.uc_mcontext.regs[31].x7",
                "rt_sigframe.uc.uc_mcontext.regs[31].x8",
                "rt_sigframe.uc.uc_mcontext.regs[31].x9",
                "rt_sigframe.uc.uc_mcontext.regs[31].x10",
                "rt_sigframe.uc.uc_mcontext.regs[31].x11",
                "rt_sigframe.uc.uc_mcontext.regs[31].x12",
                "rt_sigframe.uc.uc_mcontext.regs[31].x13",
                "rt_sigframe.uc.uc_mcontext.regs[31].x14",
                "rt_sigframe.uc.uc_mcontext.regs[31].x15",
                "rt_sigframe.uc.uc_mcontext.regs[31].x16",
                "rt_sigframe.uc.uc_mcontext.regs[31].x17",
                "rt_sigframe.uc.uc_mcontext.regs[31].x18",
                "rt_sigframe.uc.uc_mcontext.regs[31].x19",
                "rt_sigframe.uc.uc_mcontext.regs[31].x20",
                "rt_sigframe.uc.uc_mcontext.regs[31].x21",
                "rt_sigframe.uc.uc_mcontext.regs[31].x22",
                "rt_sigframe.uc.uc_mcontext.regs[31].x23",
                "rt_sigframe.uc.uc_mcontext.regs[31].x24",
                "rt_sigframe.uc.uc_mcontext.regs[31].x25",
                "rt_sigframe.uc.uc_mcontext.regs[31].x26",
                "rt_sigframe.uc.uc_mcontext.regs[31].x27",
                "rt_sigframe.uc.uc_mcontext.regs[31].x28",
                "rt_sigframe.uc.uc_mcontext.regs[31].x29",
                "rt_sigframe.uc.uc_mcontext.regs[31].x30",
                "rt_sigframe.uc.uc_mcontext.sp",
                "rt_sigframe.uc.uc_mcontext.pc",
                "rt_sigframe.uc.uc_mcontext.pstate",
            ]

        max_name_width = max(len(x) for x in sigreturn_defines)

        out = []
        for i, tag in enumerate(sigreturn_defines):
            line = DereferenceCommand.pprint_dereferenced(base, i, tag.ljust(max_name_width))
            out.append(line)

        gef_print("\n".join(out), less=not args.no_pager)
        return


@register_command
class SropHintCommand(GenericCommand):
    """Hint for sigreturn oriented programming."""
    _cmdline_ = "srop-hint"
    _category_ = "09-d. Misc - Show Example"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", "--arch", choices=["x86", "x64", "arm", "aarch64"],
                        help="the target architecture.")
    _syntax_ = parser.format_help()

    @parse_args
    @exclude_specific_gdb_mode(mode=("wine",))
    def do_invoke(self, args):
        if args.arch is None:
            if is_x86_64():
                mode = "x64"
            elif is_x86_32():
                mode = "x86"
            elif is_arm32():
                mode = "arm"
            elif is_arm64():
                mode = "aarch64"
            else:
                mode = "x64" # default
        else:
            mode = args.arch

        s = ""
        if mode == "x64":
            s += 'exp  = struct.pack("<Q", syscall)    # rax = 15 (rt_sigreturn)\n'
            s += 'exp += struct.pack("<Q", 0xcafebabe) # rt_sigframe.pretcode\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_flags\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_link\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_stack.ss_sp\n'
            s += 'exp += struct.pack("<I", 0x0)        # rt_sigframe.uc.uc_stack.ss_flags\n'
            s += 'exp += struct.pack("<I", 0x0)        # rt_sigframe.uc.uc_stack.ss_size\n'
            s += 'exp += struct.pack("<Q", 0x08)       # rt_sigframe.uc.uc_mcontext.r8\n'
            s += 'exp += struct.pack("<Q", 0x09)       # rt_sigframe.uc.uc_mcontext.r9\n'
            s += 'exp += struct.pack("<Q", 0x0a)       # rt_sigframe.uc.uc_mcontext.r10\n'
            s += 'exp += struct.pack("<Q", 0x0b)       # rt_sigframe.uc.uc_mcontext.r11\n'
            s += 'exp += struct.pack("<Q", 0x0c)       # rt_sigframe.uc.uc_mcontext.r12\n'
            s += 'exp += struct.pack("<Q", 0x0d)       # rt_sigframe.uc.uc_mcontext.r13\n'
            s += 'exp += struct.pack("<Q", 0x0e)       # rt_sigframe.uc.uc_mcontext.r14\n'
            s += 'exp += struct.pack("<Q", 0x0f)       # rt_sigframe.uc.uc_mcontext.r15\n'
            s += 'exp += struct.pack("<Q", 0x07)       # rt_sigframe.uc.uc_mcontext.rdi\n'
            s += 'exp += struct.pack("<Q", 0x06)       # rt_sigframe.uc.uc_mcontext.rsi\n'
            s += 'exp += struct.pack("<Q", 0x05)       # rt_sigframe.uc.uc_mcontext.rbp\n'
            s += 'exp += struct.pack("<Q", 0x02)       # rt_sigframe.uc.uc_mcontext.rbx\n'
            s += 'exp += struct.pack("<Q", 0x04)       # rt_sigframe.uc.uc_mcontext.rdx\n'
            s += 'exp += struct.pack("<Q", 0x01)       # rt_sigframe.uc.uc_mcontext.rax\n'
            s += 'exp += struct.pack("<Q", 0x03)       # rt_sigframe.uc.uc_mcontext.rcx\n'
            s += 'exp += struct.pack("<Q", 0xdeadface) # rt_sigframe.uc.uc_mcontext.rsp\n'
            s += 'exp += struct.pack("<Q", 0xdeadbeef) # rt_sigframe.uc.uc_mcontext.rip\n'
            s += 'exp += struct.pack("<Q", 0x00)       # rt_sigframe.uc.uc_mcontext.rflags\n'
            s += 'exp += struct.pack("<H", 0x33)       # rt_sigframe.uc.uc_mcontext.cs\n'
            s += 'exp += struct.pack("<H", 0x00)       # rt_sigframe.uc.uc_mcontext.gs\n'
            s += 'exp += struct.pack("<H", 0x00)       # rt_sigframe.uc.uc_mcontext.fs\n'
            s += 'exp += struct.pack("<H", 0x00)       # rt_sigframe.uc.uc_mcontext.__pad0\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_mcontext.err\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_mcontext.trapno\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_mcontext.oldmask\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_mcontext.cr2\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_mcontext.fpstate # fpu/xmm are not restored if NULL\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_mcontext.reserved[8]\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_sigmask\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.info\n'
        elif mode == "x86":
            s += 'exp  = struct.pack("<I", syscall)    # eax = 119 (sigreturn)\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.gs\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.fs\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.es\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.ds\n'
            s += 'exp += struct.pack("<I", 0x7)        # sigframe.sc.edi\n'
            s += 'exp += struct.pack("<I", 0x6)        # sigframe.sc.esi\n'
            s += 'exp += struct.pack("<I", 0x5)        # sigframe.sc.ebp\n'
            s += 'exp += struct.pack("<I", 0xdeadface) # sigframe.sc.esp\n'
            s += 'exp += struct.pack("<I", 0x2)        # sigframe.sc.ebx\n'
            s += 'exp += struct.pack("<I", 0x4)        # sigframe.sc.edx\n'
            s += 'exp += struct.pack("<I", 0x3)        # sigframe.sc.ecx\n'
            s += 'exp += struct.pack("<I", 0x1)        # sigframe.sc.eax\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.trapno\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.err\n'
            s += 'exp += struct.pack("<I", 0xdeadbeef) # sigframe.sc.eip\n'
            s += 'exp += struct.pack("<I", 0x23)       # sigframe.sc.cs # use 0x73 if 32bit native machine\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.eflags\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.esp_at_signal\n'
            s += 'exp += struct.pack("<I", 0x2b)       # sigframe.sc.ss # use 0x7b if 32bit native machine\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.fpstate # fpu/xmm are not restored if NULL\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.oldmask\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.sc.cr2\n'
            s += '\n'
        elif mode == "arm":
            s += 'exp += struct.pack("<I", pop_r7_pc)  # pop {r7, pc};\n'
            s += 'exp += struct.pack("<I", 119)        # r7 = 119 (sigreturn)\n'
            s += 'exp += struct.pack("<I", call_svc)   #\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_flags\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_link\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_stack.ss_sp\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_stack.ss_flags\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_stack.ss_size\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_mcontext.trapno\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_mcontext.error_code\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_mcontext.oldmask\n'
            s += 'exp += struct.pack("<I", 0x00)       # sigframe.uc.uc_mcontext.arm_r0\n'
            s += 'exp += struct.pack("<I", 0x01)       # sigframe.uc.uc_mcontext.arm_r1\n'
            s += 'exp += struct.pack("<I", 0x02)       # sigframe.uc.uc_mcontext.arm_r2\n'
            s += 'exp += struct.pack("<I", 0x03)       # sigframe.uc.uc_mcontext.arm_r3\n'
            s += 'exp += struct.pack("<I", 0x04)       # sigframe.uc.uc_mcontext.arm_r4\n'
            s += 'exp += struct.pack("<I", 0x05)       # sigframe.uc.uc_mcontext.arm_r5\n'
            s += 'exp += struct.pack("<I", 0x06)       # sigframe.uc.uc_mcontext.arm_r6\n'
            s += 'exp += struct.pack("<I", 0x07)       # sigframe.uc.uc_mcontext.arm_r7\n'
            s += 'exp += struct.pack("<I", 0x08)       # sigframe.uc.uc_mcontext.arm_r8\n'
            s += 'exp += struct.pack("<I", 0x09)       # sigframe.uc.uc_mcontext.arm_r9\n'
            s += 'exp += struct.pack("<I", 0x0a)       # sigframe.uc.uc_mcontext.arm_r10\n'
            s += 'exp += struct.pack("<I", 0x0b)       # sigframe.uc.uc_mcontext.arm_fp\n'
            s += 'exp += struct.pack("<I", 0x0c)       # sigframe.uc.uc_mcontext.arm_ip\n'
            s += 'exp += struct.pack("<I", 0xdeadface) # sigframe.uc.uc_mcontext.arm_sp\n'
            s += 'exp += struct.pack("<I", 0x0d)       # sigframe.uc.uc_mcontext.arm_lr\n'
            s += 'exp += struct.pack("<I", 0xdeadbeef) # sigframe.uc.uc_mcontext.arm_pc\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_mcontext.arm_cpsr\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_mcontext.fault_address\n'
            s += 'exp += struct.pack("<I", 0x0)        # sigframe.uc.uc_sigmask\n'
        elif mode == "aarch64":
            s += 'exp += struct.pack("<Q", ldp_x8_x9)  # ldp x8, x9, [sp], #16; ret x9;\n'
            s += 'exp += struct.pack("<Q", 139)        # x8 = 139\n'
            s += 'exp += struct.pack("<Q", call_svc)   # \n'
            s += 'exp += struct.pack("<I", 0x0)*32     # rt_sigframe.info\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_flags\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_link\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_stack.ss_sp\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_stack.ss_flags\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_stack.ss_size\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_stack.__unused\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_sigmask\n'
            s += 'exp += struct.pack("<B", 0x0)*120    # rt_sigframe.uc.__unused[120]\n'
            s += 'exp += struct.pack("<Q", 0x0)        # rt_sigframe.uc.uc_mcontext.fault_address\n'
            s += 'exp += struct.pack("<Q", 0x00)       # rt_sigframe.uc.uc_mcontext.regs[31].x0\n'
            s += 'exp += struct.pack("<Q", 0x01)       # rt_sigframe.uc.uc_mcontext.regs[31].x1\n'
            s += 'exp += struct.pack("<Q", 0x02)       # rt_sigframe.uc.uc_mcontext.regs[31].x2\n'
            s += 'exp += struct.pack("<Q", 0x03)       # rt_sigframe.uc.uc_mcontext.regs[31].x3\n'
            s += 'exp += struct.pack("<Q", 0x04)       # rt_sigframe.uc.uc_mcontext.regs[31].x4\n'
            s += 'exp += struct.pack("<Q", 0x05)       # rt_sigframe.uc.uc_mcontext.regs[31].x5\n'
            s += 'exp += struct.pack("<Q", 0x06)       # rt_sigframe.uc.uc_mcontext.regs[31].x6\n'
            s += 'exp += struct.pack("<Q", 0x07)       # rt_sigframe.uc.uc_mcontext.regs[31].x7\n'
            s += 'exp += struct.pack("<Q", 0x08)       # rt_sigframe.uc.uc_mcontext.regs[31].x8\n'
            s += 'exp += struct.pack("<Q", 0x09)       # rt_sigframe.uc.uc_mcontext.regs[31].x9\n'
            s += 'exp += struct.pack("<Q", 0x0a)       # rt_sigframe.uc.uc_mcontext.regs[31].x10\n'
            s += 'exp += struct.pack("<Q", 0x0b)       # rt_sigframe.uc.uc_mcontext.regs[31].x11\n'
            s += 'exp += struct.pack("<Q", 0x0c)       # rt_sigframe.uc.uc_mcontext.regs[31].x12\n'
            s += 'exp += struct.pack("<Q", 0x0d)       # rt_sigframe.uc.uc_mcontext.regs[31].x13\n'
            s += 'exp += struct.pack("<Q", 0x0e)       # rt_sigframe.uc.uc_mcontext.regs[31].x14\n'
            s += 'exp += struct.pack("<Q", 0x0f)       # rt_sigframe.uc.uc_mcontext.regs[31].x15\n'
            s += 'exp += struct.pack("<Q", 0x10)       # rt_sigframe.uc.uc_mcontext.regs[31].x16\n'
            s += 'exp += struct.pack("<Q", 0x11)       # rt_sigframe.uc.uc_mcontext.regs[31].x17\n'
            s += 'exp += struct.pack("<Q", 0x12)       # rt_sigframe.uc.uc_mcontext.regs[31].x18\n'
            s += 'exp += struct.pack("<Q", 0x13)       # rt_sigframe.uc.uc_mcontext.regs[31].x19\n'
            s += 'exp += struct.pack("<Q", 0x14)       # rt_sigframe.uc.uc_mcontext.regs[31].x20\n'
            s += 'exp += struct.pack("<Q", 0x15)       # rt_sigframe.uc.uc_mcontext.regs[31].x21\n'
            s += 'exp += struct.pack("<Q", 0x16)       # rt_sigframe.uc.uc_mcontext.regs[31].x22\n'
            s += 'exp += struct.pack("<Q", 0x17)       # rt_sigframe.uc.uc_mcontext.regs[31].x23\n'
            s += 'exp += struct.pack("<Q", 0x18)       # rt_sigframe.uc.uc_mcontext.regs[31].x24\n'
            s += 'exp += struct.pack("<Q", 0x19)       # rt_sigframe.uc.uc_mcontext.regs[31].x25\n'
            s += 'exp += struct.pack("<Q", 0x1a)       # rt_sigframe.uc.uc_mcontext.regs[31].x26\n'
            s += 'exp += struct.pack("<Q", 0x1b)       # rt_sigframe.uc.uc_mcontext.regs[31].x27\n'
            s += 'exp += struct.pack("<Q", 0x1c)       # rt_sigframe.uc.uc_mcontext.regs[31].x28\n'
            s += 'exp += struct.pack("<Q", 0x1d)       # rt_sigframe.uc.uc_mcontext.regs[31].x29\n'
            s += 'exp += struct.pack("<Q", 0x1e)       # rt_sigframe.uc.uc_mcontext.regs[31].x30\n'
            s += 'exp += struct.pack("<Q", 0xdeadface) # rt_sigframe.uc.uc_mcontext.sp\n'
            s += 'exp += struct.pack("<Q", 0xdeadbeef) # rt_sigframe.uc.uc_mcontext.pc\n'
            s += 'exp += struct.pack("<Q", 0x00)       # rt_sigframe.uc.uc_mcontext.pstate\n'
        gef_print(s.rstrip())
        return


@register_command
class Ret2dlHintCommand(GenericCommand):
    """Hint for return-to-dl-resolve."""
    _cmdline_ = "ret2dl-hint"
    _category_ = "09-d. Misc - Show Example"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        s = ""
        s += "  +-.got/.got.plt @ itself---------+\n"
        s += "  | GOT[0]: _DYNAMIC               |\n"
        s += "  | GOT[1]: link_map               |\n"
        s += "  | GOT[2]: _dl_runtime_resolve@ld |\n"
        s += "  | GOT[3]: func1                  |\n"
        s += "  | GOT[4]: func2                  |\n"
        s += "  | GOT[5]: func3                  |\n"
        s += "  | ...                            |\n"
        s += "  +--------------------------------+\n"
        s += "\n"
        s += "If `link_map` and `_dl_runtime_resolve` are non-zero, just use them.\n"
        s += "If they are zero, you have to resolve them from DT_DEBUG entry of _DYNAMIC.\n"
        s += "\n"
        s += "  +-_DYNAMIC @ itself--------+     +---->+-r_debug----------+\n"
        s += "  | QWORD tag                |     |     | QWORD r_version  |\n"
        s += "  | QWORD value              |     |     | QWORD link_map   |<--- HERE\n"
        s += "  +--------------------------+     |     | QWORD r_brk      |\n"
        s += "  | ...                      |     |     | QWORD r_ldbase   |\n"
        s += "  +--------------------------+     |     +------------------+\n"
        s += "  | QWORD tag(0x15:DT_DEBUG) |     |\n"
        s += "  | QWORD value              |-----+\n"
        s += "  +--------------------------+\n"
        s += "\n"
        s += "  (binary itself)              (libc.so)                    (ld-linux.so)\n"
        s += "  +-link_map-----+     +------>+-link_map-----+     +------>+-link_map-----+\n"
        s += "  | QWORD l_addr |     |       | QWORD l_addr |     |       | QWORD l_addr |\n"
        s += "  | QWORD l_name |     |       | QWORD l_name |     |       | QWORD l_name |\n"
        s += "  | QWORD l_ld   |     |       | QWORD l_ld   |---+ |       | QWORD l_ld   |\n"
        s += "  | QWORD l_next |-----+       | QWORD l_next |---|-+       | QWORD l_next |\n"
        s += "  | QWORD l_prev |             | QWORD l_prev |   |         | QWORD l_prev |\n"
        s += "  +--------------+             +--------------+   |         +--------------+\n"
        s += "                                                  |\n"
        s += "        +-----------------------------------------+\n"
        s += "        |\n"
        s += "        +--->+-_DYNAMIC @ libc----------+     +---->+-.got/.got.plt @ libc-----------+\n"
        s += "             | QWORD tag                |     |     | GOT[0]: _DYNAMIC               |\n"
        s += "             | QWORD value              |     |     | GOT[1]: link_map               |\n"
        s += "             +--------------------------+     |     | GOT[2]: _dl_runtime_resolve@ld |<--- HERE\n"
        s += "             | ...                      |     |     | GOT[3]: func1                  |\n"
        s += "             +--------------------------+     |     | GOT[4]: func2                  |\n"
        s += "             | QWORD tag(0x3:DT_PLTGOT) |     |     | GOT[5]: func3                  |\n"
        s += "             | QWORD value              |-----+     | ...                            |\n"
        s += "             +--------------------------+           +--------------------------------+\n"
        s += "\n"
        s += "\n"
        s += "  _dl_runtime_resolve@.plt.got(link_map, reloc_arg)\n"
        s += "    -> _dl_fixup@ld(link_map, reloc_arg)\n"
        s += "                                   |\n"
        s += "                                   |\n"
        if is_32bit():
            s = s.replace("QWORD", "DWORD")
            s += "  +-------reloc_arg as offset------+\n"
            s += "  |\n"
            s += "  |      +-.rel.plt-------------------------+                        +-.dynsym------------+          +-.dynstr---------+\n"
            s += "  |      | DWORD r_offset                   |                        | DWORD st_name      |          | char[] symbol   |\n"
            s += "  |      | DWORD r_info                     |                        | DWORD st_value     |     +--->| char[] symbol   |\n"
            s += "  |      +----------------------------------+                        | DWORD st_size      |     |    | char[] symbol   |\n"
            s += "  +----->| DWORD r_offset(=writable area)   |  (r_info>>8) * 0x10    | BYTE  st_info      |     |    | char[] symbol   |\n"
            s += "         | DWORD r_info(=(dynsym_idx<<8)|7) |------------+           | BYTE  st_other     |     |    | ...             |\n"
            s += "         +----------------------------------+            |           | WORD  st_shndx     |     |    +-----------------+\n"
            s += "         | ...                              |            +---------->+--------------------+     |\n"
            s += "         +----------------------------------+                        | DWORD st_name      |-----+\n"
            s += "                                                                     | DWORD st_value     |\n"
            s += "                                                                     | DWORD st_size      |\n"
            s += "                                                                     | BYTE  st_info      |\n"
            s += "                                                                     | BYTE  st_other(=0) |\n"
            s += "                                                                     | WORD  st_shndx     |\n"
            s += "                                                                     +--------------------+\n"
            s += "                                                                     | ...                |\n"
            s += "                                                                     +--------------------+\n"
        else:
            s += "  +---reloc_arg * 0x18 as offset---+\n"
            s += "  |\n"
            s += "  |      +-.rela.plt------------------------+                        +-.dynsym------------+          +-.dynstr---------+\n"
            s += "  |      | QWORD r_offset                   |                        | DWORD st_name      |          | char[] symbol   |\n"
            s += "  |      | QWORD r_info                     |                        | BYTE  st_info      |     +--->| char[] symbol   |\n"
            s += "  |      | QWORD r_addend                   |                        | BYTE  st_other     |     |    | char[] symbol   |\n"
            s += "  +----->+----------------------------------+                        | WORD  st_shndx     |     |    | char[] symbol   |\n"
            s += "         | QWORD r_offset(=writable area)   |  (r_info>>32) * 0x18   | QWORD st_value     |     |    | ...             |\n"
            s += "         | QWORD r_info(=(dynsym_idx<<32)|7)|------------+           | QWORD st_size      |     |    +-----------------+\n"
            s += "         | QWORD r_addend                   |            +---------->+--------------------+     |\n"
            s += "         +----------------------------------+                        | DWORD st_name      |-----+\n"
            s += "         | ...                              |                        | BYTE  st_info      |\n"
            s += "         +----------------------------------+                        | BYTE  st_other(=0) |\n"
            s += "                                                                     | WORD  st_shndx     |\n"
            s += "                                                                     | QWORD st_value     |\n"
            s += "                                                                     | QWORD st_size      |\n"
            s += "                                                                     +--------------------+\n"
            s += "                                                                     | ...                |\n"
            s += "                                                                     +--------------------+\n"
        s += "\n"
        s += "Use `dynamic` and `link-map` to display the structure.\n"
        gef_print(s.rstrip())
        return


@register_command
class LinkMapCommand(GenericCommand):
    """Dump useful members of link_map with iterating."""
    _cmdline_ = "link-map"
    _category_ = "02-e. Process Information - Complex Structure Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-e", dest="elf_address", type=AddressUtil.parse_address,
                       help="the elf address to parse.")
    group.add_argument("-l", dest="link_map_address", type=AddressUtil.parse_address,
                       help="the link_map address to parse.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="verbose output.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}                   # dump itself\n".format(_cmdline_)
    _example_ += "{:s} -e 0x555555554000 # dump specified address as elf\n".format(_cmdline_)
    _example_ += "{:s} -l 0x7ffff7ffe2e0 # dump specified address as link_map".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def dump_link_map(self, link_map):
        if link_map is None:
            info("Not found link_map.")
            return

        info("link_map: {!s} [{!s}]".format(link_map, link_map.section.permission))

        # elf/link.h
        members = ["l_addr", "l_name", "l_ld", "l_next", "l_prev"]

        if self.verbose:
            # elf/elf.h
            # I assume that the glibc version can be identified.
            # Note that there is no link-map in static binaries, so there is no need to consider it.
            if get_libc_version() >= (2, 36):
                DT_NUM = 38
            else:
                DT_NUM = 35
            # Note that the number of elements in an array varies depending on the architecture.
            if is_arm64():
                DT_THISPROCNUM = 6
                ARCH_SPECIFIC_TABLE = DynamicCommand.DT_TABLE["arm64"]
            elif is_alpha():
                DT_THISPROCNUM = 1
                ARCH_SPECIFIC_TABLE = DynamicCommand.DT_TABLE["alpha"]
            elif is_mips32() or is_mips64() or is_mipsn32():
                DT_THISPROCNUM = 0x37
                ARCH_SPECIFIC_TABLE = DynamicCommand.DT_TABLE["mips"]
            elif is_ppc32():
                DT_THISPROCNUM = 2
                ARCH_SPECIFIC_TABLE = DynamicCommand.DT_TABLE["ppc32"]
            elif is_ppc64():
                DT_THISPROCNUM = 4
                ARCH_SPECIFIC_TABLE = DynamicCommand.DT_TABLE["ppc64"]
            elif is_sparc32() or is_sparc32plus() or is_sparc64():
                DT_THISPROCNUM = 2
                ARCH_SPECIFIC_TABLE = DynamicCommand.DT_TABLE["sparc"]
            else:
                DT_THISPROCNUM = 0
                ARCH_SPECIFIC_TABLE = {}
            # These values do not change between versions or architectures.
            DT_VERSIONTAGNUM = 16
            DT_EXTRANUM = 3
            DT_VALNUM = 12
            DT_ADDRNUM = 11

            # include/link.h
            l_info_length = DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM

            # include/link.h
            members += ["l_real", "l_ns", "l_libname"]
            for i in range(l_info_length):
                mb = "l_info[{:d}]".format(i)
                if i < DT_NUM:
                    tag = i
                    mb += "(={:s})".format(DynamicCommand.DT_TABLE.get(tag, "???"))
                elif i < DT_NUM + DT_THISPROCNUM:
                    tag = 0x70000000 + (i - DT_NUM)
                    mb += "(={:s})".format(ARCH_SPECIFIC_TABLE.get(tag, "???"))
                elif i < DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM:
                    tag = 0x6fffffff - (i - (DT_NUM + DT_THISPROCNUM))
                    mb += "(={:s})".format(DynamicCommand.DT_TABLE.get(tag, "???"))
                elif i < DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM:
                    tag = 0x7fffffff - (i - (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM))
                    mb += "(={:s})".format(DynamicCommand.DT_TABLE.get(tag, "???"))
                elif i < DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM:
                    tag = 0x6ffffdff - (i - (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM))
                    mb += "(={:s})".format(DynamicCommand.DT_TABLE.get(tag, "???"))
                elif i < DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM:
                    tag = 0x6ffffeff - (i - (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM))
                    mb += "(={:s})".format(DynamicCommand.DT_TABLE.get(tag, "???"))
                members.append(mb)
            members += ["l_phdr", "l_entry", "l_ldnum || l_phnum"]

        tag_maxlen = max(len(x) for x in members) + 1

        current = link_map.value
        while True:
            l_name = ProcessMap.lookup_address(read_int_from_memory(current + current_arch.ptrsize * 1))
            name = read_cstring_from_memory(l_name.value)
            l_next = ProcessMap.lookup_address(read_int_from_memory(current + current_arch.ptrsize * 3))

            if not name:
                if Path.get_filepath():
                    name = "(binary itself: {:s})".format(Path.get_filepath())
                else:
                    name = "(binary itself)"
            self.out.append(titlify(name))

            for i, tag in enumerate(members):
                line = DereferenceCommand.pprint_dereferenced(current, i, tag.ljust(tag_maxlen))
                self.out.append(line)

            if l_next.value == 0:
                break
            current = l_next.value
        return

    @staticmethod
    def get_link_map(filename_or_addr, silent=False):
        dynamic = DynamicCommand.get_dynamic(filename_or_addr, silent)
        current = dynamic.value
        while True:
            tag = read_int_from_memory(current)
            current += current_arch.ptrsize
            val = ProcessMap.lookup_address(read_int_from_memory(current))
            current += current_arch.ptrsize
            if tag not in DynamicCommand.DT_TABLE:
                if not silent:
                    info("Not found link_map")
                return None
            if DynamicCommand.DT_TABLE[tag] == "DT_DEBUG":
                dt_debug = val
                val_addr = ProcessMap.lookup_address(current - current_arch.ptrsize)
                val_addr_offset = val_addr.value - dynamic.value
                if not silent:
                    info("_DYNAMIC+{:#x}(=DT_DEBUG): {!s}{:s}{!s}".format(val_addr_offset, val_addr, RIGHT_ARROW, dt_debug))
                link_map_ptr = ProcessMap.lookup_address(dt_debug.value + current_arch.ptrsize)
                if not is_valid_addr(link_map_ptr.value):
                    return None
                link_map = ProcessMap.lookup_address(read_int_from_memory(link_map_ptr.value))
                if not silent:
                    info("DT_DEBUG+{:#x}: {!s}{:s}{!s}".format(current_arch.ptrsize, link_map_ptr, RIGHT_ARROW, link_map))
                break
        return link_map

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        Cache.reset_gef_caches(all=True)

        self.verbose = args.verbose

        if args.link_map_address:
            link_map = ProcessMap.lookup_address(args.link_map_address)

        elif args.elf_address:
            try:
                link_map = self.get_link_map(args.elf_address)
            except Exception:
                err("Failed to get link_map.")
                return
        else:
            filename = Path.get_filepath()
            if filename is None:
                err("Failed to get filename.")
                return

            if not os.path.exists(filename):
                err("{:s} is not found.".format(filename))
                return

            if not Elf.get_elf(filename).has_dynamic():
                info("The binary has no link_map.")
                return

            try:
                link_map = self.get_link_map(filename)
            except Exception:
                err("Failed to get link_map.")
                return

        self.out = []
        try:
            self.dump_link_map(link_map)
        except Exception:
            err("Failed to parse link_map.")
            return

        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class DynamicCommand(GenericCommand):
    """Display current status of the _DYNAMIC area."""
    _cmdline_ = "dynamic"
    _category_ = "02-e. Process Information - Complex Structure Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-f", dest="filename", help="the filename to parse.")
    group.add_argument("-e", dest="elf_address", type=AddressUtil.parse_address,
                       help="the elf address to parse.")
    group.add_argument("-d", dest="dynamic_address", type=AddressUtil.parse_address,
                       help="the dynamic address to parse.")
    parser.add_argument("--size", dest="dynamic_size", type=AddressUtil.parse_address,
                        help="use specified size of dynamic region.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}                                        # dump itself\n".format(_cmdline_)
    _example_ += "{:s} -f /usr/lib/x86_64-linux-gnu/libc.so.6 # dump specified binary\n".format(_cmdline_)
    _example_ += "{:s} -e 0x555555554000                      # dump specified address as elf\n".format(_cmdline_)
    _example_ += "{:s} -d 0x555555575a98                      # dump specified address as dynamic\n".format(_cmdline_)
    _example_ += "{:s} -d 0x555555575a98 --size 0x1c0         # dump specified address with specified size".format(_cmdline_)

    DT_TABLE = {
        0: "DT_NULL",
        1: "DT_NEEDED",
        2: "DT_PLTRELSZ",
        3: "DT_PLTGOT",
        4: "DT_HASH",
        5: "DT_STRTAB",
        6: "DT_SYMTAB",
        7: "DT_RELA",
        8: "DT_RELASZ",
        9: "DT_RELAENT",
        10: "DT_STRSZ",
        11: "DT_SYMENT",
        12: "DT_INIT",
        13: "DT_FINI",
        14: "DT_SONAME",
        15: "DT_RPATH",
        16: "DT_SYMBOLIC",
        17: "DT_REL",
        18: "DT_RELSZ",
        19: "DT_RELENT",
        20: "DT_PLTREL",
        21: "DT_DEBUG",
        22: "DT_TEXTREL",
        23: "DT_JMPREL",
        24: "DT_BIND_NOW",
        25: "DT_INIT_ARRAY",
        26: "DT_FINI_ARRAY",
        27: "DT_INIT_ARRAYSZ",
        28: "DT_FINI_ARRAYSZ",
        29: "DT_RUNPATH",
        30: "DT_FLAGS",
        #32: "DT_ENCODING", # unspecified
        32: "DT_PREINIT_ARRAY",
        33: "DT_PREINIT_ARRAYSZ",
        34: "DT_SYMTAB_SHNDX",
        35: "DT_RELRSZ",
        36: "DT_RELR",
        37: "DT_RELRENT",
        #0x6000000d: "DT_LOOS", # unspecified
        0x6000000e: "DT_SUNW_RTLDINF",
        0x6000000f: "DT_ANDROID_REL",
        0x60000010: "DT_ANDROID_RELSZ",
        0x60000011: "DT_ANDROID_RELA",
        0x60000012: "DT_ANDROID_RELASZ",
        0x6fffe000: "DT_ANDROID_RELR",
        0x6fffe001: "DT_ANDROID_RELRSZ",
        0x6fffe003: "DT_ANDROID_RELRENT",
        0x6fffe005: "DT_ANDROID_RELRCOUNT",
        #0x6ffff000: "DT_HIOS", # unspecified
        #0x6ffffd00: "DT_VALRNGLO", # unspecified
        0x6ffffdf5: "DT_GNU_PRELINKED",
        0x6ffffdf6: "DT_GNU_CONFLICTSZ",
        0x6ffffdf7: "DT_GNU_LIBLISTSZ",
        0x6ffffdf8: "DT_CHECKSUM",
        0x6ffffdf9: "DT_PLTPADSZ",
        0x6ffffdfa: "DT_MOVEENT",
        0x6ffffdfb: "DT_MOVESZ",
        0x6ffffdfc: "DT_FEATURE_1",
        0x6ffffdfd: "DT_POSFLAG_1",
        0x6ffffdfe: "DT_SYMINSZ",
        0x6ffffdff: "DT_SYMINENT",
        #0x6ffffdff: "DT_VALRNGHI", # unspecified
        #0x6ffffe00: "DT_ADDRRNGLO", # unspecified
        0x6ffffef5: "DT_GNU_HASH",
        0x6ffffef6: "DT_TLSDESC_PLT",
        0x6ffffef7: "DT_TLSDESC_GOT",
        0x6ffffef8: "DT_GNU_CONFLICT",
        0x6ffffef9: "DT_GNU_LIBLIST",
        0x6ffffefa: "DT_CONFIG",
        0x6ffffefb: "DT_DEPAUDIT",
        0x6ffffefc: "DT_AUDIT",
        0x6ffffefd: "DT_PLTPAD",
        0x6ffffefe: "DT_MOVETAB",
        0x6ffffeff: "DT_SYMINFO",
        #0x6ffffeff: "DT_ADDRRNGHI", # unspecified
        0x6ffffff0: "DT_VERSYM",
        0x6ffffff9: "DT_RELACOUNT",
        0x6ffffffa: "DT_RELCOUNT",
        0x6ffffffb: "DT_FLAGS_1",
        0x6ffffffc: "DT_VERDEF",
        0x6ffffffd: "DT_VERDEFNUM",
        0x6ffffffe: "DT_VERNEED",
        0x6fffffff: "DT_VERNEEDNUM",
        #0x70000000: "DT_LOPROC", # unspecified
        "arm64": {
            0x70000001: "DT_AARCH64_BTI_PLT",
            0x70000003: "DT_AARCH64_PAC_PLT",
            0x70000005: "DT_AARCH64_VARIANT_PCS",
        },
        "alpha": {
            0x70000000: "DT_ALPHA_PLTRO",
        },
        "mips": {
            0x70000001: "DT_MIPS_RLD_VERSION",
            0x70000002: "DT_MIPS_TIME_STAMP",
            0x70000003: "DT_MIPS_ICHECKSUM",
            0x70000004: "DT_MIPS_IVERSION",
            0x70000005: "DT_MIPS_FLAGS",
            0x70000006: "DT_MIPS_BASE_ADDRESS",
            0x70000007: "DT_MIPS_MSYM",
            0x70000008: "DT_MIPS_CONFLICT",
            0x70000009: "DT_MIPS_LIBLIST",
            0x7000000a: "DT_MIPS_LOCAL_GOTNO",
            0x7000000b: "DT_MIPS_CONFLICTNO",
            0x70000010: "DT_MIPS_LIBLISTNO",
            0x70000011: "DT_MIPS_SYMTABNO",
            0x70000012: "DT_MIPS_UNREFEXTNO",
            0x70000013: "DT_MIPS_GOTSYM",
            0x70000014: "DT_MIPS_HIPAGENO",
            0x70000016: "DT_MIPS_RLD_MAP",
            0x70000017: "DT_MIPS_DELTA_CLASS",
            0x70000018: "DT_MIPS_DELTA_CLASS_NO",
            0x70000019: "DT_MIPS_DELTA_INSTANCE",
            0x7000001a: "DT_MIPS_DELTA_INSTANCE_NO",
            0x7000001b: "DT_MIPS_DELTA_RELOC",
            0x7000001c: "DT_MIPS_DELTA_RELOC_NO",
            0x7000001d: "DT_MIPS_DELTA_SYM",
            0x7000001e: "DT_MIPS_DELTA_SYM_NO",
            0x70000020: "DT_MIPS_DELTA_CLASSSYM",
            0x70000021: "DT_MIPS_DELTA_CLASSSYM_NO",
            0x70000022: "DT_MIPS_CXX_FLAGS",
            0x70000023: "DT_MIPS_PIXIE_INIT",
            0x70000024: "DT_MIPS_SYMBOL_LIB",
            0x70000025: "DT_MIPS_LOCALPAGE_GOTIDX",
            0x70000026: "DT_MIPS_LOCAL_GOTIDX",
            0x70000027: "DT_MIPS_HIDDEN_GOTIDX",
            0x70000028: "DT_MIPS_PROTECTED_GOTIDX",
            0x70000029: "DT_MIPS_OPTIONS",
            0x7000002a: "DT_MIPS_INTERFACE",
            0x7000002b: "DT_MIPS_DYNSTR_ALIGN",
            0x7000002c: "DT_MIPS_INTERFACE_SIZE",
            0x7000002d: "DT_MIPS_RLD_TEXT_RESOLVE_ADDR",
            0x7000002e: "DT_MIPS_PERF_SUFFIX",
            0x7000002f: "DT_MIPS_COMPACT_SIZE",
            0x70000030: "DT_MIPS_GP_VALUE",
            0x70000031: "DT_MIPS_AUX_DYNAMIC",
            0x70000032: "DT_MIPS_PLTGOT",
            0x70000034: "DT_MIPS_RWPLT",
            0x70000035: "DT_MIPS_RLD_MAP_REL",
            0x70000036: "DT_MIPS_XHASH",
            0x7ffffffd: "DT_AUXILIARY",
            0x7ffffffe: "DT_USED",
            0x7fffffff: "DT_FILTER",
        },
        "ppc32": {
            0x70000000: "DT_PPC_GOT",
            0x70000001: "DT_PPC_OPT",
        },
        "ppc64": {
            0x70000000: "DT_PPC64_GLINK",
            0x70000001: "DT_PPC64_OPD",
            0x70000002: "DT_PPC64_OPDSZ",
            0x70000003: "DT_PPC64_OPT",
        },
        "sparc": {
            0x70000001: "DT_SPARC_REGISTER",
        },
        #0x7fffffff: "DT_HIPROC", # unspecified
    }

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_FILENAME)
        return

    def dump_dynamic(self, dynamic, remain_size):
        base_address_color = Config.get_gef_setting("theme.dereference_base_address")

        if dynamic is None:
            info("_DYNAMIC is not found.")
            return

        width = AddressUtil.get_format_address_width()

        fmt = "{:{:d}s}  {:{:d}s} {:{:d}s}     {:s}"
        legend = ["address", width, "tag", width, "value", width, "tag_name"]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        current = dynamic.value
        while True:
            addr = current
            tag = read_int_from_memory(current)
            current += current_arch.ptrsize
            val = read_int_from_memory(current)
            current += current_arch.ptrsize

            if remain_size is None:
                if tag not in self.DT_TABLE:
                    break
            else:
                remain_size -= current_arch.ptrsize * 2

            val = ProcessMap.lookup_address(val)
            tag_description = self.DT_TABLE.get(tag, "Unknown")
            colored_addr = Color.colorify("{:#0{:d}x}".format(addr, width), base_address_color)
            gef_print("{:s}: {:#0{:d}x} {!s}  |  {:s}".format(colored_addr, tag, width, val, tag_description))

            if remain_size is not None and remain_size <= 0:
                break
        return

    @staticmethod
    def get_dynamic(filename_or_addr, silent=False):
        if not silent:
            if isinstance(filename_or_addr, str):
                info("filename: {:s}".format(filename_or_addr))
            else:
                info("address: {:#x}".format(filename_or_addr))

        elf = Elf.get_elf(filename_or_addr)
        phdr = elf.get_phdr(Elf.Phdr.PT_DYNAMIC)
        if phdr is None:
            return None

        if isinstance(filename_or_addr, str):
            if elf.is_pie():
                load_base = ProcessMap.get_section_base_address(filename_or_addr)
                dynamic = phdr.p_vaddr + load_base
            else:
                dynamic = phdr.p_vaddr
        else:
            if phdr.p_vaddr < filename_or_addr:
                dynamic = phdr.p_vaddr + filename_or_addr
            else:
                dynamic = phdr.p_vaddr

        dynamic = ProcessMap.lookup_address(dynamic)
        if not silent:
            info("_DNYAMIC: {!s} [{!s}]".format(dynamic, dynamic.section.permission))
        return dynamic

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        if args.dynamic_address:
            dynamic = ProcessMap.lookup_address(args.dynamic_address)

        elif args.elf_address:
            try:
                dynamic = self.get_dynamic(args.elf_address)
            except Exception:
                err("Failed to get _DYNAMIC.")
                return

        else:
            if args.filename:
                filename = args.filename
            else:
                filename = Path.get_filepath()
                if filename is None:
                    err("Failed to get filename.")
                    return

            if not os.path.exists(filename):
                err("{:s} is not found.".format(filename))
                return

            if not Elf.get_elf(filename).has_dynamic():
                info("The binary has no _DYNAMIC.")
                return

            if ProcessMap.get_section_base_address(filename) is None:
                err("{:s} is not loaded.".format(filename))
                return

            try:
                dynamic = self.get_dynamic(filename)
            except Exception:
                err("Failed to get _DYNAMIC.")
                return

        try:
            self.dump_dynamic(dynamic, args.dynamic_size)
        except Exception:
            err("Failed to parse _DYNAMIC.")
        return


@register_command
class DestructorDumpCommand(GenericCommand):
    """Display registered destructor functions."""
    _cmdline_ = "dtor-dump"
    _category_ = "02-e. Process Information - Complex Structure Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-r", "--remote", action="store_true",
                        help="parse remote binary if download feature is available.")
    parser.add_argument("-f", "--file", help="the file path to parse.")
    parser.add_argument("--tdl", type=AddressUtil.parse_address,
                        help="specify the offset of `tls_dtor_list` from TLS base.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}\n".format(_cmdline_)
    _example_ += "{:s} --tdl 0x50                 # specify offset of tls_dtor_list\n".format(_cmdline_)
    _example_ += "{:s} --tdl 0xffffffffffffffa8   # specify negative offset".format(_cmdline_)

    def C(self, addr):
        base_address_color = Config.get_gef_setting("theme.dereference_base_address")
        a = Color.colorify("{:#0{:d}x}".format(addr, AddressUtil.get_format_address_width()), base_address_color)
        try:
            b = "[{!s}]".format(ProcessMap.lookup_address(addr).section.permission)
            return a + b
        except Exception:
            return a + "[???]"

    """
    glibc 2.37~

    x86_32: dynamic symboled: linkmap-relative
    x86_32: dynamic stripped: linkmap-relative
    x86_32: static symboled: msymbols
    x86_32: static stripped: heuristic

    x86_64: dynamic symboled: linkmap-relative
    x86_64: dynamic stripped: linkmap-relative
    x86_64: static symboled: msymbols
    x86_64: static stripped: heuristic

    arm32: dynamic symboled: linkmap-relative
    arm32: dynamic stripped: linkmap-relative
    arm32: static symboled: msymbols
    arm32: static stripped: heuristic

    arm64: dynamic symboled: linkmap-relative
    arm64: dynamic stripped: linkmap-relative
    arm64: static symboled: msymbols
    arm64: static stripped: heuristic

    sparc64: dynamic symboled: linkmap-relative
    sparc64: dynamic stripped: linkmap-relative
    sparc64: static symboled: msymbols
    sparc64: static stripped: heuristic

    s390x: dynamic symboled: linkmap-relative
    s390x: dynamic stripped: linkmap-relative
    s390x: static symboled: msymbols
    s390x: static stripped: heuristic

    loongarch64: dynamic symboled: linkmap-relative
    loongarch64: dynamic stripped: linkmap-relative
    loongarch64: static symboled: msymbols
    loongarch64: static stripped: heuristic

    sh4: dynamic symboled: heuristic (link_map is not in TLS)
    sh4: dynamic stripped: heuristic (link_map is not in TLS)
    sh4: static symboled: msymbols
    sh4: static stripped: heuristic

    ppc32: dynamic symboled: heuristic (link_map is not in TLS)
    ppc32: dynamic stripped: heuristic (link_map is not in TLS)
    ppc32: static symboled: heuristic
    ppc32: static stripped: heuristic

    ppc64: dynamic symboled: heuristic (link_map is not in TLS)
    ppc64: dynamic stripped: heuristic (link_map is not in TLS)
    ppc64: static symboled: msymbols
    ppc64: static stripped: heuristic

    nios2: dynamic symboled: heuristic (link_map is not in TLS)
    nios2: dynamic stripped: heuristic (link_map is not in TLS)
    nios2: static symboled: msymbols
    nios2: static stripped: heuristic

    alpha: dynamic symboled: heuristic (link_map is not in TLS)
    alpha: dynamic stripped: heuristic (link_map is not in TLS)
    alpha: static symboled: msymbols
    alpha: static stripped: heuristic

    riscv64: dynamic symboled: linkmap-relative
    riscv64: dynamic stripped: linkmap-relative
    riscv64: static symboled: msymbols
    riscv64: static stripped: NG (PTR_MANGLE is no-XOR)

    riscv32: dynamic symboled: linkmap-relative
    riscv32: dynamic stripped: linkmap-relative
    riscv32: static symboled: msymbols
    riscv32: static stripped: NG (PTR_MANGLE is no-XOR)

    or1k: dynamic symboled: linkmap-relative
    or1k: dynamic stripped: linkmap-relative
    or1k: static symboled: msymbols
    or1k: static stripped: NG (PTR_MANGLE is no-XOR)

    arc32: dynamic symboled: linkmap-relative
    arc32: dynamic stripped: linkmap-relative
    arc32: static symboled: msymbols
    arc32: static stripped: NG (PTR_MANGLE is no-XOR)

    m68k: dynamic symboled: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    m68k: dynamic stripped: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    m68k: static symboled: msymbols
    m68k: static stripped: NG (PTR_MANGLE is no-XOR)

    mips32: dynamic symboled: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    mips32: dynamic stripped: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    mips32: static symboled: msymbols
    mips32: static stripped: NG (PTR_MANGLE is no-XOR)

    mips64: dynamic symboled: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    mips64: dynamic stripped: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    mips64: static symboled: msymbols
    mips64: static stripped: NG (PTR_MANGLE is no-XOR)

    hppa32: dynamic symboled: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    hppa32: dynamic stripped: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    hppa32: static symboled: msymbols
    hppa32: static stripped: NG (PTR_MANGLE is no-XOR)

    microblaze: dynamic symboled: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    microblaze: dynamic stripped: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    microblaze: static symboled: msymbols
    microblaze: static stripped: NG (PTR_MANGLE is no-XOR)

    arc64: dynamic symboled: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    arc64: dynamic stripped: NG (link_map is not in TLS and PTR_MANGLE is no-XOR)
    arc64: static symboled: msymbols
    arc64: static stripped: NG (PTR_MANGLE is no-XOR)

    csky: dynamic symboled: ???
    csky: dynamic stripped: ???
    csky: static symboled: msymbols
    csky: static stripped: heuristic
    """

    def get_dtor_list_from_msymbols(self):
        # Statically linked binaries cannot resolve the address of thread-local storage variables.
        # Therefore, identify it from the output of the msymbols command and the offset of thread_arena.

        # thread_arena address of main thread
        main_thread_main_arena = GlibcHeap.search_for_main_arena_from_tls()
        if main_thread_main_arena is None:
            return None

        # thread_arena offset from .tbss
        ret = gdb.execute("maintenance print msymbols", to_string=True)
        m = re.search(r"(0x\S+) thread_arena section .tbss", ret)
        if not m:
            return None
        thread_arena_offset = int(m.group(1), 16)

        # tls_dtor_list offset from .tbss
        m = re.search(r"(0x\S+) tls_dtor_list section .tbss", ret)
        if not m:
            return None
        tls_dtor_list_offset = int(m.group(1), 16)

        # tls_dtor_list offset from TLS
        main_thread_tbss_base = main_thread_main_arena - thread_arena_offset
        main_thread_tls_dtor_list = main_thread_tbss_base + tls_dtor_list_offset

        # TLS address of main thread
        selected_thread = gdb.selected_thread()
        threads = gdb.selected_inferior().threads()
        main_thread = [th for th in threads if th.num == 1][0]
        main_thread.switch() # switch temporarily
        main_tls = current_arch.get_tls()
        selected_thread.switch() # revert thread

        # tls_dotr_list of current thread
        tls_dtor_list = main_thread_tls_dtor_list - main_tls + current_arch.get_tls()
        return tls_dtor_list

    def get_dtor_list_from_linkmap_relative(self):
        if self.codebase is None:
            return None

        if is_x86() or is_sparc64() or is_s390x():
            direction = -1
        else:
            direction = 1

        """
        --- TLS-0x80 ---
        0x7ffff7fa06c0|+0x0000|+000: 0x0000000000000000
        0x7ffff7fa06c8|+0x0008|+001: 0x00007ffff7d9b4c0 <_nl_C_LC_CTYPE_tolower+0x200>  ->  0x0000000100000000
        0x7ffff7fa06d0|+0x0010|+002: 0x00007ffff7d9bac0 <_nl_C_LC_CTYPE_toupper+0x200>  ->  0x0000000100000000
        0x7ffff7fa06d8|+0x0018|+003: 0x00007ffff7d9c3c0 <_nl_C_LC_CTYPE_class+0x100>  ->  0x0002000200020002
        0x7ffff7fa06e0|+0x0020|+004: 0x00007ffff7ffe2c0  ->  0x0000555555554000  ->  0x00010102464c457f <- link_map
        0x7ffff7fa06e8|+0x0028|+005: 0x00005555555592a0  ->  0x3c56fdd6341540d8                         <- tls_dtor_list
        0x7ffff7fa06f0|+0x0030|+006: 0x0000000000000000
        0x7ffff7fa06f8|+0x0038|+007: 0x0000555555559010  ->  0x0000000000000000
        0x7ffff7fa0700|+0x0040|+008: 0x0000000000000000
        0x7ffff7fa0708|+0x0048|+009: 0x00007ffff7df6c80 <main_arena>  ->  0x0000000000000000
        0x7ffff7fa0710|+0x0050|+010: 0x0000000000000000
        0x7ffff7fa0718|+0x0058|+011: 0x0000000000000000
        0x7ffff7fa0720|+0x0060|+012: 0x0000000000000000
        0x7ffff7fa0728|+0x0068|+013: 0x0000000000000000
        0x7ffff7fa0730|+0x0070|+014: 0x0000000000000000
        0x7ffff7fa0738|+0x0078|+015: 0x0000000000000000
        --- TLS ---
        ...
        """
        tls = current_arch.get_tls()
        for i in range(1, 16):
            addr = tls + (current_arch.ptrsize * i) * direction

            if not is_valid_addr(addr):
                break

            candidate_link_map = read_int_from_memory(addr)
            if not is_valid_addr(candidate_link_map):
                continue

            candidate_codebase = read_int_from_memory(candidate_link_map)
            if candidate_codebase == self.codebase:
                # found
                if is_s390x():
                    tls_dtor_list = tls + (current_arch.ptrsize * (i + 1)) * direction
                else:
                    tls_dtor_list = tls + (current_arch.ptrsize * (i - 1)) * direction
                if is_valid_addr(tls_dtor_list):
                    # maybe valid
                    return tls_dtor_list
                else:
                    # invalid
                    return None
        return None

    def get_dtor_list_from_heuristic(self):
        if is_x86() or is_sparc64() or is_s390x():
            direction = -1
        else:
            direction = 1

        """
        --- TLS-0x80 ---
        0x0000004af340|+0x0000|+000: 0x0000000000000000
        0x0000004af348|+0x0008|+001: 0x0000000000000000
        0x0000004af350|+0x0010|+002: 0x00000000004a83e0  ->  0x00000000004a4ae0  ->  0x000000000047e150  ->  ...
        0x0000004af358|+0x0018|+003: 0x00000000004a83e8  ->  0x00000000004a5020  ->  0x000000000047e150  ->  ...
        0x0000004af360|+0x0020|+004: 0x00000000004a83e0  ->  0x00000000004a4ae0  ->  0x000000000047e150  ->  ...
        0x0000004af368|+0x0028|+005: 0x0000000000000000  <-  $r13
        0x0000004af370|+0x0030|+006: 0x0000000000000000
        0x0000004af378|+0x0038|+007: 0x0000000000000000
        0x0000004af380|+0x0040|+008: 0x00000000004b0210  ->  0xac500ef775892689  <- tls_dtor_list
        0x0000004af388|+0x0048|+009: 0x00000000004afd50  ->  0x0000000000000000
        0x0000004af390|+0x0050|+010: 0x0000000000000000
        0x0000004af398|+0x0058|+011: 0x00000000004a71e0  ->  0x0000000000000000
        0x0000004af3a0|+0x0060|+012: 0x0000000000484e60  ->  0x0000000100000000
        0x0000004af3a8|+0x0068|+013: 0x0000000000485460  ->  0x0000000100000000
        0x0000004af3b0|+0x0070|+014: 0x0000000000485d60  ->  0x0002000200020002
        0x0000004af3b8|+0x0078|+015: 0x0000000000000000
        --- TLS ---
        ...
        """
        tls = current_arch.get_tls()
        for i in range(1, 16):
            addr = tls + (current_arch.ptrsize * i) * direction

            if not is_valid_addr(addr):
                break

            x = read_int_from_memory(addr)
            if not is_valid_addr(x):
                continue

            y = read_int_from_memory(x)
            if is_valid_addr(y):
                continue

            yb = bytearray(read_memory(x, 8))
            if yb.count(b"\x00") <= 2:
                # statistically ok
                return addr
        return None

    def dump_tls_dtors(self, offset_tls_dtor_list):
        info("Probably only exists in glibc.")
        if not self.tls:
            err("TLS is not found")
            return

        tls_dtor_list = None

        # user specified
        if offset_tls_dtor_list:
            tls_dtor_list = AddressUtil.align_address(current_arch.get_tls() + offset_tls_dtor_list)

        # method 1 (directly)
        if tls_dtor_list is None:
            try:
                tls_dtor_list = AddressUtil.parse_address("&tls_dtor_list")
                if not is_valid_addr(tls_dtor_list):
                    tls_dtor_list = None
            except gdb.error:
                pass

        # method 2 (from msymbols)
        if tls_dtor_list is None:
            if self.elf.is_static():
                tls_dtor_list = self.get_dtor_list_from_msymbols()

        # method 3 (from link-map)
        if tls_dtor_list is None:
            if not self.elf.is_static():
                tls_dtor_list = self.get_dtor_list_from_linkmap_relative()

        # method 4 (from tls with likely pattern)
        if tls_dtor_list is None:
            if current_arch.encode_cookie(0x1, 0xdeadbeef) != 0x1: # use cookie xor
                tls_dtor_list = self.get_dtor_list_from_heuristic()

        if tls_dtor_list is None:
            err("Not found tls_dtor_list")
            return

        # parse tls_dtor_list and print
        head_p = tls_dtor_list
        head = ProcessMap.lookup_address(read_int_from_memory(head_p))
        current = head.value
        if head.section is None:
            gef_print("{:s}: {:s}: {!s}".format("tls_dtor_list", self.C(head_p), head))
        else:
            gef_print("{:s}: {:s}: {!s}[{!s}]".format("tls_dtor_list", self.C(head_p), head, head.section.permission))

        ptrsize = current_arch.ptrsize

        def read_fns(addr):
            func = ProcessMap.lookup_address(read_int_from_memory(current))
            obj = ProcessMap.lookup_address(read_int_from_memory(current + ptrsize * 1))
            link_map = ProcessMap.lookup_address(read_int_from_memory(current + ptrsize * 2))
            next = ProcessMap.lookup_address(read_int_from_memory(current + ptrsize * 3))
            return func, obj, link_map, next

        while current:
            try:
                func, obj, link_map, next = read_fns(current)
            except gdb.MemoryError:
                err("Memory access error at {:#x}".format(current))
                break

            decoded_fn = current_arch.decode_cookie(func.value, self.cookie)
            sym = Symbol.get_symbol_string(decoded_fn)
            decoded_fn_s = Color.boldify("{:#x}".format(decoded_fn))

            if is_valid_addr(decoded_fn):
                valid_msg = Color.colorify("valid", "bold green")
            else:
                valid_msg = Color.colorify("invalid", "bold red")

            gef_print("   {:s}func:     {:s}: {!s} (={:s}{:s}) [{:s}]".format(
                RIGHT_ARROW, self.C(current), func, decoded_fn_s, sym, valid_msg,
            ))
            gef_print("       obj:      {:s}: {!s}".format(
                self.C(current + ptrsize * 1), obj,
            ))
            gef_print("       link_map: {:s}: {!s}".format(
                self.C(current + ptrsize * 2), link_map,
            ))
            gef_print("       next:     {:s}: {!s}".format(
                self.C(current + ptrsize * 3), next,
            ))
            current = next.value
        return

    def dump_exit_funcs(self, name):
        try:
            head_p = AddressUtil.parse_address("&" + name)
        except gdb.error:
            err("Not found symbol ({:s})".format(name))
            return

        head = ProcessMap.lookup_address(read_int_from_memory(head_p))
        current = head.value
        if head.section is None:
            gef_print("{:s}: {:s}: {!s}".format(name, self.C(head_p), head))
        else:
            gef_print("{:s}: {:s}: {!s}[{!s}]".format(name, self.C(head_p), head, head.section.permission))
        if current == 0:
            return

        ptrsize = current_arch.ptrsize

        try:
            next = ProcessMap.lookup_address(read_int_from_memory(current))
            idx = ProcessMap.lookup_address(read_int_from_memory(current + ptrsize))
        except gdb.MemoryError:
            err("Memory access error at {:#x}".format(current))
            return
        current += ptrsize * 2
        gef_print("   {:s}next:     {:s}: {!s}".format(RIGHT_ARROW, self.C(head.value + ptrsize * 0), next))
        gef_print("       idx:      {:s}: {!s}".format(self.C(head.value + ptrsize * 1), idx))

        def read_fns(addr):
            flavor = ProcessMap.lookup_address(read_int_from_memory(addr))
            fn = ProcessMap.lookup_address(read_int_from_memory(addr + ptrsize * 1))
            arg = ProcessMap.lookup_address(read_int_from_memory(addr + ptrsize * 2))
            dso_handle = ProcessMap.lookup_address(read_int_from_memory(addr + ptrsize * 3))
            return flavor, fn, arg, dso_handle

        fns_size = ptrsize * 4 # flavor, fn, arg, dso_handle

        for i in range(idx.value, -1, -1):
            addr = AddressUtil.align_address(current + fns_size * i)
            try:
                flavor, fn, arg, dso_handle = read_fns(addr)
            except gdb.MemoryError:
                err("Memory access error at {:#x}".format(addr))
                break
            if fn.value == 0:
                continue
            decoded_fn = current_arch.decode_cookie(fn.value, self.cookie)
            sym = Symbol.get_symbol_string(decoded_fn)
            decoded_fn_s = Color.boldify("{:#x}".format(decoded_fn))

            if is_valid_addr(decoded_fn):
                valid_msg = Color.colorify("valid", "bold green")
            else:
                valid_msg = Color.colorify("invalid", "bold red")

            fns = "       fns[{:#x}]: {:s}:".format(i, self.C(addr))
            width = len(fns) - 9
            gef_print("{} flavor:     {!s}".format(fns, flavor))
            gef_print("{} func:       {!s} (={:s}{:s}) [{:s}]".format(" " * width, fn, decoded_fn_s, sym, valid_msg))
            gef_print("{} arg:        {!s}".format(" " * width, arg))
            gef_print("{} dso_handle: {!s}".format(" " * width, dso_handle))
        return

    def yield_link_map(self, codebase):
        link_map = LinkMapCommand.get_link_map(codebase, silent=True)
        if link_map is None:
            return
        current = link_map.value
        while current:
            dic = {}
            dic["load_address"] = read_int_from_memory(current)
            name_ptr = read_int_from_memory(current + current_arch.ptrsize * 1)
            dic["name"] = dic["name_org"] = read_cstring_from_memory(name_ptr)
            if dic["name_org"] == "":
                dic["name"] = "{:s}".format(self.local_filepath)
            dic["dynamic"] = read_int_from_memory(current + current_arch.ptrsize * 2)
            dic["next"] = read_int_from_memory(current + current_arch.ptrsize * 3)
            LinkMap = collections.namedtuple("LinkMap", dic.keys())
            link_map = LinkMap(*dic.values())
            yield link_map
            current = dic["next"]
        return

    def dump_fini(self):
        if not self.codebase:
            return None

        if self.elf.has_dynamic():
            # Parse all loaded libraries.
            for link_map in self.yield_link_map(self.codebase):
                # get dynamic
                dynamic = DynamicCommand.get_dynamic(link_map.load_address, silent=True)
                if dynamic is None:
                    continue

                # search .fini
                fini = None
                current = dynamic.value
                while True:
                    tag = read_int_from_memory(current)
                    if tag == 13: # DT_FINI
                        fini = read_int_from_memory(current + current_arch.ptrsize)
                        if fini < link_map.load_address:
                            fini += link_map.load_address
                        break
                    if tag not in DynamicCommand.DT_TABLE:
                        break
                    current += current_arch.ptrsize * 2

                if fini is None:
                    continue

                # print .fini
                gef_print(link_map.name)
                sym = Symbol.get_symbol_string(fini)
                func_s = Color.boldify("{:#x}".format(fini))
                gef_print("   {:s}{:s}{:s}".format(RIGHT_ARROW, func_s, sym))
        else:
            # Static binary has no _DYNAMIC, but we can resolve the target address
            # from section name due to local file path.
            shdr = self.elf.get_shdr(".fini")
            if shdr is None:
                err("Not found .fini section")
                return

            fini = shdr.sh_addr
            if fini < self.codebase:
                fini += self.codebase
            gef_print(self.local_filepath)
            sym = Symbol.get_symbol_string(fini)
            func_s = Color.boldify("{:#x}".format(fini))
            gef_print("   {:s}{:s}{:s}".format(RIGHT_ARROW, func_s, sym))
        return

    def dump_fini_array(self):
        if not self.codebase:
            return None

        if self.elf.has_dynamic():
            # Parse all loaded libraries.
            for link_map in self.yield_link_map(self.codebase):
                # get dynamic
                dynamic = DynamicCommand.get_dynamic(link_map.load_address, silent=True)
                if dynamic is None:
                    continue

                # search .fini_array, fini_array_sz
                fini_array = None
                fini_array_sz = None
                current = dynamic.value
                while True:
                    tag = read_int_from_memory(current)
                    if tag == 26: # DT_FINI_ARRAY
                        fini_array = read_int_from_memory(current + current_arch.ptrsize)
                        if fini_array < link_map.load_address:
                            fini_array += link_map.load_address
                    if tag == 28: # DT_FINI_ARRAY_SZ
                        fini_array_sz = read_int_from_memory(current + current_arch.ptrsize)
                    if fini_array is not None and fini_array_sz is not None:
                        break
                    if tag not in DynamicCommand.DT_TABLE:
                        break
                    current += current_arch.ptrsize * 2

                if fini_array is None or fini_array_sz is None:
                    continue

                # parse .fini_array
                entries = []
                for i in range(fini_array_sz // current_arch.ptrsize):
                    addr = fini_array + current_arch.ptrsize * i
                    func = read_int_from_memory(addr)
                    if not is_valid_addr(func):
                        continue
                    entries.append([addr, func])
                if not entries:
                    continue

                # print .fini_array
                gef_print(link_map.name)
                for addr, func in entries:
                    sym = Symbol.get_symbol_string(func)
                    func_s = Color.boldify("{:#x}".format(func))
                    gef_print("   {:s}{:s}: {:s}{:s}".format(RIGHT_ARROW, self.C(addr), func_s, sym))
        else:
            # Static binary has no _DYNAMIC, but we can resolve the target address
            # from section name due to local file path.
            shdr = self.elf.get_shdr(".fini_array")
            if shdr is None:
                err("Not found .fini_array section")
                return

            entries = []
            vend = (1 << AddressUtil.get_memory_alignment(in_bits=True)) - 1
            for i in range(shdr.sh_size // current_arch.ptrsize):
                addr = shdr.sh_addr + current_arch.ptrsize * i
                func = read_int_from_memory(addr)
                if func in [0, vend]:
                    continue
                entries.append([addr, func])
            if not entries:
                err("Not found valid entry")
                return
            gef_print(self.local_filepath)
            for addr, func in entries:
                sym = Symbol.get_symbol_string(func)
                func_s = Color.boldify("{:#x}".format(func))
                gef_print("   {:s}{:s}: {:s}{:s}".format(RIGHT_ARROW, self.C(addr), func_s, sym))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @exclude_specific_arch(arch=("SPARC32", "XTENSA", "CRIS"))
    def do_invoke(self, args):
        Cache.reset_gef_caches(all=True)

        # init
        self.remote = args.remote

        local_filepath = None
        remote_filepath = None
        tmp_filepath = None

        if args.remote:
            if not is_remote_debug():
                err("-r option is allowed only remote debug.")
                return

            if args.file:
                remote_filepath = args.file # if specified, assume it is remote
            elif gdb.current_progspace().filename:
                f = gdb.current_progspace().filename
                if f.startswith("target:"): # gdbserver
                    f = f[7:]
                remote_filepath = f
            elif Pid.get_pid(remote=True):
                remote_filepath = "/proc/{:d}/exe".format(Pid.get_pid(remote=True))
            else:
                err("File name could not be determined.")
                return

            data = Path.read_remote_file(remote_filepath, as_byte=True) # qemu-user is failed here, it is ok
            if not data:
                err("Failed to read remote filepath")
                return
            tmp_fd, tmp_filepath = tempfile.mkstemp(dir=GEF_TEMP_DIR, suffix=".elf", prefix="dtor-dump-")
            os.fdopen(tmp_fd, "wb").write(data)
            local_filepath = tmp_filepath
            del data

        elif args.file:
            local_filepath = args.file

        elif args.file is None:
            local_filepath = Path.get_filepath()

        if local_filepath is None:
            err("File name could not be determined.")
            return

        # filepath and elf
        self.local_filepath = local_filepath
        self.elf = Elf.get_elf(local_filepath)

        # codebase
        if remote_filepath:
            self.codebase = ProcessMap.get_section_base_address(remote_filepath)
        elif local_filepath:
            self.codebase = ProcessMap.get_section_base_address(local_filepath)
        if self.codebase is None:
            self.codebase = ProcessMap.get_section_base_address(Path.get_filepath(append_proc_root_prefix=False))
        if self.codebase is None:
            self.codebase = ProcessMap.get_section_base_address(Path.get_filepath_from_info_proc())
        if self.codebase is None:
            warn("Not found codebase")

        # tls
        self.tls = current_arch.get_tls()
        if self.tls is None or not is_valid_addr(self.tls):
            warn("Not found tls")

        # cookie
        self.cookie = PtrDemangleCommand.get_cookie()
        if self.cookie is None:
            warn("Not found cookie")

        # dump
        gef_print(titlify("tls_dtor_list: registered by __cxa_thread_atexit_impl()"))
        self.dump_tls_dtors(args.tdl)

        gef_print(titlify("__exit_funcs: registered by atexit(), on_exit()"))
        self.dump_exit_funcs("__exit_funcs")

        gef_print(titlify("__quick_exit_funcs: registered by at_quick_exit()"))
        self.dump_exit_funcs("__quick_exit_funcs")

        gef_print(titlify(".fini_array section"))
        self.dump_fini_array()

        gef_print(titlify(".fini section"))
        self.dump_fini()

        # cleanup
        if tmp_filepath and os.path.exists(tmp_filepath):
            os.unlink(tmp_filepath)
        return


@register_command
class GotCommand(GenericCommand):
    """Display current status of the got/plt inside the process."""
    _cmdline_ = "got"
    _category_ = "02-e. Process Information - Complex Structure Information"
    _aliases_ = ["plt"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--file", help="the filename to parse.")
    parser.add_argument("-e", "--elf-address", type=AddressUtil.parse_address,
                        help="the elf address to parse.")
    parser.add_argument("-r", "--remote", action="store_true",
                        help="parse remote binary if download feature is available.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    parser.add_argument("-v", "--verbose", action="store_true", help="verbose output.")
    parser.add_argument("filter", metavar="FILTER", nargs="*", help="filter string.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} read print                             # filter specified keyword\n".format(_cmdline_)
    _example_ += "{:s} -f /usr/lib/x86_64-linux-gnu/libc.so.6 # specified target binary\n".format(_cmdline_)
    _example_ += "{:s} -f /bin/ls -e 0x4000000000             # use specified address, it is useful under qemu".format(_cmdline_)

    def __init__(self, *args, **kwargs):
        super().__init__(complete=gdb.COMPLETE_FILENAME)
        self.add_setting("function_resolved", "green", "Line color of the got command output if the function has been resolved")
        self.add_setting("function_not_resolved", "yellow", "Line color of the got command output if the function has not been resolved")
        return

    def get_jmp_slots(self):
        try:
            readelf = GefUtil.which("readelf")
            cmd = [readelf, "--relocs", "--wide", self.filename]
            lines = GefUtil.gef_execute_external(cmd, as_list=True)
        except (FileNotFoundError, subprocess.CalledProcessError):
            return []

        elf = Elf.get_elf(self.filename)

        output = {}
        section_name = None
        reloc_count = 0
        for line in lines:
            # get section
            r = re.findall("'(.+?)' at offset", line) # considered LANG environment
            if r:
                section_name = r[0]
                continue

            # GOT entry pattern 1
            if "JUMP_SLOT" in line:
                type = "JUMP_SLOT"
                address, _, _, _, name = line.split()[:5]
                address = int(address, 16)
                name = name.split("@")[0]
            # GOT entry pattern 2 (?)
            elif "GLOB_DAT" in line:
                type = "GLOB_DAT"
                address, _, _, _, name = line.split()[:5]
                address = int(address, 16)
                name = name.split("@")[0]
            # GOT entry pattern 3 (?)
            elif "IRELATIVE" in line:
                type = "IRELATIVE"
                if is_32bit():
                    address = line.split()[0]
                    address = int(address, 16)
                    name = "*ABS*"
                else:
                    address, _, _, addend = line.split()[:4]
                    address = int(address, 16)
                    name = "*ABS*+{:#x}".format(int(addend, 16))
            # Not GOT entry
            else:
                continue

            # count up reloc_arg
            if elf.is_static():
                reloc_arg = None
            elif section_name not in [".rel.plt", ".rela.plt"]:
                reloc_arg = None
            else:
                reloc_arg = reloc_count * [1, 8][is_32bit()]
                reloc_count += 1

            # fix address
            if elf.is_pie():
                address += self.base_address

            # save
            array = output.get(type, [])
            output[type] = array + [[address, name, section_name, type, reloc_arg]]

        # flatten
        a = output.get("JUMP_SLOT", [])
        b = output.get("IRELATIVE", [])
        c = output.get("GLOB_DAT", [])
        return a + b + c

    def get_plt_addresses(self):
        try:
            objdump = GefUtil.which("objdump")
            cmd = [objdump, "-j", ".plt", "-j", ".plt.sec", "-j", ".plt.got", "-d", self.filename]
            lines = GefUtil.gef_execute_external(cmd, as_list=True)
        except (FileNotFoundError, subprocess.CalledProcessError):
            return {}

        elf = Elf.get_elf(self.filename)

        output = {}
        for line in lines:
            # get function name
            r = re.findall(r"^([0-9a-f]+) <(.+)@plt>:", line)
            if not r:
                continue
            address, func_name = int(r[0][0], 16), r[0][1]

            # fix address
            if elf.is_pie():
                address += self.base_address

            # save
            # Since DT_REL (used at i386) has no r_addend, the information of identification does not exist.
            # So there are multiple "*ABS*" entries, keep them in a list.
            array = output.get(func_name, [])
            output[func_name] = array + [address]
        return output

    def get_plt_range(self):
        # The PLT range is required to determine whether the information in the GOT is resolved or not.
        elf = Elf.get_elf(self.filename)
        sections = [x for x in elf.shdrs if x.sh_name in [".plt", ".plt.got", ".plt.sec"]]
        if len(sections) == 0:
            return 0, 0
        plt_begin = min([x.sh_addr for x in sections])
        plt_end = max([x.sh_addr + x.sh_size for x in sections])

        # fix address
        if elf.is_pie():
            plt_begin += self.base_address
            plt_end += self.base_address
        return plt_begin, plt_end

    def perm(self, addr):
        sec = ProcessMap.lookup_address(addr).section
        if sec is None:
            return "[???]"
        return "[{!s}]".format(sec.permission)

    def get_shdr_range(self):
        # Required to identify the section name.
        elf = Elf.get_elf(self.filename)
        ranges = []
        for shdr in elf.shdrs:
            sh_start = shdr.sh_addr
            sh_end = shdr.sh_addr + shdr.sh_size
            if elf.is_pie():
                sh_start += self.base_address
                sh_end += self.base_address
            ranges.append([shdr.sh_name, sh_start, sh_end])
        return ranges

    def get_section_name(self, addr):
        ranges = self.get_shdr_range()
        for name, start, end in ranges:
            if start <= addr < end:
                return name
        return "???"

    def get_section_sym(self, addr):
        ranges = self.get_shdr_range()
        for name, start, end in ranges:
            if start <= addr < end:
                return " <{:s}+{:#x}>".format(name, addr - start)
        return ""

    def parse_plt_got(self):
        width = AddressUtil.get_format_address_width()

        # retrieve jump slots using readelf
        jmpslots = self.get_jmp_slots()

        # retrieve plt address using objdump
        plts = self.get_plt_addresses()

        # retrieve the end of plt from elf parsing
        plt_begin, plt_end = self.get_plt_range()

        # calc name_width
        name_width = 0
        for _, name, _, _, _ in jmpslots:
            if len(name) > name_width:
                name_width = len(name)

        # print legend
        if not self.quiet:
            if self.verbose:
                fmt = "{:<{:d}} {:s} {:9s} {:s} {:{:d}s} @ {:12s} {:>8s} {:>9s} {:s} {:{:d}s} @ {:12s} {:>8s} {:s} {:{:d}}"
                legend = [
                    "Name", name_width, VERTICAL_LINE,
                    "Type", VERTICAL_LINE,
                    "PLT", width, "Section", "Offset", "reloc_arg", VERTICAL_LINE,
                    "GOT", width, "Section", "Offset", VERTICAL_LINE, "GOT value", width,
                ]
            else:
                fmt = "{:<{:d}s} {:s} {:{:d}s} {:s} {:{:d}s} {:s} {:{:d}}"
                legend = [
                    "Name", name_width,  VERTICAL_LINE,
                    "PLT", width, VERTICAL_LINE,
                    "GOT", width, VERTICAL_LINE, "GOT value", width,
                ]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        # link each PLT entries and each GOT entries
        # and create lines for output
        resolved_info = []
        for got_address, name, section_name, type, reloc_arg in jmpslots:
            # resolve PLT from GOT name
            if section_name != ".rel.plt" and name == "*ABS*":
                # 32-bit arch special case.
                plt_address = None
            else:
                # in many other case.
                # This includes the common *ABS* duplication pattern on 32-bit arch.
                plt_address = plts.get(name, None)
                if plt_address:
                    # It is actually popped from plts[name]. plt_address is reassigned by int value.
                    plt_address = plt_address.pop(0)

            # resolve offset from absolute address
            got_offset = got_address - self.base_address
            if plt_address:
                plt_offset = plt_address - self.base_address

            # read the address of the function
            try:
                got_value = read_int_from_memory(got_address)
            except gdb.error:
                if not self.quiet:
                    err("Memory access error")
                return

            # resolve got value's symbol
            if got_value == 0:
                got_value_sym = ""
            elif plt_begin <= got_value < plt_end: # Non-PIE
                got_value_sym = self.get_section_sym(got_value)
            elif plt_begin - self.base_address <= got_value < plt_end - self.base_address: # PIE
                got_value_sym = self.get_section_sym(got_value)
            else:
                got_value_sym = Symbol.get_symbol_string(got_value)

            # different colors if the function has been resolved or not
            if got_value == 0:
                color = Config.get_gef_setting("got.function_resolved") # .rela.dyn && uninitialized, etc.
            elif plt_begin <= got_value < plt_end: # Non-PIE
                color = Config.get_gef_setting("got.function_not_resolved")
            elif plt_begin - self.base_address <= got_value < plt_end - self.base_address: # PIE
                color = Config.get_gef_setting("got.function_not_resolved")
            else:
                color = Config.get_gef_setting("got.function_resolved")

            # reloc_arg
            if reloc_arg is None:
                reloc_arg_info = "{:>9s}".format("-")
            else:
                reloc_arg_info = "{:#9x}".format(reloc_arg)

            # make name info
            name_info = "{:{:d}s}".format(name, name_width)

            # make plt info
            if self.verbose:
                if plt_address:
                    plt_section = self.get_section_name(plt_address) + self.perm(plt_address)
                    plt_address = ProcessMap.lookup_address(plt_address)
                    plt_info = "{!s} @{:13s} {:#8x} {:9s}".format(plt_address, plt_section, plt_offset, reloc_arg_info)
                else:
                    plt_info = "{:{:d}s}  {:13s} {:>8s} {:9s}".format("Not found", width, "", "", reloc_arg_info)
            else:
                if plt_address:
                    plt_address = ProcessMap.lookup_address(plt_address)
                    plt_info = "{!s}".format(plt_address)
                else:
                    plt_info = "{:{:d}s}".format("Not found", width)

            # make got info
            if self.verbose:
                got_section = self.get_section_name(got_address) + self.perm(got_address)
                got_address = ProcessMap.lookup_address(got_address)
                got_info = "{!s} @{:13s} {:#8x}".format(got_address, got_section, got_offset)
            else:
                got_address = ProcessMap.lookup_address(got_address)
                got_info = "{!s}".format(got_address)
            got_value_info = Color.colorify("{:#0{:d}x}{:s}".format(got_value, width, got_value_sym), color)

            # make line
            if self.verbose:
                type_info = "{:9s}".format(type)
                line_element = [name_info, type_info, plt_info, got_info, got_value_info]
            else:
                line_element = [name_info, plt_info, got_info, got_value_info]
            delim = " {:s} ".format(VERTICAL_LINE)
            line = delim.join(line_element)

            # save
            resolved_info.append([got_address.value, section_name, line])

        # sort by GOT address
        resolved_info = sorted(resolved_info)

        # print
        prev_section = None
        for _, section_name, line in sorted(resolved_info):
            # print section name
            if prev_section != section_name:
                if not self.quiet:
                    self.out.append(titlify(section_name))
            prev_section = section_name
            # if we have a filter let's skip the entries that are not requested
            if self.filter:
                if not any(pattern in line for pattern in self.filter):
                    continue
            self.out.append(line)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        try:
            GefUtil.which("objdump")
            GefUtil.which("readelf")
        except FileNotFoundError as e:
            if not args.quiet:
                err("{}".format(e))
            return

        # A valid path even if the mount namespace is different.
        local_filepath = None

        # A path in /proc/PID/maps. Ignore namespace differences.
        # Used to find the base address.
        vmmap_filepath = None

        # A path in remote environment.
        remote_filepath = None

        # A path downloaded file from remote environment.
        # It should be removed later.
        tmp_filepath = None

        self.out = []
        if args.remote:
            if not is_remote_debug():
                if not args.quiet:
                    err("-r option is allowed only remote debug.")
                return

            if args.file:
                remote_filepath = args.file # if specified, assume it is remote
                vmmap_filepath = args.file
            elif gdb.current_progspace().filename:
                f = gdb.current_progspace().filename
                if f.startswith("target:"): # gdbserver
                    f = f[7:]
                remote_filepath = f
                vmmap_filepath = f
            elif Pid.get_pid(remote=True):
                remote_filepath = "/proc/{:d}/exe".format(Pid.get_pid(remote=True))
            else:
                if not args.quiet:
                    err("File name could not be determined.")
                return

            data = Path.read_remote_file(remote_filepath, as_byte=True) # qemu-user is failed here, it is ok
            if not data:
                if not args.quiet:
                    err("Failed to read remote filepath")
                return
            tmp_fd, tmp_filepath = tempfile.mkstemp(dir=GEF_TEMP_DIR, suffix=".elf", prefix="got-")
            os.fdopen(tmp_fd, "wb").write(data)
            local_filepath = tmp_filepath
            del data

        elif args.file:
            local_filepath = args.file

        elif args.file is None:
            local_filepath = Path.get_filepath() # /proc/<PID>/root/path/to/binary if another mnt namespace
            vmmap_filepath = Path.get_filepath(append_proc_root_prefix=False)

        if local_filepath is None:
            if not args.quiet:
                err("File name could not be determined.")
            return

        if not os.path.exists(local_filepath):
            if not args.quiet:
                err("{:s} does not exist".format(local_filepath))
            return

        if not args.quiet:
            if remote_filepath:
                print_filename = "{:s} (remote: {:s})".format(local_filepath, remote_filepath)
            else:
                print_filename = local_filepath

            elf = Elf.get_elf(local_filepath)
            if elf.is_relro():
                if elf.is_full_relro():
                    relro_status = "Full RELRO"
                else:
                    relro_status = "Partial RELRO"
            else:
                relro_status = "No RELRO"
            self.out.append(titlify("PLT / GOT - {:s} - {:s}".format(print_filename, relro_status)))

        # get base address
        if args.elf_address:
            if not args.file:
                if not args.quiet:
                    err("-e option needs -f option")
                return
            base_address = args.elf_address
        else:
            vmmap = ProcessMap.get_process_maps()
            target_filepath = vmmap_filepath or local_filepath

            # get the address matching the specified path
            path_match = [x.page_start for x in vmmap if x.path == target_filepath]
            if path_match:
                base_address = min(path_match)
            else:
                # When using the -L option with qemu-user, the file path on the disk and the file path on vmmap are different.
                #
                # e.g. qemu-arm -g 1234 -L /usr/arm-linux-gnueabihf ./a.out
                # gef> vmm
                # [ Legend:  Code | Heap | Stack | Writable | ReadOnly | None | RWX ]
                # Start      End        Size       Offset     Perm Path
                # 0x3f694000 0x3f79f000 0x0010b000 0x00000000 r-x /lib/libc.so.6
                # 0x3f79f000 0x3f7b9000 0x0001a000 0x0010a000 r-- /lib/libc.so.6
                # 0x3f7b9000 0x3f7c4000 0x0000b000 0x00124000 rw- /lib/libc.so.6
                # ...
                path_match_end = [x.page_start for x in vmmap if target_filepath.endswith(x.path)]
                if path_match_end:
                    base_address = min(path_match_end)
                else:
                    if not args.quiet:
                        err("Not found {:s} in memory".format(target_filepath))
                    return

        # get the filtering parameter
        self.filter = args.filter or []
        self.filename = local_filepath
        self.base_address = base_address
        self.verbose = args.verbose
        self.quiet = args.quiet

        # doit
        self.parse_plt_got()
        if len(self.out) > GefUtil.get_terminal_size()[0]:
            gef_print("\n".join(self.out), less=not args.no_pager)
        else:
            gef_print("\n".join(self.out), less=False)

        # clean up
        if tmp_filepath and os.path.exists(tmp_filepath):
            os.unlink(tmp_filepath)
        return


@register_command
class GotAllCommand(GenericCommand):
    """Show got entries for all libraries."""
    _cmdline_ = "got-all"
    _category_ = "02-e. Process Information - Complex Structure Information"
    _aliases_ = ["plt-all"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="verbose output.")
    parser.add_argument("filter", metavar="FILTER", nargs="*", help="filter string.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_gdb_target_local
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        verbose = ["", "-v"][args.verbose]
        extra_args = "{:s} {:s}".format(verbose, " ".join(args.filter))

        self.out = []
        processed = []
        for m in ProcessMap.get_process_maps():
            if not m.path:
                continue
            if m.path.startswith(("[", "<")) or m.path.endswith(("]", ">")):
                continue
            if m.path in processed:
                continue

            if not is_valid_addr(m.page_start):
                continue
            x = read_memory(m.page_start, 4)
            if x != b"\x7fELF":
                continue

            ret = gdb.execute("got -f {:s} -n {:s}".format(m.path, extra_args), to_string=True)
            if "<" in Color.remove_color(ret): # at least one element is hit
                self.out.extend(ret.splitlines())
                self.out.append("")
            processed.append(m.path)

        if len(self.out) > GefUtil.get_terminal_size()[0]:
            gef_print("\n".join(self.out), less=not args.no_pager)
        else:
            gef_print("\n".join(self.out), less=False)
        return


class FormatStringBreakpoint(gdb.Breakpoint):
    """Inspect stack for format string."""
    def __init__(self, spec, num_args):
        super().__init__(spec, type=gdb.BP_BREAKPOINT, internal=False)
        self.num_args = num_args
        self.enabled = True
        return

    def stop(self):
        Cache.reset_gef_caches()
        msg = []
        ptr, addr = current_arch.get_ith_parameter(self.num_args)
        addr = ProcessMap.lookup_address(addr)

        if not addr.valid:
            return False

        if addr.section.permission.value & Permission.WRITE:
            content = read_cstring_from_memory(addr.value)
            content = String.gef_pystring(String.str2bytes(content))
            name = addr.info.name if addr.info else addr.section.path
            msg.append(Color.colorify("Format string helper", "bold yellow"))
            m = "Possible insecure format string: {:s}('{:s}' {:s} {:#x}: '{:s}')"
            msg.append(m.format(self.location, ptr, RIGHT_ARROW, addr.value, content))
            m = "Reason: Call to '{:s}()' with format string argument in position "
            m += "#{:d} is in page {:#x} ({:s}) that has write permission"
            msg.append(m.format(self.location, self.num_args, addr.section.page_start, name))
            ContextCommand.push_context_message("warn", "\n".join(msg))
            return True
        return False


@register_command
class FormatStringSearchCommand(GenericCommand):
    """The helper to search exploitable format-string."""
    _cmdline_ = "format-string-helper"
    _category_ = "01-g. Debugging Support - Other"
    _aliases_ = ["fmtstr-helper"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @exclude_specific_gdb_mode(mode=("wine",))
    def do_invoke(self, args):
        dangerous_functions = {
            "printf": 0,                # int printf(const char *fmt, ...);
            "fprintf": 1,               # int fprintf(FILE *stream, const char *fmt, ...);
            "dprintf": 1,               # int dprintf(int fd, const char *fmt, ...);
            "sprintf": 1,               # int sprintf(char *str, const char *fmt, ...);
            "asprintf": 1,              # int asprintf(char **strp, const char *fmt, ...);
            "snprintf": 2,              # int snprintf(char *str, size_t size, const char *fmt, ...);
            "wprintf": 0,               # int wprintf(const wchar_t *fmt, ...);
            "fwprintf": 1,              # int fwprintf(FILE *stream, const wchar_t *fmt, ...);
            "swprintf": 2,              # int swprintf(wchar_t *str, size_t n, const wchar_t *fmt, ...);
            "obstack_printf": 1,        # int obstack_printf(struct obstack *obstack, const char *fmt, ...);
            "__printf_chk": 1,          # int __printf_chk(int flag, const char *fmt);
            "__fprintf_chk": 2,         # int __fprintf_chk(FILE *stream, int flag, const char *fmt, ...);
            "__dprintf_chk": 2,         # int __dprintf_chk(int d, int flags, const char *fmt, ...)
            "__sprintf_chk": 3,         # int __sprintf_chk(char *str, int flag, size_t strlen, const char *fmt, ...);
            "__asprintf_chk": 2,        # int __asprintf_chk(char **strp, int flag, const char *fmt, ...)
            "__snprintf_chk": 4,        # int __snprintf_chk(char *str, size_t maxlen, int flag, size_t strlen, const char *fmt, ...);
            "__wprintf_chk": 1,         # int __wprintf_chk(int flag, const wchar_t *format, ...);
            "__fwprintf_chk": 2,        # int __fwprintf_chk(FILE *stream, int flag, const wchar_t *format, ...);
            "__swprintf_chk": 4,        # int __swprintf_chk(wchar_t *str, size_t maxlen, int flag, size_t slen, const wchar_t *fmt, ...);
            "__obstack_printf_chk": 2,  # int __obstack_printf_chk(struct obstack *obstack, int flag, const char *fmt, ...);

            "vprintf": 0,               # int vprintf(const char *fmt, va_list ap);
            "vfprintf": 1,              # int vfprintf(FILE *stream, const char *fmt, va_list ap);
            "vdprintf": 1,              # int vdprintf(int fd, const char *fmt, va_list ap);
            "vsprintf": 1,              # int vsprintf(char *str, const char *fmt, va_list ap);
            "vasprintf": 1,             # int vasprintf(char **strp, const char *fmt, va_list ap);
            "vsnprintf": 2,             # int vsnprintf(char *str, size_t size, const char *fmt, va_list ap);
            "vwprintf": 0,              # int vwprintf(const wchar_t *fmt, va_list ap);
            "vfwprintf": 1,             # int vfwprintf(FILE *stream, const wchar_t *fmt, va_list ap);
            "vswprintf": 2,             # int vswprintf(wchar_t *str, size_t maxlen, const wchar_t *fmt, va_list ap);
            "obstack_vprintf": 1,       # int obstack_vprintf(struct obstack *obstack, const char *fmt, va_list ap);
            "__vprintf_chk": 1,         # int __vprintf_chk(int flag, const char *fmt, va_list ap);
            "__vfprintf_chk": 2,        # int __vfprintf_chk(FILE *stream, int flag, const char *fmt, va_list ap);
            "__vdprintf_chk": 2,        # int __vdprintf_chk(int d, int flag, const char *fmt, va_list ap);
            "__vsprintf_chk": 3,        # int __vsprintf_chk(char *str, int flag, size_t slen, const char *fmt, va_list ap);
            "__vasprintf_chk": 2,       # int __vasprintf_chk(char **strp, int flag, const char *fmt, va_list ap);
            "__vsnprintf_chk": 4,       # int __vsnprintf_chk(char *str, size_t maxlen, int flag, size_t slen, const char *fmt, va_list ap);
            "__vwprintf_chk": 1,        # int __vwprintf_chk(int flag, const wchar_t *fmt, va_list ap);
            "__vfwprintf_chk": 2,       # int __vfwprintf_chk(FILE *stream, int flag, const wchar_t *fmt, va_list ap);
            "__vswprintf_chk": 4,       # int __vswprintf_chk(wchar_t *str, size_t maxlen, int flag, size_t slen, const wchar_t *fmt, va_list ap);
            "__obstack_vprintf_chk": 2, # int __obstack_vprintf_chk(struct obstack *obstack, int flag, const char *fmt, va_list ap);

            "syslog": 1,                # void syslog(int priority, const char *fmt, ...);
            "vsyslog": 1,               # void vsyslog(int priority, const char *fmt, va_list ap);
            "__syslog_chk": 2,          # void __syslog_chk(int priority, int flag, const char *fmt, ...);
            "__vsyslog_chk": 2,         # void __vsyslog_chk(int priority, int flag, const char *fmt, va_list ap);

            "scanf": 0,                 # int scanf(const char *fmt, ...);
            "fscanf": 1,                # int fscanf(FILE *stream, const char *fmt, ...);
            "sscanf": 1,                # int sscanf(const char *str, const char *fmt, ...);
            "wscanf": 0,                # int wscanf(const wchar_t *fmt, ...);
            "fwscanf": 1,               # int fwscanf(FILE *stream, const wchar_t *fmt, ...);
            "swscanf": 1,               # int swscanf(const wchar_t *ws, const wchar_t *fmt, ...);

            "vscanf": 0,                # int vscanf(const char *fmt, va_list ap);
            "vfscanf": 1,               # int vfscanf(FILE *stream, const char *fmt, va_list ap);
            "vsscanf": 1,               # int vsscanf(const char *str, const char *fmt, va_list ap);
            "vwscanf": 0,               # int vwscanf(const wchar_t *fmt, va_list ap);
            "vfwscanf": 1,              # int vfwscanf(FILE *stream, const wchar_t *fmt, va_list ap);
            "vswscanf": 1,              # int vswscanf(const wchar_t *s, const wchar_t *fmt, va_list ap);

            "warn": 0,                  # void warn(const char *fmt, ...);
            "warnx": 0,                 # void warnx(const char *fmt, ...);
            "err": 1,                   # void err(int status, const char *fmt, ...);
            "errx": 1,                  # void errx(int status, const char *fmt, ...);

            "vwarn": 0,                 # void vwarn(const char *fmt, va_list ap);
            "vwarnx": 0,                # void vwarnx(const char *fmt, va_list ap);
            "verr": 1,                  # void verr(int status, const char *fmt, va_list ap);
            "verrx": 1,                 # void verrx(int status, const char *fmt, va_list ap);

            "error": 2,                 # void error(int status, int errnum, const char *fmt, ...);
            "error_at_line": 4,         # void error_at_line(int status, int errnum, const char *filename, uint linenum, const char *fmt, ...);

            "argp_error": 1,            # void argp_error(const struct argp_state *state, const char *fmt, ...);
            "argp_failure": 3,          # void argp_failure(const struct argp_state *state, int status, int errnum, const char *fmt, ...);

            "xasprintf": 0,             # char* xasprintf(const char *fmt, ...);
            "xvasprintf": 0,            # char* xvasprintf(const char *fmt, va_list ap);
        }

        bp_count = 0
        for func_name, num_arg in dangerous_functions.items():
            try:
                AddressUtil.parse_address(func_name)
            except gdb.error:
                continue
            gef_print(func_name + ": ", end="")
            FormatStringBreakpoint(func_name, num_arg)
            bp_count += 1

        ok("Enabled {:d}/{:d} FormatStringBreakpoint".format(bp_count, len(dangerous_functions)))
        return


class TraceMallocBreakpoint(gdb.Breakpoint):
    """Track allocations done with malloc() or calloc()."""
    def __init__(self, name):
        super().__init__(name, gdb.BP_BREAKPOINT, internal=True)
        self.silent = True
        self.name = name
        return

    def stop(self):
        # The first call to malloc calls malloc twice internally, like malloc -> malloc_hook_ini -> malloc.
        # You need to prevent the breakpoint from being set twice.
        if hasattr(self, "retbp"):
            # The retbp is `gdb.FinishBreakpoint`, not `gdb.Breakpoint`.
            # so it is deleted automatically if out of scope, so it must be checked by is_valid().
            if self.retbp.is_valid() and self.retbp.enabled:
                return False
        Cache.reset_gef_caches()
        _, size = current_arch.get_ith_parameter(0)
        self.retbp = TraceMallocRetBreakpoint(size, self.name)
        return False


class TraceMallocRetBreakpoint(gdb.FinishBreakpoint):
    """Internal temporary breakpoint to retrieve the return value of malloc()."""
    def __init__(self, size, name):
        try:
            frame = gdb.newest_frame()
            while frame and frame.is_valid():
                pc = frame.older().pc()
                if current_arch.is_call(get_insn_prev(pc)):
                    break
                frame = frame.older()
            if not frame:
                return
        except gdb.error:
            return

        super().__init__(frame, internal=True)
        self.size = size
        self.name = name
        self.silent = True
        return

    def stop(self):
        if self.return_value:
            loc = int(self.return_value)
        else:
            loc = AddressUtil.parse_address(current_arch.return_register)

        ok("{:s} - {:s}({:#6x})={:#x}    // #allocated: {:d}, #freed: {:d}".format(
            Color.colorify("Heap-Analysis", "bold yellow"), self.name, self.size, loc,
            len(HeapAnalysisCommand.heap_allocated_list),
            len(HeapAnalysisCommand.heap_freed_list),
        ))
        check_heap_overlap = Config.get_gef_setting("heap_analysis_helper.check_heap_overlap")

        # pop from freed list if it was in it
        if HeapAnalysisCommand.heap_freed_list:
            idx = 0
            for item in HeapAnalysisCommand.heap_freed_list:
                addr = item[0]
                if addr == loc:
                    HeapAnalysisCommand.heap_freed_list.remove(item)
                    continue
                idx += 1

        # pop from uaf watchlist
        if HeapAnalysisCommand.heap_uaf_watchpoints:
            idx = 0
            for wp in HeapAnalysisCommand.heap_uaf_watchpoints:
                if loc <= wp.ptr < loc + self.size:
                    HeapAnalysisCommand.heap_uaf_watchpoints.remove(wp)
                    wp.enabled = False
                    continue
                idx += 1

        item = (loc, self.size)

        if check_heap_overlap:
            # seek all the currently allocated chunks, read their effective size and check for overlap
            msg = []
            align = AddressUtil.get_memory_alignment()
            for chunk_addr, _ in HeapAnalysisCommand.heap_allocated_list:
                current_chunk = GlibcHeap.GlibcChunk(chunk_addr)
                current_chunk_size = current_chunk.get_chunk_size()

                if not (chunk_addr <= loc < chunk_addr + current_chunk_size):
                    continue
                offset = loc - chunk_addr - 2 * align
                if offset < 0:
                    continue # false positive, discard

                msg.append(Color.colorify("Heap-Analysis", "bold yellow"))
                msg.append("Possible heap overlap detected")
                msg.append("Reason {:s} new allocated chunk {:#x} (of size {:d}) overlaps in-used chunk {:#x} (of size {:#x})".format(
                    RIGHT_ARROW, loc, self.size, chunk_addr, current_chunk_size,
                ))
                msg.append("Writing {:d} bytes from {:#x} will reach chunk {:#x}".format(offset, chunk_addr, loc))
                msg.append("Payload example for chunk {:#x} (to overwrite {:#x} headers):".format(chunk_addr, loc))
                msg.append("  data = 'A'*{0:d} + 'B'*{1:d} + 'C'*{1:d}".format(offset, align))
                ContextCommand.push_context_message("warn", "\n".join(msg))
                return True

        # add it to alloc-ed list
        HeapAnalysisCommand.heap_allocated_list.append(item)
        return False

    def out_of_scope(self): # noqa
        if self.enabled:
            ok("{:s} - {:s}({:#6x}) {:s}".format(
                Color.colorify("Heap-Analysis", "bold red"), self.name, self.size,
                Color.redify("(abnormal finish)"),
            ))
            self.enabled = False
        return


class TraceReallocBreakpoint(gdb.Breakpoint):
    """Track re-allocations done with realloc()."""
    def __init__(self):
        super().__init__("__libc_realloc", gdb.BP_BREAKPOINT, internal=True)
        self.silent = True
        return

    def stop(self):
        _, ptr = current_arch.get_ith_parameter(0)
        _, size = current_arch.get_ith_parameter(1)

        if ptr == 0:
            # When ptr is NULL, realloc internally calls malloc, which are tracked separately.
            # Therefore realloc just displays its arguments, but don't track it.
            ok("{:s} - __libc_realloc({:#x}, {:#x}) {:s}".format(
                Color.colorify("Heap-Analysis", "bold yellow"), ptr, size,
                Color.greenify("(redirected to malloc)"),
            ))
            return False

        self.retbp = TraceReallocRetBreakpoint(ptr, size)
        return False


class TraceReallocRetBreakpoint(gdb.FinishBreakpoint):
    """Internal temporary breakpoint to retrieve the return value of realloc()."""
    def __init__(self, ptr, size):
        try:
            frame = gdb.newest_frame()
            while frame and frame.is_valid():
                pc = frame.older().pc()
                if current_arch.is_call(get_insn_prev(pc)):
                    break
                frame = frame.older()
            if not frame:
                return
        except gdb.error:
            return

        super().__init__(frame, internal=True)
        self.ptr = ptr
        self.size = size
        self.silent = True
        return

    def stop(self):
        if self.return_value:
            newloc = int(self.return_value)
        else:
            newloc = AddressUtil.parse_address(current_arch.return_register)

        if self.ptr == 0:
            msg = Color.yellowify("{:#x} (return new chunk)".format(newloc))
        elif newloc != self.ptr:
            msg = Color.redify("{:#x} (return another chunk)".format(newloc))
        else:
            msg = Color.greenify("{:#x} (return same chunk)".format(newloc))
        ok("{:s} - __libc_realloc({:#x}, {:#x})={:s}    // #allocated: {:d}, #freed: {:d}".format(
            Color.colorify("Heap-Analysis", "bold yellow"), self.ptr, self.size, msg,
            len(HeapAnalysisCommand.heap_allocated_list),
            len(HeapAnalysisCommand.heap_freed_list),
        ))

        item = (newloc, self.size)

        try:
            # check if item was in alloc-ed list
            idx = [x for x, y in HeapAnalysisCommand.heap_allocated_list].index(self.ptr)
            # if so pop it out
            item = HeapAnalysisCommand.heap_allocated_list.pop(idx)
        except ValueError:
            if self.ptr != 0:
                warn("Chunk {:#x} was not in tracking list".format(self.ptr))
        finally:
            # add new item to alloc-ed list
            HeapAnalysisCommand.heap_allocated_list.append(item)

        return False

    def out_of_scope(self): # noqa
        if self.enabled:
            ok("{:s} - __libc_realloc({:#x}, {:#x}) {:s}".format(
                Color.colorify("Heap-Analysis", "bold red"), self.ptr, self.size,
                Color.redify("(abnormal finish)"),
            ))
            self.enabled = False
        return


class TraceFreeBreakpoint(gdb.Breakpoint):
    """Track calls to free() and attempts to detect inconsistencies."""
    def __init__(self):
        super().__init__("__libc_free", gdb.BP_BREAKPOINT, internal=True)
        self.silent = True
        return

    def stop(self):
        Cache.reset_gef_caches()
        _, ptr = current_arch.get_ith_parameter(0)
        msg = []
        check_double_free = Config.get_gef_setting("heap_analysis_helper.check_double_free")
        check_weird_free = Config.get_gef_setting("heap_analysis_helper.check_weird_free")
        check_uaf = Config.get_gef_setting("heap_analysis_helper.check_uaf")

        ok("{:s} - free({:#x})    // #allocated: {:d}, #freed: {:d}".format(
            Color.colorify("Heap-Analysis", "bold yellow"), ptr,
            len(HeapAnalysisCommand.heap_allocated_list),
            len(HeapAnalysisCommand.heap_freed_list),
        ))
        if ptr == 0:
            return False

        if ptr in [x for (x, y) in HeapAnalysisCommand.heap_freed_list]:
            if check_double_free:
                msg.append(Color.colorify("Heap-Analysis", "bold yellow"))
                msg.append("Double-free detected {:s} free({:#x}) is called at {:#x} but is already in the freed list".format(
                    RIGHT_ARROW, ptr, current_arch.pc,
                ))
                msg.append("Execution will likely crash...")
                ContextCommand.push_context_message("warn", "\n".join(msg))
                return True
            return False

        # if here, no error
        # 1. move alloc-ed item to free list
        try:
            # pop from alloc-ed list
            idx = [x for x, y in HeapAnalysisCommand.heap_allocated_list].index(ptr)
            item = HeapAnalysisCommand.heap_allocated_list.pop(idx)

        except ValueError:
            if check_weird_free:
                msg.append(Color.colorify("Heap-Analysis", "bold yellow"))
                msg.append("Heap inconsistency detected:")
                msg.append("Attempting to free an unknown value: {:#x}".format(ptr))
                ContextCommand.push_context_message("warn", "\n".join(msg))
                return True
            return False

        # 2. add it to freed list
        HeapAnalysisCommand.heap_freed_list.append(item)

        self.retbp = None
        if check_uaf:
            # 3. (opt.) add a watchpoint on pointer
            self.retbp = TraceFreeRetBreakpoint(ptr)
        return False


class TraceFreeRetBreakpoint(gdb.FinishBreakpoint):
    """Internal temporary breakpoint to track free()d values."""
    def __init__(self, ptr):
        super().__init__(gdb.newest_frame(), internal=True)
        self.silent = True
        self.ptr = ptr
        return

    def stop(self):
        Cache.reset_gef_caches()
        wp = UafWatchpoint(self.ptr)
        HeapAnalysisCommand.heap_uaf_watchpoints.append(wp)
        return False

    def out_of_scope(self): # noqa
        if self.enabled:
            ok("{:s} - __libc_free({:#x}) {:s}".format(
                Color.colorify("Heap-Analysis", "bold red"), self.ptr,
                Color.redify("(abnormal finish)"),
            ))
            self.enabled = False
        return


class UafWatchpoint(gdb.Breakpoint):
    """Custom watchpoints set TraceFreeBreakpoint() to monitor free()d pointers being used."""
    def __init__(self, ptr):
        super().__init__("*{:#x}".format(ptr), gdb.BP_WATCHPOINT, internal=True)
        self.ptr = ptr
        self.silent = True
        self.enabled = True
        return

    def stop(self):
        """If this method is triggered, we likely have a UaF. Break the execution and report it."""
        Cache.reset_gef_caches()
        try:
            frame = gdb.selected_frame()
        except gdb.error:
            return False
        if frame.name() in ("_int_malloc", "malloc_consolidate", "__libc_calloc",):
            return False

        # software watchpoints stop after the next statement
        # see https://sourceware.org/gdb/onlinedocs/gdb/Set-Watchpoints.html
        pc = Disasm.gdb_get_nth_previous_instruction_address(current_arch.pc, 2)
        msg = []
        msg.append(Color.colorify("Heap-Analysis", "bold yellow"))
        msg.append("Possible Use-after-Free in '{:s}': pointer {:#x} was freed, but is attempted to be used at {:#x}".format(
            Path.get_filepath(), self.ptr, pc,
        ))
        ContextCommand.push_context_message("warn", "\n".join(msg))
        return True


@register_command
class HeapAnalysisCommand(GenericCommand):
    """Trace malloc/free to check heap integrity for Use-after-Free, Double Free, Heap overlap."""
    _cmdline_ = "heap-analysis-helper"
    _category_ = "06-a. Heap - Glibc"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--show", action="store_true", help="show the tracked allocations.")
    parser.add_argument("--config", action="store_true", help="show the config for settings.")
    _syntax_ = parser.format_help()

    _note_ = "It doesn't seem to work well on Ubuntu 24.04 (glibc 2.39). Currently it is in investigating the cause."

    heap_allocated_list = []
    heap_freed_list = []
    heap_uaf_watchpoints = []

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.add_setting("check_double_free", True, "Break execution when a double free is encountered")
        self.add_setting("check_weird_free", True, "Break execution when free() is called against a non-tracked pointer")
        self.add_setting("check_uaf", True, "Break execution when a possible Use-after-Free condition is found")
        self.add_setting("check_heap_overlap", True, "Break execution when a possible overlap in allocation is found")
        self.bp_malloc = None
        self.bp_calloc = None
        self.bp_free = None
        self.bp_realloc = None
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        if args.show:
            self.dump_tracked_allocations()
            return

        if args.config:
            gdb.execute("gef config heap_analysis_helper.check_double_free")
            gdb.execute("gef config heap_analysis_helper.check_weird_free")
            gdb.execute("gef config heap_analysis_helper.check_uaf")
            gdb.execute("gef config heap_analysis_helper.check_heap_overlap")
            return

        self.setup()
        return

    def setup(self):
        ok("Tracking malloc() & calloc()")
        self.bp_malloc = TraceMallocBreakpoint("__libc_malloc")
        self.bp_calloc = TraceMallocBreakpoint("__libc_calloc")
        ok("Tracking free()")
        self.bp_free = TraceFreeBreakpoint()
        ok("Tracking realloc()")
        self.bp_realloc = TraceReallocBreakpoint()

        ok("Disabling hardware watchpoints (this may increase the latency)")
        gdb.execute("set can-use-hw-watchpoints 0")

        info("Dynamic breakpoints correctly setup, GEF will break execution if a possible vulnerabity is found.")
        warn("{:s}: The heap analysis slows down the execution noticeably.".format(Color.colorify("Note", "bold underline yellow")))

        # when inferior quits, we need to clean everything for a next execution
        EventHooking.gef_on_exit_hook(self.clean)
        return

    def dump_tracked_allocations(self):
        if HeapAnalysisCommand.heap_allocated_list:
            ok("Tracked as in-use chunks:")
            for addr, sz in HeapAnalysisCommand.heap_allocated_list:
                gef_print("{:#x} = malloc({:#x})".format(addr, sz))
        else:
            ok("No malloc() chunk tracked")

        if HeapAnalysisCommand.heap_freed_list:
            ok("Tracked as freed chunks:")
            for addr, _sz in HeapAnalysisCommand.heap_freed_list:
                gef_print("free({:#x})".format(addr))
        else:
            ok("No free() chunk tracked")
        return

    def clean(self, _event):
        ok("{:s} - Cleaning up".format(Color.colorify("Heap-Analysis", "bold yellow")))
        for bp in [self.bp_malloc, self.bp_calloc, self.bp_free, self.bp_realloc]:
            if hasattr(bp, "retbp") and bp.retbp:
                try:
                    bp.retbp.delete()
                except RuntimeError:
                    # in some cases, gdb was found failing to correctly remove the retbp
                    # but they can be safely ignored since the debugging session is over
                    pass

            bp.delete()

        for wp in HeapAnalysisCommand.heap_uaf_watchpoints:
            wp.delete()

        HeapAnalysisCommand.heap_allocated_list = []
        HeapAnalysisCommand.heap_freed_list = []
        HeapAnalysisCommand.heap_uaf_watchpoints = []

        ok("{:s} - Re-enabling hardware watchpoints".format(Color.colorify("Heap-Analysis", "bold yellow")))
        gdb.execute("set can-use-hw-watchpoints 1")

        EventHooking.gef_on_exit_unhook(self.clean)
        return


@register_command
class SyscallSearchCommand(GenericCommand):
    """Search the syscall number for specified architecture."""
    _cmdline_ = "syscall-search"
    _category_ = "05-b. Syscall - Search"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", dest="arch", help="specify the architecture. (default: current_arch.arch)")
    parser.add_argument("-m", dest="mode", help="specify the mode. (default: current_arch.mode)")
    parser.add_argument("search_pattern", metavar="SYSCALL_NAME|SYSCALL_NUM",
                        help="syscall name or number to search. Regex is available.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="display prototype of syscall.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} -a X86 -m 64        "^writev?" # amd64\n'.format(_cmdline_)
    _example_ += '{:s} -a X86 -m 32        "^writev?" # i386 on amd64\n'.format(_cmdline_)
    _example_ += '{:s} -a X86 -m N32       "^writev?" # i386 native\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM64 -m ARM     "^writev?" # arm64\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM -m 32        "^writev?" # arm32 on arm64\n'.format(_cmdline_)
    _example_ += '{:s} -a ARM -m N32       "^writev?" # arm32 native\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m 32       "^writev?" # mips32\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m n32      "^writev?" # mipsn32\n'.format(_cmdline_)
    _example_ += '{:s} -a MIPS -m 64       "^writev?" # mips64\n'.format(_cmdline_)
    _example_ += '{:s} -a PPC -m 32        "^writev?" # ppc32\n'.format(_cmdline_)
    _example_ += '{:s} -a PPC -m 64        "^writev?" # ppc64\n'.format(_cmdline_)
    _example_ += '{:s} -a SPARC -m 32      "^writev?" # sparc32\n'.format(_cmdline_)
    _example_ += '{:s} -a SPARC -m 32PLUS  "^writev?" # sparc32plus\n'.format(_cmdline_)
    _example_ += '{:s} -a SPARC -m 64      "^writev?" # sparc64\n'.format(_cmdline_)
    _example_ += '{:s} -a RISCV -m 32      "^writev?" # riscv32\n'.format(_cmdline_)
    _example_ += '{:s} -a RISCV -m 64      "^writev?" # riscv64\n'.format(_cmdline_)
    _example_ += '{:s} -a S390X -m 64      "^writev?" # s390x\n'.format(_cmdline_)
    _example_ += '{:s} -a SH4              "^writev?" # sh4\n'.format(_cmdline_)
    _example_ += '{:s} -a M68K -m 32       "^writev?" # m68k\n'.format(_cmdline_)
    _example_ += '{:s} -a ALPHA            "^writev?" # alpha\n'.format(_cmdline_)
    _example_ += '{:s} -a HPPA -m 32       "^writev?" # hppa32\n'.format(_cmdline_)
    _example_ += '{:s} -a HPPA -m 64       "^writev?" # hppa64\n'.format(_cmdline_)
    _example_ += '{:s} -a OR1K             "^writev?" # or1k\n'.format(_cmdline_)
    _example_ += '{:s} -a NIOS2            "^writev?" # nios2\n'.format(_cmdline_)
    _example_ += '{:s} -a MICROBLAZE       "^writev?" # microblaze\n'.format(_cmdline_)
    _example_ += '{:s} -a XTENSA           "^writev?" # xtensa\n'.format(_cmdline_)
    _example_ += '{:s} -a CRIS             "^writev?" # cris\n'.format(_cmdline_)
    _example_ += '{:s} -a LOONGARCH -m 64  "^writev?" # loongarch64\n'.format(_cmdline_)
    _example_ += '{:s} -a ARC -m 32        "^writev?" # arc32\n'.format(_cmdline_)
    _example_ += '{:s} -a ARC -m 64        "^writev?" # arc64\n'.format(_cmdline_)
    _example_ += '{:s} -a CSKY             "^writev?" # csky'.format(_cmdline_)

    def make_output(self, syscall_table, syscall_num, syscall_name_pattern):
        self.out.append(titlify("arch={:s}, mode={:s}".format(syscall_table.arch, syscall_table.mode)))
        self.out.append(Color.colorify("{:<17}{:s}".format("Syscall-num", "Syscall-name"), Config.get_gef_setting("theme.table_heading")))
        for key, entry in syscall_table.table.items():
            nr = key
            if not re.search(syscall_name_pattern, entry.name):
                continue
            if syscall_num is not None and nr != syscall_num:
                continue
            params = ""
            if self.verbose:
                params = "(" + ", ".join(entry.args_full) + ");"
            self.out.append("NR={:<#14x}{:s}{:s}".format(nr, Color.boldify(entry.name), params))
        return

    @parse_args
    def do_invoke(self, args):
        self.verbose = args.verbose

        syscall_num = None
        syscall_name_pattern = ".*"

        target_arch = args.arch
        target_mode = args.mode
        # force fixing
        if target_mode is None:
            if target_arch in ["SH4", "ALPHA", "OR1K", "NIOS2", "MICROBLAZE", "XTENSA", "CRIS", "CSKY"]:
                target_mode = target_arch

        try:
            syscall_num = int(args.search_pattern, 0)
        except ValueError:
            syscall_name_pattern = args.search_pattern

        try:
            syscall_table = get_syscall_table(target_arch, target_mode)
        except Exception:
            self.usage()
            return

        self.out = []
        self.make_output(syscall_table, syscall_num, syscall_name_pattern)

        if len(self.out) > GefUtil.get_terminal_size()[0]:
            gef_print("\n".join(self.out), less=not args.no_pager)
        else:
            gef_print("\n".join(self.out), less=False)
        return


# System call table (linux-6.10)

# [How to make]
# clang-format --style='{BasedOnStyle: Google, ColumnLimit: 1000}' FILENAME | grep ^asmlinkage
#   `!` at the beginning of the line: manually fixed the argument information
#   `#` at the beginning of the line: excluded for reasons such as duplication

# include/linux/syscalls.h
syscall_defs = """
asmlinkage long sys_io_setup(unsigned nr_reqs, aio_context_t __user *ctx);
asmlinkage long sys_io_destroy(aio_context_t ctx);
!asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr, struct iocb __user * __user *iocbpp);
asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, struct io_event __user *result);
asmlinkage long sys_io_getevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event __user *events, struct __kernel_timespec __user *timeout);
asmlinkage long sys_io_getevents_time32(__u32 ctx_id, __s32 min_nr, __s32 nr, struct io_event __user *events, struct old_timespec32 __user *timeout);
asmlinkage long sys_io_pgetevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event __user *events, struct __kernel_timespec __user *timeout, const struct __aio_sigset __user *sig);
asmlinkage long sys_io_pgetevents_time32(aio_context_t ctx_id, long min_nr, long nr, struct io_event __user *events, struct old_timespec32 __user *timeout, const struct __aio_sigset __user *sig);
asmlinkage long sys_io_uring_setup(u32 entries, struct io_uring_params __user *p);
asmlinkage long sys_io_uring_enter(unsigned int fd, u32 to_submit, u32 min_complete, u32 flags, const void __user *argp, size_t argsz);
asmlinkage long sys_io_uring_register(unsigned int fd, unsigned int op, void __user *arg, unsigned int nr_args);
asmlinkage long sys_setxattr(const char __user *path, const char __user *name, const void __user *value, size_t size, int flags);
asmlinkage long sys_lsetxattr(const char __user *path, const char __user *name, const void __user *value, size_t size, int flags);
asmlinkage long sys_fsetxattr(int fd, const char __user *name, const void __user *value, size_t size, int flags);
asmlinkage long sys_getxattr(const char __user *path, const char __user *name, void __user *value, size_t size);
asmlinkage long sys_lgetxattr(const char __user *path, const char __user *name, void __user *value, size_t size);
asmlinkage long sys_fgetxattr(int fd, const char __user *name, void __user *value, size_t size);
asmlinkage long sys_listxattr(const char __user *path, char __user *list, size_t size);
asmlinkage long sys_llistxattr(const char __user *path, char __user *list, size_t size);
asmlinkage long sys_flistxattr(int fd, char __user *list, size_t size);
asmlinkage long sys_removexattr(const char __user *path, const char __user *name);
asmlinkage long sys_lremovexattr(const char __user *path, const char __user *name);
asmlinkage long sys_fremovexattr(int fd, const char __user *name);
asmlinkage long sys_getcwd(char __user *buf, unsigned long size);
asmlinkage long sys_eventfd2(unsigned int count, int flags);
asmlinkage long sys_epoll_create1(int flags);
asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event);
asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events, int maxevents, int timeout, const sigset_t __user *sigmask, size_t sigsetsize);
asmlinkage long sys_epoll_pwait2(int epfd, struct epoll_event __user *events, int maxevents, const struct __kernel_timespec __user *timeout, const sigset_t __user *sigmask, size_t sigsetsize);
asmlinkage long sys_dup(unsigned int fildes);
asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags);
asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg);
asmlinkage long sys_inotify_init1(int flags);
asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask);
asmlinkage long sys_inotify_rm_watch(int fd, __s32 wd);
asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
asmlinkage long sys_ioprio_set(int which, int who, int ioprio);
asmlinkage long sys_ioprio_get(int which, int who);
asmlinkage long sys_flock(unsigned int fd, unsigned int cmd);
asmlinkage long sys_mknodat(int dfd, const char __user *filename, umode_t mode, unsigned dev);
asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, umode_t mode);
asmlinkage long sys_unlinkat(int dfd, const char __user *pathname, int flag);
asmlinkage long sys_symlinkat(const char __user *oldname, int newdfd, const char __user *newname);
asmlinkage long sys_linkat(int olddfd, const char __user *oldname, int newdfd, const char __user *newname, int flags);
asmlinkage long sys_renameat(int olddfd, const char __user *oldname, int newdfd, const char __user *newname);
asmlinkage long sys_umount(char __user *name, int flags);
asmlinkage long sys_mount(char __user *dev_name, char __user *dir_name, char __user *type, unsigned long flags, void __user *data);
asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *put_old);
asmlinkage long sys_statfs(const char __user *path, struct statfs __user *buf);
asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 __user *buf);
asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user *buf);
asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user *buf);
asmlinkage long sys_statmount(const struct mnt_id_req __user *req, struct statmount __user *buf, size_t bufsize, unsigned int flags);
asmlinkage long sys_listmount(const struct mnt_id_req __user *req, u64 __user *mnt_ids, size_t nr_mnt_ids, unsigned int flags);
asmlinkage long sys_truncate(const char __user *path, long length);
asmlinkage long sys_ftruncate(unsigned int fd, off_t length);
asmlinkage long sys_truncate64(const char __user *path, loff_t length);
asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length);
asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode);
asmlinkage long sys_faccessat2(int dfd, const char __user *filename, int mode, int flags);
asmlinkage long sys_chdir(const char __user *filename);
asmlinkage long sys_fchdir(unsigned int fd);
asmlinkage long sys_chroot(const char __user *filename);
asmlinkage long sys_fchmod(unsigned int fd, umode_t mode);
asmlinkage long sys_fchmodat(int dfd, const char __user *filename, umode_t mode);
asmlinkage long sys_fchmodat2(int dfd, const char __user *filename, umode_t mode, unsigned int flags);
asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group, int flag);
asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group);
asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, umode_t mode);
asmlinkage long sys_openat2(int dfd, const char __user *filename, struct open_how __user *how, size_t size);
asmlinkage long sys_close(unsigned int fd);
asmlinkage long sys_close_range(unsigned int fd, unsigned int max_fd, unsigned int flags);
asmlinkage long sys_vhangup(void);
asmlinkage long sys_pipe2(int __user *fildes, int flags);
asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t id, void __user *addr);
asmlinkage long sys_quotactl_fd(unsigned int fd, unsigned int cmd, qid_t id, void __user *addr);
asmlinkage long sys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count);
asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t __user *result, unsigned int whence);
asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int whence);
asmlinkage long sys_read(unsigned int fd, char __user *buf, size_t count);
asmlinkage long sys_write(unsigned int fd, const char __user *buf, size_t count);
asmlinkage long sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen);
asmlinkage long sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen);
asmlinkage long sys_pread64(unsigned int fd, char __user *buf, size_t count, loff_t pos);
asmlinkage long sys_pwrite64(unsigned int fd, const char __user *buf, size_t count, loff_t pos);
asmlinkage long sys_preadv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h);
asmlinkage long sys_pwritev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h);
asmlinkage long sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count);
!asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct __kernel_timespec __user *tsp, void __user *sig);
!asmlinkage long sys_pselect6_time32(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct old_timespec32 __user *tsp, void __user *sig);
!asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds, struct __kernel_timespec __user *tsp, const sigset_t __user *sigmask, size_t sigsetsize);
!asmlinkage long sys_ppoll_time32(struct pollfd __user *ufds, unsigned int nfds, struct old_timespec32 __user *tsp, const sigset_t __user *sigmask, size_t sigsetsize);
asmlinkage long sys_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask, int flags);
asmlinkage long sys_vmsplice(int fd, const struct iovec __user *iov, unsigned long nr_segs, unsigned int flags);
asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, int fd_out, loff_t __user *off_out, size_t len, unsigned int flags);
asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags);
asmlinkage long sys_readlinkat(int dfd, const char __user *path, char __user *buf, int bufsiz);
asmlinkage long sys_newfstatat(int dfd, const char __user *filename, struct stat __user *statbuf, int flag);
asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf);
asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf);
asmlinkage long sys_fstatat64(int dfd, const char __user *filename, struct stat64 __user *statbuf, int flag);
asmlinkage long sys_sync(void);
asmlinkage long sys_fsync(unsigned int fd);
asmlinkage long sys_fdatasync(unsigned int fd);
asmlinkage long sys_sync_file_range2(int fd, unsigned int flags, loff_t offset, loff_t nbytes);
asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, unsigned int flags);
asmlinkage long sys_timerfd_create(int clockid, int flags);
asmlinkage long sys_timerfd_settime(int ufd, int flags, const struct __kernel_itimerspec __user *utmr, struct __kernel_itimerspec __user *otmr);
asmlinkage long sys_timerfd_gettime(int ufd, struct __kernel_itimerspec __user *otmr);
asmlinkage long sys_timerfd_gettime32(int ufd, struct old_itimerspec32 __user *otmr);
asmlinkage long sys_timerfd_settime32(int ufd, int flags, const struct old_itimerspec32 __user *utmr, struct old_itimerspec32 __user *otmr);
asmlinkage long sys_utimensat(int dfd, const char __user *filename, struct __kernel_timespec __user *utimes, int flags);
asmlinkage long sys_utimensat_time32(unsigned int dfd, const char __user *filename, struct old_timespec32 __user *t, int flags);
asmlinkage long sys_acct(const char __user *name);
asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr);
asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data);
asmlinkage long sys_personality(unsigned int personality);
asmlinkage long sys_exit(int error_code);
asmlinkage long sys_exit_group(int error_code);
asmlinkage long sys_waitid(int which, pid_t pid, struct siginfo __user *infop, int options, struct rusage __user *ru);
asmlinkage long sys_set_tid_address(int __user *tidptr);
asmlinkage long sys_unshare(unsigned long unshare_flags);
asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val, const struct __kernel_timespec __user *utime, u32 __user *uaddr2, u32 val3);
asmlinkage long sys_futex_time32(u32 __user *uaddr, int op, u32 val, const struct old_timespec32 __user *utime, u32 __user *uaddr2, u32 val3);
asmlinkage long sys_get_robust_list(int pid, struct robust_list_head __user *__user *head_ptr, size_t __user *len_ptr);
asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len);
asmlinkage long sys_futex_waitv(struct futex_waitv __user *waiters, unsigned int nr_futexes, unsigned int flags, struct __kernel_timespec __user *timeout, clockid_t clockid);
asmlinkage long sys_futex_wake(void __user *uaddr, unsigned long mask, int nr, unsigned int flags);
asmlinkage long sys_futex_wait(void __user *uaddr, unsigned long val, unsigned long mask, unsigned int flags, struct __kernel_timespec __user *timespec, clockid_t clockid);
asmlinkage long sys_futex_requeue(struct futex_waitv __user *waiters, unsigned int flags, int nr_wake, int nr_requeue);
asmlinkage long sys_nanosleep(struct __kernel_timespec __user *rqtp, struct __kernel_timespec __user *rmtp);
asmlinkage long sys_nanosleep_time32(struct old_timespec32 __user *rqtp, struct old_timespec32 __user *rmtp);
asmlinkage long sys_getitimer(int which, struct __kernel_old_itimerval __user *value);
asmlinkage long sys_setitimer(int which, struct __kernel_old_itimerval __user *value, struct __kernel_old_itimerval __user *ovalue);
asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, unsigned long flags);
asmlinkage long sys_init_module(void __user *umod, unsigned long len, const char __user *uargs);
asmlinkage long sys_delete_module(const char __user *name_user, unsigned int flags);
asmlinkage long sys_timer_create(clockid_t which_clock, struct sigevent __user *timer_event_spec, timer_t __user *created_timer_id);
asmlinkage long sys_timer_gettime(timer_t timer_id, struct __kernel_itimerspec __user *setting);
asmlinkage long sys_timer_getoverrun(timer_t timer_id);
asmlinkage long sys_timer_settime(timer_t timer_id, int flags, const struct __kernel_itimerspec __user *new_setting, struct __kernel_itimerspec __user *old_setting);
asmlinkage long sys_timer_delete(timer_t timer_id);
asmlinkage long sys_clock_settime(clockid_t which_clock, const struct __kernel_timespec __user *tp);
asmlinkage long sys_clock_gettime(clockid_t which_clock, struct __kernel_timespec __user *tp);
asmlinkage long sys_clock_getres(clockid_t which_clock, struct __kernel_timespec __user *tp);
asmlinkage long sys_clock_nanosleep(clockid_t which_clock, int flags, const struct __kernel_timespec __user *rqtp, struct __kernel_timespec __user *rmtp);
asmlinkage long sys_timer_gettime32(timer_t timer_id, struct old_itimerspec32 __user *setting);
asmlinkage long sys_timer_settime32(timer_t timer_id, int flags, struct old_itimerspec32 __user *new, struct old_itimerspec32 __user *old);
asmlinkage long sys_clock_settime32(clockid_t which_clock, struct old_timespec32 __user *tp);
asmlinkage long sys_clock_gettime32(clockid_t which_clock, struct old_timespec32 __user *tp);
asmlinkage long sys_clock_getres_time32(clockid_t which_clock, struct old_timespec32 __user *tp);
asmlinkage long sys_clock_nanosleep_time32(clockid_t which_clock, int flags, struct old_timespec32 __user *rqtp, struct old_timespec32 __user *rmtp);
asmlinkage long sys_syslog(int type, char __user *buf, int len);
asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, unsigned long data);
asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param __user *param);
asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param);
asmlinkage long sys_sched_getscheduler(pid_t pid);
asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param __user *param);
asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, unsigned long __user *user_mask_ptr);
asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len, unsigned long __user *user_mask_ptr);
asmlinkage long sys_sched_yield(void);
asmlinkage long sys_sched_get_priority_max(int policy);
asmlinkage long sys_sched_get_priority_min(int policy);
asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct __kernel_timespec __user *interval);
asmlinkage long sys_sched_rr_get_interval_time32(pid_t pid, struct old_timespec32 __user *interval);
asmlinkage long sys_restart_syscall(void);
asmlinkage long sys_kill(pid_t pid, int sig);
asmlinkage long sys_tkill(pid_t pid, int sig);
asmlinkage long sys_tgkill(pid_t tgid, pid_t pid, int sig);
asmlinkage long sys_sigaltstack(const struct sigaltstack __user *uss, struct sigaltstack __user *uoss);
asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize);
!asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act, struct sigaction __user *oact, size_t sigsetsize);
asmlinkage long sys_rt_sigprocmask(int how, sigset_t __user *set, sigset_t __user *oset, size_t sigsetsize);
asmlinkage long sys_rt_sigpending(sigset_t __user *set, size_t sigsetsize);
asmlinkage long sys_rt_sigtimedwait(const sigset_t __user *uthese, siginfo_t __user *uinfo, const struct __kernel_timespec __user *uts, size_t sigsetsize);
asmlinkage long sys_rt_sigtimedwait_time32(const sigset_t __user *uthese, siginfo_t __user *uinfo, const struct old_timespec32 __user *uts, size_t sigsetsize);
asmlinkage long sys_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t __user *uinfo);
asmlinkage long sys_setpriority(int which, int who, int niceval);
asmlinkage long sys_getpriority(int which, int who);
asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user *arg);
asmlinkage long sys_setregid(gid_t rgid, gid_t egid);
asmlinkage long sys_setgid(gid_t gid);
asmlinkage long sys_setreuid(uid_t ruid, uid_t euid);
asmlinkage long sys_setuid(uid_t uid);
asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid);
asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid);
asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid);
asmlinkage long sys_setfsuid(uid_t uid);
asmlinkage long sys_setfsgid(gid_t gid);
asmlinkage long sys_times(struct tms __user *tbuf);
asmlinkage long sys_setpgid(pid_t pid, pid_t pgid);
asmlinkage long sys_getpgid(pid_t pid);
asmlinkage long sys_getsid(pid_t pid);
asmlinkage long sys_setsid(void);
asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist);
asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist);
asmlinkage long sys_newuname(struct new_utsname __user *name);
asmlinkage long sys_sethostname(char __user *name, int len);
asmlinkage long sys_setdomainname(char __user *name, int len);
asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit __user *rlim);
asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim);
asmlinkage long sys_getrusage(int who, struct rusage __user *ru);
asmlinkage long sys_umask(int mask);
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
asmlinkage long sys_gettimeofday(struct __kernel_old_timeval __user *tv, struct timezone __user *tz);
asmlinkage long sys_settimeofday(struct __kernel_old_timeval __user *tv, struct timezone __user *tz);
asmlinkage long sys_adjtimex(struct __kernel_timex __user *txc_p);
asmlinkage long sys_adjtimex_time32(struct old_timex32 __user *txc_p);
asmlinkage long sys_getpid(void);
asmlinkage long sys_getppid(void);
asmlinkage long sys_getuid(void);
asmlinkage long sys_geteuid(void);
asmlinkage long sys_getgid(void);
asmlinkage long sys_getegid(void);
asmlinkage long sys_gettid(void);
asmlinkage long sys_sysinfo(struct sysinfo __user *info);
asmlinkage long sys_mq_open(const char __user *name, int oflag, umode_t mode, struct mq_attr __user *attr);
asmlinkage long sys_mq_unlink(const char __user *name);
asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct __kernel_timespec __user *abs_timeout);
asmlinkage long sys_mq_timedreceive(mqd_t mqdes, char __user *msg_ptr, size_t msg_len, unsigned int __user *msg_prio, const struct __kernel_timespec __user *abs_timeout);
asmlinkage long sys_mq_notify(mqd_t mqdes, const struct sigevent __user *notification);
asmlinkage long sys_mq_getsetattr(mqd_t mqdes, const struct mq_attr __user *mqstat, struct mq_attr __user *omqstat);
asmlinkage long sys_mq_timedreceive_time32(mqd_t mqdes, char __user *u_msg_ptr, unsigned int msg_len, unsigned int __user *u_msg_prio, const struct old_timespec32 __user *u_abs_timeout);
asmlinkage long sys_mq_timedsend_time32(mqd_t mqdes, const char __user *u_msg_ptr, unsigned int msg_len, unsigned int msg_prio, const struct old_timespec32 __user *u_abs_timeout);
asmlinkage long sys_msgget(key_t key, int msgflg);
asmlinkage long sys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, long msgtyp, int msgflg);
asmlinkage long sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg);
asmlinkage long sys_semget(key_t key, int nsems, int semflg);
asmlinkage long sys_semctl(int semid, int semnum, int cmd, unsigned long arg);
asmlinkage long sys_old_semctl(int semid, int semnum, int cmd, unsigned long arg);
asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, unsigned nsops, const struct __kernel_timespec __user *timeout);
asmlinkage long sys_semtimedop_time32(int semid, struct sembuf __user *sops, unsigned nsops, const struct old_timespec32 __user *timeout);
asmlinkage long sys_semop(int semid, struct sembuf __user *sops, unsigned nsops);
asmlinkage long sys_shmget(key_t key, size_t size, int flag);
asmlinkage long sys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg);
asmlinkage long sys_shmdt(char __user *shmaddr);
!asmlinkage long sys_socket(int family, int type, int protocol);
!asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *usockvec);
!asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen);
!asmlinkage long sys_listen(int fd, int backlog);
!asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen);
!asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen);
!asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len);
!asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len);
!asmlinkage long sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags, struct sockaddr __user *addr, int addr_len);
!asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags, struct sockaddr __user *addr, int __user *addr_len);
asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen);
asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen);
!asmlinkage long sys_shutdown(int fd, int how);
asmlinkage long sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags);
asmlinkage long sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags);
asmlinkage long sys_readahead(int fd, loff_t offset, size_t count);
asmlinkage long sys_brk(unsigned long brk);
asmlinkage long sys_munmap(unsigned long addr, size_t len);
asmlinkage long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr);
asmlinkage long sys_add_key(const char __user *_type, const char __user *_description, const void __user *_payload, size_t plen, key_serial_t destringid);
asmlinkage long sys_request_key(const char __user *_type, const char __user *_description, const char __user *_callout_info, key_serial_t destringid);
asmlinkage long sys_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
#asmlinkage long sys_clone(unsigned long, unsigned long, int __user *, unsigned long, int __user *);
#asmlinkage long sys_clone(unsigned long, unsigned long, int, int __user *, int __user *, unsigned long);
#asmlinkage long sys_clone(unsigned long, unsigned long, int __user *, int __user *, unsigned long);
asmlinkage long sys_clone3(struct clone_args __user *uargs, size_t size);
asmlinkage long sys_execve(const char __user *filename, const char __user *const __user *argv, const char __user *const __user *envp);
asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice);
asmlinkage long sys_swapon(const char __user *specialfile, int swap_flags);
asmlinkage long sys_swapoff(const char __user *specialfile);
asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot);
asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
asmlinkage long sys_mlock(unsigned long start, size_t len);
asmlinkage long sys_munlock(unsigned long start, size_t len);
asmlinkage long sys_mlockall(int flags);
asmlinkage long sys_munlockall(void);
asmlinkage long sys_mincore(unsigned long start, size_t len, unsigned char __user *vec);
asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior);
asmlinkage long sys_process_madvise(int pidfd, const struct iovec __user *vec, size_t vlen, int behavior, unsigned int flags);
asmlinkage long sys_process_mrelease(int pidfd, unsigned int flags);
asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, unsigned long flags);
asmlinkage long sys_mseal(unsigned long start, size_t len, unsigned long flags);
asmlinkage long sys_mbind(unsigned long start, unsigned long len, unsigned long mode, const unsigned long __user *nmask, unsigned long maxnode, unsigned flags);
asmlinkage long sys_get_mempolicy(int __user *policy, unsigned long __user *nmask, unsigned long maxnode, unsigned long addr, unsigned long flags);
asmlinkage long sys_set_mempolicy(int mode, const unsigned long __user *nmask, unsigned long maxnode);
asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode, const unsigned long __user *from, const unsigned long __user *to);
asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, const void __user *__user *pages, const int __user *nodes, int __user *status, int flags);
asmlinkage long sys_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t __user *uinfo);
asmlinkage long sys_perf_event_open(struct perf_event_attr __user *attr_uptr, pid_t pid, int cpu, int group_fd, unsigned long flags);
!asmlinkage long sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen, int flags);
asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg, unsigned int vlen, unsigned flags, struct __kernel_timespec __user *timeout);
asmlinkage long sys_recvmmsg_time32(int fd, struct mmsghdr __user *msg, unsigned int vlen, unsigned flags, struct old_timespec32 __user *timeout);
asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr, int options, struct rusage __user *ru);
asmlinkage long sys_prlimit64(pid_t pid, unsigned int resource, const struct rlimit64 __user *new_rlim, struct rlimit64 __user *old_rlim);
asmlinkage long sys_fanotify_init(unsigned int flags, unsigned int event_f_flags);
#asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags, unsigned int mask_1, unsigned int mask_2, int dfd, const char __user *pathname);
#asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags, u64 mask, int fd, const char __user *pathname);
asmlinkage long sys_name_to_handle_at(int dfd, const char __user *name, struct file_handle __user *handle, int __user *mnt_id, int flag);
asmlinkage long sys_open_by_handle_at(int mountdirfd, struct file_handle __user *handle, int flags);
asmlinkage long sys_clock_adjtime(clockid_t which_clock, struct __kernel_timex __user *tx);
asmlinkage long sys_clock_adjtime32(clockid_t which_clock, struct old_timex32 __user *tx);
asmlinkage long sys_syncfs(int fd);
asmlinkage long sys_setns(int fd, int nstype);
asmlinkage long sys_pidfd_open(pid_t pid, unsigned int flags);
asmlinkage long sys_sendmmsg(int fd, struct mmsghdr __user *msg, unsigned int vlen, unsigned flags);
asmlinkage long sys_process_vm_readv(pid_t pid, const struct iovec __user *lvec, unsigned long liovcnt, const struct iovec __user *rvec, unsigned long riovcnt, unsigned long flags);
asmlinkage long sys_process_vm_writev(pid_t pid, const struct iovec __user *lvec, unsigned long liovcnt, const struct iovec __user *rvec, unsigned long riovcnt, unsigned long flags);
asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2);
asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
asmlinkage long sys_sched_setattr(pid_t pid, struct sched_attr __user *attr, unsigned int flags);
asmlinkage long sys_sched_getattr(pid_t pid, struct sched_attr __user *attr, unsigned int size, unsigned int flags);
asmlinkage long sys_renameat2(int olddfd, const char __user *oldname, int newdfd, const char __user *newname, unsigned int flags);
asmlinkage long sys_seccomp(unsigned int op, unsigned int flags, void __user *uargs);
asmlinkage long sys_getrandom(char __user *buf, size_t count, unsigned int flags);
asmlinkage long sys_memfd_create(const char __user *uname_ptr, unsigned int flags);
asmlinkage long sys_bpf(int cmd, union bpf_attr __user *attr, unsigned int size);
asmlinkage long sys_execveat(int dfd, const char __user *filename, const char __user *const __user *argv, const char __user *const __user *envp, int flags);
asmlinkage long sys_userfaultfd(int flags);
asmlinkage long sys_membarrier(int cmd, unsigned int flags, int cpu_id);
asmlinkage long sys_mlock2(unsigned long start, size_t len, int flags);
asmlinkage long sys_copy_file_range(int fd_in, loff_t __user *off_in, int fd_out, loff_t __user *off_out, size_t len, unsigned int flags);
asmlinkage long sys_preadv2(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, rwf_t flags);
asmlinkage long sys_pwritev2(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h, rwf_t flags);
asmlinkage long sys_pkey_mprotect(unsigned long start, size_t len, unsigned long prot, int pkey);
asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);
asmlinkage long sys_pkey_free(int pkey);
asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, unsigned mask, struct statx __user *buffer);
asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len, int flags, uint32_t sig);
asmlinkage long sys_open_tree(int dfd, const char __user *path, unsigned flags);
asmlinkage long sys_move_mount(int from_dfd, const char __user *from_path, int to_dfd, const char __user *to_path, unsigned int ms_flags);
asmlinkage long sys_mount_setattr(int dfd, const char __user *path, unsigned int flags, struct mount_attr __user *uattr, size_t usize);
asmlinkage long sys_fsopen(const char __user *fs_name, unsigned int flags);
asmlinkage long sys_fsconfig(int fs_fd, unsigned int cmd, const char __user *key, const void __user *value, int aux);
asmlinkage long sys_fsmount(int fs_fd, unsigned int flags, unsigned int ms_flags);
asmlinkage long sys_fspick(int dfd, const char __user *path, unsigned int flags);
asmlinkage long sys_pidfd_send_signal(int pidfd, int sig, siginfo_t __user *info, unsigned int flags);
asmlinkage long sys_pidfd_getfd(int pidfd, int fd, unsigned int flags);
asmlinkage long sys_landlock_create_ruleset(const struct landlock_ruleset_attr __user *attr, size_t size, __u32 flags);
asmlinkage long sys_landlock_add_rule(int ruleset_fd, enum landlock_rule_type rule_type, const void __user *rule_attr, __u32 flags);
asmlinkage long sys_landlock_restrict_self(int ruleset_fd, __u32 flags);
asmlinkage long sys_memfd_secret(unsigned int flags);
asmlinkage long sys_set_mempolicy_home_node(unsigned long start, unsigned long len, unsigned long home_node, unsigned long flags);
asmlinkage long sys_cachestat(unsigned int fd, struct cachestat_range __user *cstat_range, struct cachestat __user *cstat, unsigned int flags);
asmlinkage long sys_map_shadow_stack(unsigned long addr, unsigned long size, unsigned int flags);
asmlinkage long sys_lsm_get_self_attr(unsigned int attr, struct lsm_ctx __user *ctx, u32 __user *size, u32 flags);
asmlinkage long sys_lsm_set_self_attr(unsigned int attr, struct lsm_ctx __user *ctx, u32 size, u32 flags);
asmlinkage long sys_lsm_list_modules(u64 __user *ids, u32 __user *size, u32 flags);
asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, void __user *buf);
asmlinkage long sys_pciconfig_write(unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, void __user *buf);
asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn);
asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus);
asmlinkage long sys_spu_create(const char __user *name, unsigned int flags, umode_t mode, int fd);
asmlinkage long sys_open(const char __user *filename, int flags, umode_t mode);
asmlinkage long sys_link(const char __user *oldname, const char __user *newname);
asmlinkage long sys_unlink(const char __user *pathname);
asmlinkage long sys_mknod(const char __user *filename, umode_t mode, unsigned dev);
asmlinkage long sys_chmod(const char __user *filename, umode_t mode);
asmlinkage long sys_chown(const char __user *filename, uid_t user, gid_t group);
asmlinkage long sys_mkdir(const char __user *pathname, umode_t mode);
asmlinkage long sys_rmdir(const char __user *pathname);
asmlinkage long sys_lchown(const char __user *filename, uid_t user, gid_t group);
asmlinkage long sys_access(const char __user *filename, int mode);
asmlinkage long sys_rename(const char __user *oldname, const char __user *newname);
asmlinkage long sys_symlink(const char __user *old, const char __user *new);
asmlinkage long sys_stat64(const char __user *filename, struct stat64 __user *statbuf);
asmlinkage long sys_lstat64(const char __user *filename, struct stat64 __user *statbuf);
asmlinkage long sys_pipe(int __user *fildes);
asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd);
asmlinkage long sys_epoll_create(int size);
asmlinkage long sys_inotify_init(void);
asmlinkage long sys_eventfd(unsigned int count);
asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask);
asmlinkage long sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count);
asmlinkage long sys_newstat(const char __user *filename, struct stat __user *statbuf);
asmlinkage long sys_newlstat(const char __user *filename, struct stat __user *statbuf);
asmlinkage long sys_fadvise64(int fd, loff_t offset, size_t len, int advice);
asmlinkage long sys_alarm(unsigned int seconds);
asmlinkage long sys_getpgrp(void);
asmlinkage long sys_pause(void);
asmlinkage long sys_time(__kernel_old_time_t __user *tloc);
asmlinkage long sys_time32(old_time32_t __user *tloc);
asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times);
asmlinkage long sys_utimes(char __user *filename, struct __kernel_old_timeval __user *utimes);
asmlinkage long sys_futimesat(int dfd, const char __user *filename, struct __kernel_old_timeval __user *utimes);
asmlinkage long sys_futimesat_time32(unsigned int dfd, const char __user *filename, struct old_timeval32 __user *t);
asmlinkage long sys_utime32(const char __user *filename, struct old_utimbuf32 __user *t);
asmlinkage long sys_utimes_time32(const char __user *filename, struct old_timeval32 __user *t);
asmlinkage long sys_creat(const char __user *pathname, umode_t mode);
asmlinkage long sys_getdents(unsigned int fd, struct linux_dirent __user *dirent, unsigned int count);
asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct __kernel_old_timeval __user *tvp);
asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, int timeout);
asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, int maxevents, int timeout);
asmlinkage long sys_ustat(unsigned dev, struct ustat __user *ubuf);
asmlinkage long sys_vfork(void);
asmlinkage long sys_recv(int, void __user *, size_t, unsigned);
asmlinkage long sys_send(int, void __user *, size_t, unsigned);
asmlinkage long sys_oldumount(char __user *name);
asmlinkage long sys_uselib(const char __user *library);
asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
asmlinkage long sys_fork(void);
asmlinkage long sys_stime(__kernel_old_time_t __user *tptr);
asmlinkage long sys_stime32(old_time32_t __user *tptr);
asmlinkage long sys_sigpending(old_sigset_t __user *uset);
asmlinkage long sys_sigprocmask(int how, old_sigset_t __user *set, old_sigset_t __user *oset);
asmlinkage long sys_sigsuspend(old_sigset_t mask);
#asmlinkage long sys_sigsuspend(int unused1, int unused2, old_sigset_t mask);
asmlinkage long sys_sigaction(int, const struct old_sigaction __user *, struct old_sigaction __user *);
asmlinkage long sys_sgetmask(void);
asmlinkage long sys_ssetmask(int newmask);
asmlinkage long sys_signal(int sig, __sighandler_t handler);
asmlinkage long sys_nice(int increment);
asmlinkage long sys_kexec_file_load(int kernel_fd, int initrd_fd, unsigned long cmdline_len, const char __user *cmdline_ptr, unsigned long flags);
asmlinkage long sys_waitpid(pid_t pid, int __user *stat_addr, int options);
asmlinkage long sys_chown16(const char __user *filename, old_uid_t user, old_gid_t group);
asmlinkage long sys_lchown16(const char __user *filename, old_uid_t user, old_gid_t group);
asmlinkage long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group);
asmlinkage long sys_setregid16(old_gid_t rgid, old_gid_t egid);
asmlinkage long sys_setgid16(old_gid_t gid);
asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid);
asmlinkage long sys_setuid16(old_uid_t uid);
asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid);
asmlinkage long sys_getresuid16(old_uid_t __user *ruid, old_uid_t __user *euid, old_uid_t __user *suid);
asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid);
asmlinkage long sys_getresgid16(old_gid_t __user *rgid, old_gid_t __user *egid, old_gid_t __user *sgid);
asmlinkage long sys_setfsuid16(old_uid_t uid);
asmlinkage long sys_setfsgid16(old_gid_t gid);
asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist);
asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t __user *grouplist);
asmlinkage long sys_getuid16(void);
asmlinkage long sys_geteuid16(void);
asmlinkage long sys_getgid16(void);
asmlinkage long sys_getegid16(void);
asmlinkage long sys_socketcall(int call, unsigned long __user *args);
asmlinkage long sys_stat(const char __user *filename, struct __old_kernel_stat __user *statbuf);
asmlinkage long sys_lstat(const char __user *filename, struct __old_kernel_stat __user *statbuf);
asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat __user *statbuf);
asmlinkage long sys_readlink(const char __user *path, char __user *buf, int bufsiz);
asmlinkage long sys_old_select(struct sel_arg_struct __user *arg);
asmlinkage long sys_old_readdir(unsigned int, struct old_linux_dirent __user *, unsigned int);
asmlinkage long sys_gethostname(char __user *name, int len);
asmlinkage long sys_uname(struct old_utsname __user *);
asmlinkage long sys_olduname(struct oldold_utsname __user *);
asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim);
asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second, unsigned long third, void __user *ptr, long fifth);
asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff);
asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg);
#asmlinkage long sys_ni_syscall(void);
asmlinkage long sys_ni_posix_timers(void);
"""

# include/linux/compat.h
syscall_defs_compat = """
asmlinkage long compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p);
asmlinkage long compat_sys_io_submit(compat_aio_context_t ctx_id, int nr, u32 __user *iocb);
asmlinkage long compat_sys_io_pgetevents(compat_aio_context_t ctx_id, compat_long_t min_nr, compat_long_t nr, struct io_event __user *events, struct old_timespec32 __user *timeout, const struct __compat_aio_sigset __user *usig);
asmlinkage long compat_sys_io_pgetevents_time64(compat_aio_context_t ctx_id, compat_long_t min_nr, compat_long_t nr, struct io_event __user *events, struct __kernel_timespec __user *timeout, const struct __compat_aio_sigset __user *usig);
asmlinkage long compat_sys_epoll_pwait(int epfd, struct epoll_event __user *events, int maxevents, int timeout, const compat_sigset_t __user *sigmask, compat_size_t sigsetsize);
asmlinkage long compat_sys_epoll_pwait2(int epfd, struct epoll_event __user *events, int maxevents, const struct __kernel_timespec __user *timeout, const compat_sigset_t __user *sigmask, compat_size_t sigsetsize);
asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd, compat_ulong_t arg);
asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, compat_ulong_t arg);
asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, compat_ulong_t arg);
asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf);
asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf);
asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf);
asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf);
asmlinkage long compat_sys_truncate(const char __user *, compat_off_t);
asmlinkage long compat_sys_ftruncate(unsigned int, compat_off_t);
asmlinkage long compat_sys_openat(int dfd, const char __user *filename, int flags, umode_t mode);
asmlinkage long compat_sys_getdents(unsigned int fd, struct compat_linux_dirent __user *dirent, unsigned int count);
asmlinkage long compat_sys_lseek(unsigned int, compat_off_t, unsigned int);
asmlinkage ssize_t compat_sys_preadv(compat_ulong_t fd, const struct iovec __user *vec, compat_ulong_t vlen, u32 pos_low, u32 pos_high);
asmlinkage ssize_t compat_sys_pwritev(compat_ulong_t fd, const struct iovec __user *vec, compat_ulong_t vlen, u32 pos_low, u32 pos_high);
asmlinkage long compat_sys_preadv64(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, loff_t pos);
asmlinkage long compat_sys_pwritev64(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, loff_t pos);
asmlinkage long compat_sys_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, compat_size_t count);
asmlinkage long compat_sys_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, compat_size_t count);
asmlinkage long compat_sys_pselect6_time32(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, struct old_timespec32 __user *tsp, void __user *sig);
asmlinkage long compat_sys_pselect6_time64(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, struct __kernel_timespec __user *tsp, void __user *sig);
asmlinkage long compat_sys_ppoll_time32(struct pollfd __user *ufds, unsigned int nfds, struct old_timespec32 __user *tsp, const compat_sigset_t __user *sigmask, compat_size_t sigsetsize);
asmlinkage long compat_sys_ppoll_time64(struct pollfd __user *ufds, unsigned int nfds, struct __kernel_timespec __user *tsp, const compat_sigset_t __user *sigmask, compat_size_t sigsetsize);
asmlinkage long compat_sys_signalfd4(int ufd, const compat_sigset_t __user *sigmask, compat_size_t sigsetsize, int flags);
asmlinkage long compat_sys_newfstatat(unsigned int dfd, const char __user *filename, struct compat_stat __user *statbuf, int flag);
asmlinkage long compat_sys_newfstat(unsigned int fd, struct compat_stat __user *statbuf);
!asmlinkage long compat_sys_waitid(int which, compat_pid_t pid, struct compat_siginfo __user *waitid, int options, struct compat_rusage __user *uru);
asmlinkage long compat_sys_set_robust_list(struct compat_robust_list_head __user *head, compat_size_t len);
asmlinkage long compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, compat_size_t __user *len_ptr);
asmlinkage long compat_sys_getitimer(int which, struct old_itimerval32 __user *it);
asmlinkage long compat_sys_setitimer(int which, struct old_itimerval32 __user *in, struct old_itimerval32 __user *out);
!asmlinkage long compat_sys_kexec_load(compat_ulong_t entry, compat_ulong_t nr_segments, struct compat_kexec_segment __user *segments, compat_ulong_t flags);
asmlinkage long compat_sys_timer_create(clockid_t which_clock, struct compat_sigevent __user *timer_event_spec, timer_t __user *created_timer_id);
asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, compat_long_t addr, compat_long_t data);
asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid, unsigned int len, compat_ulong_t __user *user_mask_ptr);
asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len, compat_ulong_t __user *user_mask_ptr);
asmlinkage long compat_sys_sigaltstack(const compat_stack_t __user *uss_ptr, compat_stack_t __user *uoss_ptr);
asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize);
!asmlinkage long compat_sys_rt_sigaction(int sig, const struct compat_sigaction __user *act, struct compat_sigaction __user *oact, compat_size_t sigsetsize);
asmlinkage long compat_sys_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t __user *oset, compat_size_t sigsetsize);
asmlinkage long compat_sys_rt_sigpending(compat_sigset_t __user *uset, compat_size_t sigsetsize);
asmlinkage long compat_sys_rt_sigtimedwait_time32(compat_sigset_t __user *uthese, struct compat_siginfo __user *uinfo, struct old_timespec32 __user *uts, compat_size_t sigsetsize);
asmlinkage long compat_sys_rt_sigtimedwait_time64(compat_sigset_t __user *uthese, struct compat_siginfo __user *uinfo, struct __kernel_timespec __user *uts, compat_size_t sigsetsize);
asmlinkage long compat_sys_rt_sigqueueinfo(compat_pid_t pid, int sig, struct compat_siginfo __user *uinfo);
asmlinkage long compat_sys_times(struct compat_tms __user *tbuf);
asmlinkage long compat_sys_getrlimit(unsigned int resource, struct compat_rlimit __user *rlim);
asmlinkage long compat_sys_setrlimit(unsigned int resource, struct compat_rlimit __user *rlim);
asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru);
asmlinkage long compat_sys_gettimeofday(struct old_timeval32 __user *tv, struct timezone __user *tz);
asmlinkage long compat_sys_settimeofday(struct old_timeval32 __user *tv, struct timezone __user *tz);
asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info);
asmlinkage long compat_sys_mq_open(const char __user *u_name, int oflag, compat_mode_t mode, struct compat_mq_attr __user *u_attr);
asmlinkage long compat_sys_mq_notify(mqd_t mqdes, const struct compat_sigevent __user *u_notification);
asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes, const struct compat_mq_attr __user *u_mqstat, struct compat_mq_attr __user *u_omqstat);
asmlinkage long compat_sys_msgctl(int first, int second, void __user *uptr);
asmlinkage long compat_sys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz, compat_long_t msgtyp, int msgflg);
asmlinkage long compat_sys_msgsnd(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz, int msgflg);
asmlinkage long compat_sys_semctl(int semid, int semnum, int cmd, int arg);
asmlinkage long compat_sys_shmctl(int first, int second, void __user *uptr);
asmlinkage long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg);
asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, compat_size_t len, unsigned flags, struct sockaddr __user *addr, int __user *addrlen);
asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags);
asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags);
asmlinkage long compat_sys_keyctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5);
asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv, const compat_uptr_t __user *envp);
asmlinkage long compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid, compat_pid_t pid, int sig, struct compat_siginfo __user *uinfo);
asmlinkage long compat_sys_recvmmsg_time64(int fd, struct compat_mmsghdr __user *mmsg, unsigned vlen, unsigned int flags, struct __kernel_timespec __user *timeout);
asmlinkage long compat_sys_recvmmsg_time32(int fd, struct compat_mmsghdr __user *mmsg, unsigned vlen, unsigned int flags, struct old_timespec32 __user *timeout);
asmlinkage long compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options, struct compat_rusage __user *ru);
!asmlinkage long compat_sys_fanotify_mark(int fanotify_fd, unsigned int flags, __u32 mask_1, __u32 mask_2, int dfd, const char __user *pathname);
asmlinkage long compat_sys_open_by_handle_at(int mountdirfd, struct file_handle __user *handle, int flags);
asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg, unsigned vlen, unsigned int flags);
asmlinkage long compat_sys_execveat(int dfd, const char __user *filename, const compat_uptr_t __user *argv, const compat_uptr_t __user *envp, int flags);
asmlinkage ssize_t compat_sys_preadv2(compat_ulong_t fd, const struct iovec __user *vec, compat_ulong_t vlen, u32 pos_low, u32 pos_high, rwf_t flags);
asmlinkage ssize_t compat_sys_pwritev2(compat_ulong_t fd, const struct iovec __user *vec, compat_ulong_t vlen, u32 pos_low, u32 pos_high, rwf_t flags);
asmlinkage long compat_sys_preadv64v2(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, loff_t pos, rwf_t flags);
asmlinkage long compat_sys_pwritev64v2(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, loff_t pos, rwf_t flags);
asmlinkage long compat_sys_open(const char __user *filename, int flags, umode_t mode);
asmlinkage long compat_sys_signalfd(int ufd, const compat_sigset_t __user *sigmask, compat_size_t sigsetsize);
asmlinkage long compat_sys_newstat(const char __user *filename, struct compat_stat __user *statbuf);
asmlinkage long compat_sys_newlstat(const char __user *filename, struct compat_stat __user *statbuf);
asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, struct old_timeval32 __user *tvp);
asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32);
asmlinkage long compat_sys_recv(int fd, void __user *buf, compat_size_t len, unsigned flags);
asmlinkage long compat_sys_old_readdir(unsigned int fd, struct compat_old_linux_dirent __user *, unsigned int count);
asmlinkage long compat_sys_old_select(struct compat_sel_arg_struct __user *arg);
asmlinkage long compat_sys_ipc(u32, int, int, u32, compat_uptr_t, u32);
asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set);
asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *nset, compat_old_sigset_t __user *oset);
asmlinkage long compat_sys_sigaction(int sig, const struct compat_old_sigaction __user *act, struct compat_old_sigaction __user *oact);
asmlinkage long compat_sys_socketcall(int call, u32 __user *args);
asmlinkage long compat_sys_truncate64(const char __user *pathname, compat_arg_u64(len));
asmlinkage long compat_sys_ftruncate64(unsigned int fd, compat_arg_u64(len));
asmlinkage long compat_sys_fallocate(int fd, int mode, compat_arg_u64(offset), compat_arg_u64(len));
asmlinkage long compat_sys_pread64(unsigned int fd, char __user *buf, size_t count, compat_arg_u64(pos));
asmlinkage long compat_sys_pwrite64(unsigned int fd, const char __user *buf, size_t count, compat_arg_u64(pos));
asmlinkage long compat_sys_sync_file_range(int fd, compat_arg_u64(pos), compat_arg_u64(nbytes), unsigned int flags);
asmlinkage long compat_sys_fadvise64_64(int fd, compat_arg_u64(pos), compat_arg_u64(len), int advice);
asmlinkage long compat_sys_readahead(int fd, compat_arg_u64(offset), size_t count);
"""


# x86_64
# - arch/x86/entry/syscalls/syscall_64.tbl
x64_syscall_tbl = """
#
# 64-bit system call numbers and entry vectors
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The __x64_sys_*() stubs are created on-the-fly for sys_*() system calls
#
# The abi is "common", "64" or "x32" for this file.
#
0       common  read                    sys_read
1       common  write                   sys_write
2       common  open                    sys_open
3       common  close                   sys_close
4       common  stat                    sys_newstat
5       common  fstat                   sys_newfstat
6       common  lstat                   sys_newlstat
7       common  poll                    sys_poll
8       common  lseek                   sys_lseek
9       common  mmap                    sys_mmap
10      common  mprotect                sys_mprotect
11      common  munmap                  sys_munmap
12      common  brk                     sys_brk
13      64      rt_sigaction            sys_rt_sigaction
14      common  rt_sigprocmask          sys_rt_sigprocmask
15      64      rt_sigreturn            sys_rt_sigreturn
16      64      ioctl                   sys_ioctl
17      common  pread64                 sys_pread64
18      common  pwrite64                sys_pwrite64
19      64      readv                   sys_readv
20      64      writev                  sys_writev
21      common  access                  sys_access
22      common  pipe                    sys_pipe
23      common  select                  sys_select
24      common  sched_yield             sys_sched_yield
25      common  mremap                  sys_mremap
26      common  msync                   sys_msync
27      common  mincore                 sys_mincore
28      common  madvise                 sys_madvise
29      common  shmget                  sys_shmget
30      common  shmat                   sys_shmat
31      common  shmctl                  sys_shmctl
32      common  dup                     sys_dup
33      common  dup2                    sys_dup2
34      common  pause                   sys_pause
35      common  nanosleep               sys_nanosleep
36      common  getitimer               sys_getitimer
37      common  alarm                   sys_alarm
38      common  setitimer               sys_setitimer
39      common  getpid                  sys_getpid
40      common  sendfile                sys_sendfile64
41      common  socket                  sys_socket
42      common  connect                 sys_connect
43      common  accept                  sys_accept
44      common  sendto                  sys_sendto
45      64      recvfrom                sys_recvfrom
46      64      sendmsg                 sys_sendmsg
47      64      recvmsg                 sys_recvmsg
48      common  shutdown                sys_shutdown
49      common  bind                    sys_bind
50      common  listen                  sys_listen
51      common  getsockname             sys_getsockname
52      common  getpeername             sys_getpeername
53      common  socketpair              sys_socketpair
54      64      setsockopt              sys_setsockopt
55      64      getsockopt              sys_getsockopt
56      common  clone                   sys_clone
57      common  fork                    sys_fork
58      common  vfork                   sys_vfork
59      64      execve                  sys_execve
60      common  exit                    sys_exit
61      common  wait4                   sys_wait4
62      common  kill                    sys_kill
63      common  uname                   sys_newuname
64      common  semget                  sys_semget
65      common  semop                   sys_semop
66      common  semctl                  sys_semctl
67      common  shmdt                   sys_shmdt
68      common  msgget                  sys_msgget
69      common  msgsnd                  sys_msgsnd
70      common  msgrcv                  sys_msgrcv
71      common  msgctl                  sys_msgctl
72      common  fcntl                   sys_fcntl
73      common  flock                   sys_flock
74      common  fsync                   sys_fsync
75      common  fdatasync               sys_fdatasync
76      common  truncate                sys_truncate
77      common  ftruncate               sys_ftruncate
78      common  getdents                sys_getdents
79      common  getcwd                  sys_getcwd
80      common  chdir                   sys_chdir
81      common  fchdir                  sys_fchdir
82      common  rename                  sys_rename
83      common  mkdir                   sys_mkdir
84      common  rmdir                   sys_rmdir
85      common  creat                   sys_creat
86      common  link                    sys_link
87      common  unlink                  sys_unlink
88      common  symlink                 sys_symlink
89      common  readlink                sys_readlink
90      common  chmod                   sys_chmod
91      common  fchmod                  sys_fchmod
92      common  chown                   sys_chown
93      common  fchown                  sys_fchown
94      common  lchown                  sys_lchown
95      common  umask                   sys_umask
96      common  gettimeofday            sys_gettimeofday
97      common  getrlimit               sys_getrlimit
98      common  getrusage               sys_getrusage
99      common  sysinfo                 sys_sysinfo
100     common  times                   sys_times
101     64      ptrace                  sys_ptrace
102     common  getuid                  sys_getuid
103     common  syslog                  sys_syslog
104     common  getgid                  sys_getgid
105     common  setuid                  sys_setuid
106     common  setgid                  sys_setgid
107     common  geteuid                 sys_geteuid
108     common  getegid                 sys_getegid
109     common  setpgid                 sys_setpgid
110     common  getppid                 sys_getppid
111     common  getpgrp                 sys_getpgrp
112     common  setsid                  sys_setsid
113     common  setreuid                sys_setreuid
114     common  setregid                sys_setregid
115     common  getgroups               sys_getgroups
116     common  setgroups               sys_setgroups
117     common  setresuid               sys_setresuid
118     common  getresuid               sys_getresuid
119     common  setresgid               sys_setresgid
120     common  getresgid               sys_getresgid
121     common  getpgid                 sys_getpgid
122     common  setfsuid                sys_setfsuid
123     common  setfsgid                sys_setfsgid
124     common  getsid                  sys_getsid
125     common  capget                  sys_capget
126     common  capset                  sys_capset
127     64      rt_sigpending           sys_rt_sigpending
128     64      rt_sigtimedwait         sys_rt_sigtimedwait
129     64      rt_sigqueueinfo         sys_rt_sigqueueinfo
130     common  rt_sigsuspend           sys_rt_sigsuspend
131     64      sigaltstack             sys_sigaltstack
132     common  utime                   sys_utime
133     common  mknod                   sys_mknod
134     64      uselib
135     common  personality             sys_personality
136     common  ustat                   sys_ustat
137     common  statfs                  sys_statfs
138     common  fstatfs                 sys_fstatfs
139     common  sysfs                   sys_sysfs
140     common  getpriority             sys_getpriority
141     common  setpriority             sys_setpriority
142     common  sched_setparam          sys_sched_setparam
143     common  sched_getparam          sys_sched_getparam
144     common  sched_setscheduler      sys_sched_setscheduler
145     common  sched_getscheduler      sys_sched_getscheduler
146     common  sched_get_priority_max  sys_sched_get_priority_max
147     common  sched_get_priority_min  sys_sched_get_priority_min
148     common  sched_rr_get_interval   sys_sched_rr_get_interval
149     common  mlock                   sys_mlock
150     common  munlock                 sys_munlock
151     common  mlockall                sys_mlockall
152     common  munlockall              sys_munlockall
153     common  vhangup                 sys_vhangup
154     common  modify_ldt              sys_modify_ldt
155     common  pivot_root              sys_pivot_root
156     64      _sysctl                 sys_ni_syscall
157     common  prctl                   sys_prctl
158     common  arch_prctl              sys_arch_prctl
159     common  adjtimex                sys_adjtimex
160     common  setrlimit               sys_setrlimit
161     common  chroot                  sys_chroot
162     common  sync                    sys_sync
163     common  acct                    sys_acct
164     common  settimeofday            sys_settimeofday
165     common  mount                   sys_mount
166     common  umount2                 sys_umount
167     common  swapon                  sys_swapon
168     common  swapoff                 sys_swapoff
169     common  reboot                  sys_reboot
170     common  sethostname             sys_sethostname
171     common  setdomainname           sys_setdomainname
172     common  iopl                    sys_iopl
173     common  ioperm                  sys_ioperm
174     64      create_module
175     common  init_module             sys_init_module
176     common  delete_module           sys_delete_module
177     64      get_kernel_syms
178     64      query_module
179     common  quotactl                sys_quotactl
180     64      nfsservctl
181     common  getpmsg
182     common  putpmsg
183     common  afs_syscall
184     common  tuxcall
185     common  security
186     common  gettid                  sys_gettid
187     common  readahead               sys_readahead
188     common  setxattr                sys_setxattr
189     common  lsetxattr               sys_lsetxattr
190     common  fsetxattr               sys_fsetxattr
191     common  getxattr                sys_getxattr
192     common  lgetxattr               sys_lgetxattr
193     common  fgetxattr               sys_fgetxattr
194     common  listxattr               sys_listxattr
195     common  llistxattr              sys_llistxattr
196     common  flistxattr              sys_flistxattr
197     common  removexattr             sys_removexattr
198     common  lremovexattr            sys_lremovexattr
199     common  fremovexattr            sys_fremovexattr
200     common  tkill                   sys_tkill
201     common  time                    sys_time
202     common  futex                   sys_futex
203     common  sched_setaffinity       sys_sched_setaffinity
204     common  sched_getaffinity       sys_sched_getaffinity
205     64      set_thread_area
206     64      io_setup                sys_io_setup
207     common  io_destroy              sys_io_destroy
208     common  io_getevents            sys_io_getevents
209     64      io_submit               sys_io_submit
210     common  io_cancel               sys_io_cancel
211     64      get_thread_area
212     common  lookup_dcookie
213     common  epoll_create            sys_epoll_create
214     64      epoll_ctl_old
215     64      epoll_wait_old
216     common  remap_file_pages        sys_remap_file_pages
217     common  getdents64              sys_getdents64
218     common  set_tid_address         sys_set_tid_address
219     common  restart_syscall         sys_restart_syscall
220     common  semtimedop              sys_semtimedop
221     common  fadvise64               sys_fadvise64
222     64      timer_create            sys_timer_create
223     common  timer_settime           sys_timer_settime
224     common  timer_gettime           sys_timer_gettime
225     common  timer_getoverrun        sys_timer_getoverrun
226     common  timer_delete            sys_timer_delete
227     common  clock_settime           sys_clock_settime
228     common  clock_gettime           sys_clock_gettime
229     common  clock_getres            sys_clock_getres
230     common  clock_nanosleep         sys_clock_nanosleep
231     common  exit_group              sys_exit_group
232     common  epoll_wait              sys_epoll_wait
233     common  epoll_ctl               sys_epoll_ctl
234     common  tgkill                  sys_tgkill
235     common  utimes                  sys_utimes
236     64      vserver
237     common  mbind                   sys_mbind
238     common  set_mempolicy           sys_set_mempolicy
239     common  get_mempolicy           sys_get_mempolicy
240     common  mq_open                 sys_mq_open
241     common  mq_unlink               sys_mq_unlink
242     common  mq_timedsend            sys_mq_timedsend
243     common  mq_timedreceive         sys_mq_timedreceive
244     64      mq_notify               sys_mq_notify
245     common  mq_getsetattr           sys_mq_getsetattr
246     64      kexec_load              sys_kexec_load
247     64      waitid                  sys_waitid
248     common  add_key                 sys_add_key
249     common  request_key             sys_request_key
250     common  keyctl                  sys_keyctl
251     common  ioprio_set              sys_ioprio_set
252     common  ioprio_get              sys_ioprio_get
253     common  inotify_init            sys_inotify_init
254     common  inotify_add_watch       sys_inotify_add_watch
255     common  inotify_rm_watch        sys_inotify_rm_watch
256     common  migrate_pages           sys_migrate_pages
257     common  openat                  sys_openat
258     common  mkdirat                 sys_mkdirat
259     common  mknodat                 sys_mknodat
260     common  fchownat                sys_fchownat
261     common  futimesat               sys_futimesat
262     common  newfstatat              sys_newfstatat
263     common  unlinkat                sys_unlinkat
264     common  renameat                sys_renameat
265     common  linkat                  sys_linkat
266     common  symlinkat               sys_symlinkat
267     common  readlinkat              sys_readlinkat
268     common  fchmodat                sys_fchmodat
269     common  faccessat               sys_faccessat
270     common  pselect6                sys_pselect6
271     common  ppoll                   sys_ppoll
272     common  unshare                 sys_unshare
273     64      set_robust_list         sys_set_robust_list
274     64      get_robust_list         sys_get_robust_list
275     common  splice                  sys_splice
276     common  tee                     sys_tee
277     common  sync_file_range         sys_sync_file_range
278     64      vmsplice                sys_vmsplice
279     64      move_pages              sys_move_pages
280     common  utimensat               sys_utimensat
281     common  epoll_pwait             sys_epoll_pwait
282     common  signalfd                sys_signalfd
283     common  timerfd_create          sys_timerfd_create
284     common  eventfd                 sys_eventfd
285     common  fallocate               sys_fallocate
286     common  timerfd_settime         sys_timerfd_settime
287     common  timerfd_gettime         sys_timerfd_gettime
288     common  accept4                 sys_accept4
289     common  signalfd4               sys_signalfd4
290     common  eventfd2                sys_eventfd2
291     common  epoll_create1           sys_epoll_create1
292     common  dup3                    sys_dup3
293     common  pipe2                   sys_pipe2
294     common  inotify_init1           sys_inotify_init1
295     64      preadv                  sys_preadv
296     64      pwritev                 sys_pwritev
297     64      rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo
298     common  perf_event_open         sys_perf_event_open
299     64      recvmmsg                sys_recvmmsg
300     common  fanotify_init           sys_fanotify_init
301     common  fanotify_mark           sys_fanotify_mark
302     common  prlimit64               sys_prlimit64
303     common  name_to_handle_at       sys_name_to_handle_at
304     common  open_by_handle_at       sys_open_by_handle_at
305     common  clock_adjtime           sys_clock_adjtime
306     common  syncfs                  sys_syncfs
307     64      sendmmsg                sys_sendmmsg
308     common  setns                   sys_setns
309     common  getcpu                  sys_getcpu
310     64      process_vm_readv        sys_process_vm_readv
311     64      process_vm_writev       sys_process_vm_writev
312     common  kcmp                    sys_kcmp
313     common  finit_module            sys_finit_module
314     common  sched_setattr           sys_sched_setattr
315     common  sched_getattr           sys_sched_getattr
316     common  renameat2               sys_renameat2
317     common  seccomp                 sys_seccomp
318     common  getrandom               sys_getrandom
319     common  memfd_create            sys_memfd_create
320     common  kexec_file_load         sys_kexec_file_load
321     common  bpf                     sys_bpf
322     64      execveat                sys_execveat
323     common  userfaultfd             sys_userfaultfd
324     common  membarrier              sys_membarrier
325     common  mlock2                  sys_mlock2
326     common  copy_file_range         sys_copy_file_range
327     64      preadv2                 sys_preadv2
328     64      pwritev2                sys_pwritev2
329     common  pkey_mprotect           sys_pkey_mprotect
330     common  pkey_alloc              sys_pkey_alloc
331     common  pkey_free               sys_pkey_free
332     common  statx                   sys_statx
333     common  io_pgetevents           sys_io_pgetevents
334     common  rseq                    sys_rseq
# don't use numbers 387 through 423, add new calls after the last
# 'common' entry
424     common  pidfd_send_signal       sys_pidfd_send_signal
425     common  io_uring_setup          sys_io_uring_setup
426     common  io_uring_enter          sys_io_uring_enter
427     common  io_uring_register       sys_io_uring_register
428     common  open_tree               sys_open_tree
429     common  move_mount              sys_move_mount
430     common  fsopen                  sys_fsopen
431     common  fsconfig                sys_fsconfig
432     common  fsmount                 sys_fsmount
433     common  fspick                  sys_fspick
434     common  pidfd_open              sys_pidfd_open
435     common  clone3                  sys_clone3
436     common  close_range             sys_close_range
437     common  openat2                 sys_openat2
438     common  pidfd_getfd             sys_pidfd_getfd
439     common  faccessat2              sys_faccessat2
440     common  process_madvise         sys_process_madvise
441     common  epoll_pwait2            sys_epoll_pwait2
442     common  mount_setattr           sys_mount_setattr
443     common  quotactl_fd             sys_quotactl_fd
444     common  landlock_create_ruleset sys_landlock_create_ruleset
445     common  landlock_add_rule       sys_landlock_add_rule
446     common  landlock_restrict_self  sys_landlock_restrict_self
447     common  memfd_secret            sys_memfd_secret
448     common  process_mrelease        sys_process_mrelease
449     common  futex_waitv             sys_futex_waitv
450     common  set_mempolicy_home_node sys_set_mempolicy_home_node
451     common  cachestat               sys_cachestat
452     common  fchmodat2               sys_fchmodat2
453     common  map_shadow_stack        sys_map_shadow_stack
454     common  futex_wake              sys_futex_wake
455     common  futex_wait              sys_futex_wait
456     common  futex_requeue           sys_futex_requeue
457     common  statmount               sys_statmount
458     common  listmount               sys_listmount
459     common  lsm_get_self_attr       sys_lsm_get_self_attr
460     common  lsm_set_self_attr       sys_lsm_set_self_attr
461     common  lsm_list_modules        sys_lsm_list_modules
462     common  mseal                   sys_mseal

#
# Due to a historical design error, certain syscalls are numbered differently
# in x32 as compared to native x86_64.  These syscalls have numbers 512-547.
# Do not add new syscalls to this range.  Numbers 548 and above are available
# for non-x32 use.
#
512     x32     rt_sigaction            compat_sys_rt_sigaction
513     x32     rt_sigreturn            compat_sys_x32_rt_sigreturn
514     x32     ioctl                   compat_sys_ioctl
515     x32     readv                   sys_readv
516     x32     writev                  sys_writev
517     x32     recvfrom                compat_sys_recvfrom
518     x32     sendmsg                 compat_sys_sendmsg
519     x32     recvmsg                 compat_sys_recvmsg
520     x32     execve                  compat_sys_execve
521     x32     ptrace                  compat_sys_ptrace
522     x32     rt_sigpending           compat_sys_rt_sigpending
523     x32     rt_sigtimedwait         compat_sys_rt_sigtimedwait_time64
524     x32     rt_sigqueueinfo         compat_sys_rt_sigqueueinfo
525     x32     sigaltstack             compat_sys_sigaltstack
526     x32     timer_create            compat_sys_timer_create
527     x32     mq_notify               compat_sys_mq_notify
528     x32     kexec_load              compat_sys_kexec_load
529     x32     waitid                  compat_sys_waitid
530     x32     set_robust_list         compat_sys_set_robust_list
531     x32     get_robust_list         compat_sys_get_robust_list
532     x32     vmsplice                sys_vmsplice
533     x32     move_pages              sys_move_pages
534     x32     preadv                  compat_sys_preadv64
535     x32     pwritev                 compat_sys_pwritev64
536     x32     rt_tgsigqueueinfo       compat_sys_rt_tgsigqueueinfo
537     x32     recvmmsg                compat_sys_recvmmsg_time64
538     x32     sendmmsg                compat_sys_sendmmsg
539     x32     process_vm_readv        sys_process_vm_readv
540     x32     process_vm_writev       sys_process_vm_writev
541     x32     setsockopt              sys_setsockopt
542     x32     getsockopt              sys_getsockopt
543     x32     io_setup                compat_sys_io_setup
544     x32     io_submit               compat_sys_io_submit
545     x32     execveat                compat_sys_execveat
546     x32     preadv2                 compat_sys_preadv64v2
547     x32     pwritev2                compat_sys_pwritev64v2
# This is the end of the legacy x32 range.  Numbers 548 and above are
# not special and are not to be used for x32-specific syscalls.
"""


# i386 (native / compat(emulated))
# - arch/x86/entry/syscalls/syscall_32.tbl
x86_syscall_tbl = """
#
# 32-bit system call numbers and entry vectors
#
# The format is:
# <number> <abi> <name> <entry point> <compat entry point>
#
# The __ia32_sys and __ia32_compat_sys stubs are created on-the-fly for
# sys_*() system calls and compat_sys_*() compat system calls if
# IA32_EMULATION is defined, and expect struct pt_regs *regs as their only
# parameter.
#
# The abi is always "i386" for this file.
#
0       i386    restart_syscall         sys_restart_syscall
1       i386    exit                    sys_exit
2       i386    fork                    sys_fork
3       i386    read                    sys_read
4       i386    write                   sys_write
5       i386    open                    sys_open                        compat_sys_open
6       i386    close                   sys_close
7       i386    waitpid                 sys_waitpid
8       i386    creat                   sys_creat
9       i386    link                    sys_link
10      i386    unlink                  sys_unlink
11      i386    execve                  sys_execve                      compat_sys_execve
12      i386    chdir                   sys_chdir
13      i386    time                    sys_time32
14      i386    mknod                   sys_mknod
15      i386    chmod                   sys_chmod
16      i386    lchown                  sys_lchown16
17      i386    break
18      i386    oldstat                 sys_stat
19      i386    lseek                   sys_lseek                       compat_sys_lseek
20      i386    getpid                  sys_getpid
21      i386    mount                   sys_mount
22      i386    umount                  sys_oldumount
23      i386    setuid                  sys_setuid16
24      i386    getuid                  sys_getuid16
25      i386    stime                   sys_stime32
26      i386    ptrace                  sys_ptrace                      compat_sys_ptrace
27      i386    alarm                   sys_alarm
28      i386    oldfstat                sys_fstat
29      i386    pause                   sys_pause
30      i386    utime                   sys_utime32
31      i386    stty
32      i386    gtty
33      i386    access                  sys_access
34      i386    nice                    sys_nice
35      i386    ftime
36      i386    sync                    sys_sync
37      i386    kill                    sys_kill
38      i386    rename                  sys_rename
39      i386    mkdir                   sys_mkdir
40      i386    rmdir                   sys_rmdir
41      i386    dup                     sys_dup
42      i386    pipe                    sys_pipe
43      i386    times                   sys_times                       compat_sys_times
44      i386    prof
45      i386    brk                     sys_brk
46      i386    setgid                  sys_setgid16
47      i386    getgid                  sys_getgid16
48      i386    signal                  sys_signal
49      i386    geteuid                 sys_geteuid16
50      i386    getegid                 sys_getegid16
51      i386    acct                    sys_acct
52      i386    umount2                 sys_umount
53      i386    lock
54      i386    ioctl                   sys_ioctl                       compat_sys_ioctl
55      i386    fcntl                   sys_fcntl                       compat_sys_fcntl64
56      i386    mpx
57      i386    setpgid                 sys_setpgid
58      i386    ulimit
59      i386    oldolduname             sys_olduname
60      i386    umask                   sys_umask
61      i386    chroot                  sys_chroot
62      i386    ustat                   sys_ustat                       compat_sys_ustat
63      i386    dup2                    sys_dup2
64      i386    getppid                 sys_getppid
65      i386    getpgrp                 sys_getpgrp
66      i386    setsid                  sys_setsid
67      i386    sigaction               sys_sigaction                   compat_sys_sigaction
68      i386    sgetmask                sys_sgetmask
69      i386    ssetmask                sys_ssetmask
70      i386    setreuid                sys_setreuid16
71      i386    setregid                sys_setregid16
72      i386    sigsuspend              sys_sigsuspend
73      i386    sigpending              sys_sigpending                  compat_sys_sigpending
74      i386    sethostname             sys_sethostname
75      i386    setrlimit               sys_setrlimit                   compat_sys_setrlimit
76      i386    getrlimit               sys_old_getrlimit               compat_sys_old_getrlimit
77      i386    getrusage               sys_getrusage                   compat_sys_getrusage
78      i386    gettimeofday            sys_gettimeofday                compat_sys_gettimeofday
79      i386    settimeofday            sys_settimeofday                compat_sys_settimeofday
80      i386    getgroups               sys_getgroups16
81      i386    setgroups               sys_setgroups16
82      i386    select                  sys_old_select                  compat_sys_old_select
83      i386    symlink                 sys_symlink
84      i386    oldlstat                sys_lstat
85      i386    readlink                sys_readlink
86      i386    uselib                  sys_uselib
87      i386    swapon                  sys_swapon
88      i386    reboot                  sys_reboot
89      i386    readdir                 sys_old_readdir                 compat_sys_old_readdir
90      i386    mmap                    sys_old_mmap                    compat_sys_ia32_mmap
91      i386    munmap                  sys_munmap
92      i386    truncate                sys_truncate                    compat_sys_truncate
93      i386    ftruncate               sys_ftruncate                   compat_sys_ftruncate
94      i386    fchmod                  sys_fchmod
95      i386    fchown                  sys_fchown16
96      i386    getpriority             sys_getpriority
97      i386    setpriority             sys_setpriority
98      i386    profil
99      i386    statfs                  sys_statfs                      compat_sys_statfs
100     i386    fstatfs                 sys_fstatfs                     compat_sys_fstatfs
101     i386    ioperm                  sys_ioperm
102     i386    socketcall              sys_socketcall                  compat_sys_socketcall
103     i386    syslog                  sys_syslog
104     i386    setitimer               sys_setitimer                   compat_sys_setitimer
105     i386    getitimer               sys_getitimer                   compat_sys_getitimer
106     i386    stat                    sys_newstat                     compat_sys_newstat
107     i386    lstat                   sys_newlstat                    compat_sys_newlstat
108     i386    fstat                   sys_newfstat                    compat_sys_newfstat
109     i386    olduname                sys_uname
110     i386    iopl                    sys_iopl
111     i386    vhangup                 sys_vhangup
112     i386    idle
113     i386    vm86old                 sys_vm86old                     sys_ni_syscall
114     i386    wait4                   sys_wait4                       compat_sys_wait4
115     i386    swapoff                 sys_swapoff
116     i386    sysinfo                 sys_sysinfo                     compat_sys_sysinfo
117     i386    ipc                     sys_ipc                         compat_sys_ipc
118     i386    fsync                   sys_fsync
119     i386    sigreturn               sys_sigreturn                   compat_sys_sigreturn
120     i386    clone                   sys_clone                       compat_sys_ia32_clone
121     i386    setdomainname           sys_setdomainname
122     i386    uname                   sys_newuname
123     i386    modify_ldt              sys_modify_ldt
124     i386    adjtimex                sys_adjtimex_time32
125     i386    mprotect                sys_mprotect
126     i386    sigprocmask             sys_sigprocmask                 compat_sys_sigprocmask
127     i386    create_module
128     i386    init_module             sys_init_module
129     i386    delete_module           sys_delete_module
130     i386    get_kernel_syms
131     i386    quotactl                sys_quotactl
132     i386    getpgid                 sys_getpgid
133     i386    fchdir                  sys_fchdir
134     i386    bdflush                 sys_ni_syscall
135     i386    sysfs                   sys_sysfs
136     i386    personality             sys_personality
137     i386    afs_syscall
138     i386    setfsuid                sys_setfsuid16
139     i386    setfsgid                sys_setfsgid16
140     i386    _llseek                 sys_llseek
141     i386    getdents                sys_getdents                    compat_sys_getdents
142     i386    _newselect              sys_select                      compat_sys_select
143     i386    flock                   sys_flock
144     i386    msync                   sys_msync
145     i386    readv                   sys_readv
146     i386    writev                  sys_writev
147     i386    getsid                  sys_getsid
148     i386    fdatasync               sys_fdatasync
149     i386    _sysctl                 sys_ni_syscall
150     i386    mlock                   sys_mlock
151     i386    munlock                 sys_munlock
152     i386    mlockall                sys_mlockall
153     i386    munlockall              sys_munlockall
154     i386    sched_setparam          sys_sched_setparam
155     i386    sched_getparam          sys_sched_getparam
156     i386    sched_setscheduler      sys_sched_setscheduler
157     i386    sched_getscheduler      sys_sched_getscheduler
158     i386    sched_yield             sys_sched_yield
159     i386    sched_get_priority_max  sys_sched_get_priority_max
160     i386    sched_get_priority_min  sys_sched_get_priority_min
161     i386    sched_rr_get_interval   sys_sched_rr_get_interval_time32
162     i386    nanosleep               sys_nanosleep_time32
163     i386    mremap                  sys_mremap
164     i386    setresuid               sys_setresuid16
165     i386    getresuid               sys_getresuid16
166     i386    vm86                    sys_vm86                        sys_ni_syscall
167     i386    query_module
168     i386    poll                    sys_poll
169     i386    nfsservctl
170     i386    setresgid               sys_setresgid16
171     i386    getresgid               sys_getresgid16
172     i386    prctl                   sys_prctl
173     i386    rt_sigreturn            sys_rt_sigreturn                compat_sys_rt_sigreturn
174     i386    rt_sigaction            sys_rt_sigaction                compat_sys_rt_sigaction
175     i386    rt_sigprocmask          sys_rt_sigprocmask              compat_sys_rt_sigprocmask
176     i386    rt_sigpending           sys_rt_sigpending               compat_sys_rt_sigpending
177     i386    rt_sigtimedwait         sys_rt_sigtimedwait_time32      compat_sys_rt_sigtimedwait_time32
178     i386    rt_sigqueueinfo         sys_rt_sigqueueinfo             compat_sys_rt_sigqueueinfo
179     i386    rt_sigsuspend           sys_rt_sigsuspend               compat_sys_rt_sigsuspend
180     i386    pread64                 sys_ia32_pread64
181     i386    pwrite64                sys_ia32_pwrite64
182     i386    chown                   sys_chown16
183     i386    getcwd                  sys_getcwd
184     i386    capget                  sys_capget
185     i386    capset                  sys_capset
186     i386    sigaltstack             sys_sigaltstack                 compat_sys_sigaltstack
187     i386    sendfile                sys_sendfile                    compat_sys_sendfile
188     i386    getpmsg
189     i386    putpmsg
190     i386    vfork                   sys_vfork
191     i386    ugetrlimit              sys_getrlimit                   compat_sys_getrlimit
192     i386    mmap2                   sys_mmap_pgoff
193     i386    truncate64              sys_ia32_truncate64
194     i386    ftruncate64             sys_ia32_ftruncate64
195     i386    stat64                  sys_stat64                      compat_sys_ia32_stat64
196     i386    lstat64                 sys_lstat64                     compat_sys_ia32_lstat64
197     i386    fstat64                 sys_fstat64                     compat_sys_ia32_fstat64
198     i386    lchown32                sys_lchown
199     i386    getuid32                sys_getuid
200     i386    getgid32                sys_getgid
201     i386    geteuid32               sys_geteuid
202     i386    getegid32               sys_getegid
203     i386    setreuid32              sys_setreuid
204     i386    setregid32              sys_setregid
205     i386    getgroups32             sys_getgroups
206     i386    setgroups32             sys_setgroups
207     i386    fchown32                sys_fchown
208     i386    setresuid32             sys_setresuid
209     i386    getresuid32             sys_getresuid
210     i386    setresgid32             sys_setresgid
211     i386    getresgid32             sys_getresgid
212     i386    chown32                 sys_chown
213     i386    setuid32                sys_setuid
214     i386    setgid32                sys_setgid
215     i386    setfsuid32              sys_setfsuid
216     i386    setfsgid32              sys_setfsgid
217     i386    pivot_root              sys_pivot_root
218     i386    mincore                 sys_mincore
219     i386    madvise                 sys_madvise
220     i386    getdents64              sys_getdents64
221     i386    fcntl64                 sys_fcntl64                     compat_sys_fcntl64
# 222 is unused
# 223 is unused
224     i386    gettid                  sys_gettid
225     i386    readahead               sys_ia32_readahead
226     i386    setxattr                sys_setxattr
227     i386    lsetxattr               sys_lsetxattr
228     i386    fsetxattr               sys_fsetxattr
229     i386    getxattr                sys_getxattr
230     i386    lgetxattr               sys_lgetxattr
231     i386    fgetxattr               sys_fgetxattr
232     i386    listxattr               sys_listxattr
233     i386    llistxattr              sys_llistxattr
234     i386    flistxattr              sys_flistxattr
235     i386    removexattr             sys_removexattr
236     i386    lremovexattr            sys_lremovexattr
237     i386    fremovexattr            sys_fremovexattr
238     i386    tkill                   sys_tkill
239     i386    sendfile64              sys_sendfile64
240     i386    futex                   sys_futex_time32
241     i386    sched_setaffinity       sys_sched_setaffinity           compat_sys_sched_setaffinity
242     i386    sched_getaffinity       sys_sched_getaffinity           compat_sys_sched_getaffinity
243     i386    set_thread_area         sys_set_thread_area
244     i386    get_thread_area         sys_get_thread_area
245     i386    io_setup                sys_io_setup                    compat_sys_io_setup
246     i386    io_destroy              sys_io_destroy
247     i386    io_getevents            sys_io_getevents_time32
248     i386    io_submit               sys_io_submit                   compat_sys_io_submit
249     i386    io_cancel               sys_io_cancel
250     i386    fadvise64               sys_ia32_fadvise64
# 251 is available for reuse (was briefly sys_set_zone_reclaim)
252     i386    exit_group              sys_exit_group
253     i386    lookup_dcookie
254     i386    epoll_create            sys_epoll_create
255     i386    epoll_ctl               sys_epoll_ctl
256     i386    epoll_wait              sys_epoll_wait
257     i386    remap_file_pages        sys_remap_file_pages
258     i386    set_tid_address         sys_set_tid_address
259     i386    timer_create            sys_timer_create                compat_sys_timer_create
260     i386    timer_settime           sys_timer_settime32
261     i386    timer_gettime           sys_timer_gettime32
262     i386    timer_getoverrun        sys_timer_getoverrun
263     i386    timer_delete            sys_timer_delete
264     i386    clock_settime           sys_clock_settime32
265     i386    clock_gettime           sys_clock_gettime32
266     i386    clock_getres            sys_clock_getres_time32
267     i386    clock_nanosleep         sys_clock_nanosleep_time32
268     i386    statfs64                sys_statfs64                    compat_sys_statfs64
269     i386    fstatfs64               sys_fstatfs64                   compat_sys_fstatfs64
270     i386    tgkill                  sys_tgkill
271     i386    utimes                  sys_utimes_time32
272     i386    fadvise64_64            sys_ia32_fadvise64_64
273     i386    vserver
274     i386    mbind                   sys_mbind
275     i386    get_mempolicy           sys_get_mempolicy
276     i386    set_mempolicy           sys_set_mempolicy
277     i386    mq_open                 sys_mq_open                     compat_sys_mq_open
278     i386    mq_unlink               sys_mq_unlink
279     i386    mq_timedsend            sys_mq_timedsend_time32
280     i386    mq_timedreceive         sys_mq_timedreceive_time32
281     i386    mq_notify               sys_mq_notify                   compat_sys_mq_notify
282     i386    mq_getsetattr           sys_mq_getsetattr               compat_sys_mq_getsetattr
283     i386    kexec_load              sys_kexec_load                  compat_sys_kexec_load
284     i386    waitid                  sys_waitid                      compat_sys_waitid
# 285 sys_setaltroot
286     i386    add_key                 sys_add_key
287     i386    request_key             sys_request_key
288     i386    keyctl                  sys_keyctl                      compat_sys_keyctl
289     i386    ioprio_set              sys_ioprio_set
290     i386    ioprio_get              sys_ioprio_get
291     i386    inotify_init            sys_inotify_init
292     i386    inotify_add_watch       sys_inotify_add_watch
293     i386    inotify_rm_watch        sys_inotify_rm_watch
294     i386    migrate_pages           sys_migrate_pages
295     i386    openat                  sys_openat                      compat_sys_openat
296     i386    mkdirat                 sys_mkdirat
297     i386    mknodat                 sys_mknodat
298     i386    fchownat                sys_fchownat
299     i386    futimesat               sys_futimesat_time32
300     i386    fstatat64               sys_fstatat64                   compat_sys_ia32_fstatat64
301     i386    unlinkat                sys_unlinkat
302     i386    renameat                sys_renameat
303     i386    linkat                  sys_linkat
304     i386    symlinkat               sys_symlinkat
305     i386    readlinkat              sys_readlinkat
306     i386    fchmodat                sys_fchmodat
307     i386    faccessat               sys_faccessat
308     i386    pselect6                sys_pselect6_time32             compat_sys_pselect6_time32
309     i386    ppoll                   sys_ppoll_time32                compat_sys_ppoll_time32
310     i386    unshare                 sys_unshare
311     i386    set_robust_list         sys_set_robust_list             compat_sys_set_robust_list
312     i386    get_robust_list         sys_get_robust_list             compat_sys_get_robust_list
313     i386    splice                  sys_splice
314     i386    sync_file_range         sys_ia32_sync_file_range
315     i386    tee                     sys_tee
316     i386    vmsplice                sys_vmsplice
317     i386    move_pages              sys_move_pages
318     i386    getcpu                  sys_getcpu
319     i386    epoll_pwait             sys_epoll_pwait
320     i386    utimensat               sys_utimensat_time32
321     i386    signalfd                sys_signalfd                    compat_sys_signalfd
322     i386    timerfd_create          sys_timerfd_create
323     i386    eventfd                 sys_eventfd
324     i386    fallocate               sys_ia32_fallocate
325     i386    timerfd_settime         sys_timerfd_settime32
326     i386    timerfd_gettime         sys_timerfd_gettime32
327     i386    signalfd4               sys_signalfd4                   compat_sys_signalfd4
328     i386    eventfd2                sys_eventfd2
329     i386    epoll_create1           sys_epoll_create1
330     i386    dup3                    sys_dup3
331     i386    pipe2                   sys_pipe2
332     i386    inotify_init1           sys_inotify_init1
333     i386    preadv                  sys_preadv                      compat_sys_preadv
334     i386    pwritev                 sys_pwritev                     compat_sys_pwritev
335     i386    rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo           compat_sys_rt_tgsigqueueinfo
336     i386    perf_event_open         sys_perf_event_open
337     i386    recvmmsg                sys_recvmmsg_time32             compat_sys_recvmmsg_time32
338     i386    fanotify_init           sys_fanotify_init
339     i386    fanotify_mark           sys_fanotify_mark               compat_sys_fanotify_mark
340     i386    prlimit64               sys_prlimit64
341     i386    name_to_handle_at       sys_name_to_handle_at
342     i386    open_by_handle_at       sys_open_by_handle_at           compat_sys_open_by_handle_at
343     i386    clock_adjtime           sys_clock_adjtime32
344     i386    syncfs                  sys_syncfs
345     i386    sendmmsg                sys_sendmmsg                    compat_sys_sendmmsg
346     i386    setns                   sys_setns
347     i386    process_vm_readv        sys_process_vm_readv
348     i386    process_vm_writev       sys_process_vm_writev
349     i386    kcmp                    sys_kcmp
350     i386    finit_module            sys_finit_module
351     i386    sched_setattr           sys_sched_setattr
352     i386    sched_getattr           sys_sched_getattr
353     i386    renameat2               sys_renameat2
354     i386    seccomp                 sys_seccomp
355     i386    getrandom               sys_getrandom
356     i386    memfd_create            sys_memfd_create
357     i386    bpf                     sys_bpf
358     i386    execveat                sys_execveat                    compat_sys_execveat
359     i386    socket                  sys_socket
360     i386    socketpair              sys_socketpair
361     i386    bind                    sys_bind
362     i386    connect                 sys_connect
363     i386    listen                  sys_listen
364     i386    accept4                 sys_accept4
365     i386    getsockopt              sys_getsockopt                  sys_getsockopt
366     i386    setsockopt              sys_setsockopt                  sys_setsockopt
367     i386    getsockname             sys_getsockname
368     i386    getpeername             sys_getpeername
369     i386    sendto                  sys_sendto
370     i386    sendmsg                 sys_sendmsg                     compat_sys_sendmsg
371     i386    recvfrom                sys_recvfrom                    compat_sys_recvfrom
372     i386    recvmsg                 sys_recvmsg                     compat_sys_recvmsg
373     i386    shutdown                sys_shutdown
374     i386    userfaultfd             sys_userfaultfd
375     i386    membarrier              sys_membarrier
376     i386    mlock2                  sys_mlock2
377     i386    copy_file_range         sys_copy_file_range
378     i386    preadv2                 sys_preadv2                     compat_sys_preadv2
379     i386    pwritev2                sys_pwritev2                    compat_sys_pwritev2
380     i386    pkey_mprotect           sys_pkey_mprotect
381     i386    pkey_alloc              sys_pkey_alloc
382     i386    pkey_free               sys_pkey_free
383     i386    statx                   sys_statx
384     i386    arch_prctl              sys_arch_prctl                  compat_sys_arch_prctl
385     i386    io_pgetevents           sys_io_pgetevents_time32        compat_sys_io_pgetevents
386     i386    rseq                    sys_rseq
393     i386    semget                  sys_semget
394     i386    semctl                  sys_semctl                      compat_sys_semctl
395     i386    shmget                  sys_shmget
396     i386    shmctl                  sys_shmctl                      compat_sys_shmctl
397     i386    shmat                   sys_shmat                       compat_sys_shmat
398     i386    shmdt                   sys_shmdt
399     i386    msgget                  sys_msgget
400     i386    msgsnd                  sys_msgsnd                      compat_sys_msgsnd
401     i386    msgrcv                  sys_msgrcv                      compat_sys_msgrcv
402     i386    msgctl                  sys_msgctl                      compat_sys_msgctl
403     i386    clock_gettime64         sys_clock_gettime
404     i386    clock_settime64         sys_clock_settime
405     i386    clock_adjtime64         sys_clock_adjtime
406     i386    clock_getres_time64     sys_clock_getres
407     i386    clock_nanosleep_time64  sys_clock_nanosleep
408     i386    timer_gettime64         sys_timer_gettime
409     i386    timer_settime64         sys_timer_settime
410     i386    timerfd_gettime64       sys_timerfd_gettime
411     i386    timerfd_settime64       sys_timerfd_settime
412     i386    utimensat_time64        sys_utimensat
413     i386    pselect6_time64         sys_pselect6                    compat_sys_pselect6_time64
414     i386    ppoll_time64            sys_ppoll                       compat_sys_ppoll_time64
416     i386    io_pgetevents_time64    sys_io_pgetevents               compat_sys_io_pgetevents_time64
417     i386    recvmmsg_time64         sys_recvmmsg                    compat_sys_recvmmsg_time64
418     i386    mq_timedsend_time64     sys_mq_timedsend
419     i386    mq_timedreceive_time64  sys_mq_timedreceive
420     i386    semtimedop_time64       sys_semtimedop
421     i386    rt_sigtimedwait_time64  sys_rt_sigtimedwait             compat_sys_rt_sigtimedwait_time64
422     i386    futex_time64            sys_futex
423     i386    sched_rr_get_interval_time64    sys_sched_rr_get_interval
424     i386    pidfd_send_signal       sys_pidfd_send_signal
425     i386    io_uring_setup          sys_io_uring_setup
426     i386    io_uring_enter          sys_io_uring_enter
427     i386    io_uring_register       sys_io_uring_register
428     i386    open_tree               sys_open_tree
429     i386    move_mount              sys_move_mount
430     i386    fsopen                  sys_fsopen
431     i386    fsconfig                sys_fsconfig
432     i386    fsmount                 sys_fsmount
433     i386    fspick                  sys_fspick
434     i386    pidfd_open              sys_pidfd_open
435     i386    clone3                  sys_clone3
436     i386    close_range             sys_close_range
437     i386    openat2                 sys_openat2
438     i386    pidfd_getfd             sys_pidfd_getfd
439     i386    faccessat2              sys_faccessat2
440     i386    process_madvise         sys_process_madvise
441     i386    epoll_pwait2            sys_epoll_pwait2                compat_sys_epoll_pwait2
442     i386    mount_setattr           sys_mount_setattr
443     i386    quotactl_fd             sys_quotactl_fd
444     i386    landlock_create_ruleset sys_landlock_create_ruleset
445     i386    landlock_add_rule       sys_landlock_add_rule
446     i386    landlock_restrict_self  sys_landlock_restrict_self
447     i386    memfd_secret            sys_memfd_secret
448     i386    process_mrelease        sys_process_mrelease
449     i386    futex_waitv             sys_futex_waitv
450     i386    set_mempolicy_home_node         sys_set_mempolicy_home_node
451     i386    cachestat               sys_cachestat
452     i386    fchmodat2               sys_fchmodat2
453     i386    map_shadow_stack        sys_map_shadow_stack
454     i386    futex_wake              sys_futex_wake
455     i386    futex_wait              sys_futex_wait
456     i386    futex_requeue           sys_futex_requeue
457     i386    statmount               sys_statmount
458     i386    listmount               sys_listmount
459     i386    lsm_get_self_attr       sys_lsm_get_self_attr
460     i386    lsm_set_self_attr       sys_lsm_set_self_attr
461     i386    lsm_list_modules        sys_lsm_list_modules
462     i386    mseal                   sys_mseal
"""


# ARM64
#
# [How to make]
# cd /path/to/linux-6.*/
# gcc -I `pwd`/include/uapi/ -E -D__SYSCALL=SYSCALL arch/arm64/include/uapi/asm/unistd.h \
# | grep ^SYSCALL | sed -e 's/SYSCALL(//;s/[,)]//g' > /tmp/a
# grep -oP "__NR\S+\s+\d+$" include/uapi/asm-generic/unistd.h | grep -v __NR_sync_file_range2 > /tmp/b
# join -2 2 -o 1.1,1.10,2.1,1.2 -e arm64 /tmp/a /tmp/b | sed -e 's/\(__NR_\|__NR3264_\)//g' | column -t
#
arm64_syscall_tbl = """
0    arm64  io_setup                 sys_io_setup
1    arm64  io_destroy               sys_io_destroy
2    arm64  io_submit                sys_io_submit
3    arm64  io_cancel                sys_io_cancel
4    arm64  io_getevents             sys_io_getevents
5    arm64  setxattr                 sys_setxattr
6    arm64  lsetxattr                sys_lsetxattr
7    arm64  fsetxattr                sys_fsetxattr
8    arm64  getxattr                 sys_getxattr
9    arm64  lgetxattr                sys_lgetxattr
10   arm64  fgetxattr                sys_fgetxattr
11   arm64  listxattr                sys_listxattr
12   arm64  llistxattr               sys_llistxattr
13   arm64  flistxattr               sys_flistxattr
14   arm64  removexattr              sys_removexattr
15   arm64  lremovexattr             sys_lremovexattr
16   arm64  fremovexattr             sys_fremovexattr
17   arm64  getcwd                   sys_getcwd
18   arm64  lookup_dcookie           sys_ni_syscall
19   arm64  eventfd2                 sys_eventfd2
20   arm64  epoll_create1            sys_epoll_create1
21   arm64  epoll_ctl                sys_epoll_ctl
22   arm64  epoll_pwait              sys_epoll_pwait
23   arm64  dup                      sys_dup
24   arm64  dup3                     sys_dup3
25   arm64  fcntl                    sys_fcntl
26   arm64  inotify_init1            sys_inotify_init1
27   arm64  inotify_add_watch        sys_inotify_add_watch
28   arm64  inotify_rm_watch         sys_inotify_rm_watch
29   arm64  ioctl                    sys_ioctl
30   arm64  ioprio_set               sys_ioprio_set
31   arm64  ioprio_get               sys_ioprio_get
32   arm64  flock                    sys_flock
33   arm64  mknodat                  sys_mknodat
34   arm64  mkdirat                  sys_mkdirat
35   arm64  unlinkat                 sys_unlinkat
36   arm64  symlinkat                sys_symlinkat
37   arm64  linkat                   sys_linkat
38   arm64  renameat                 sys_renameat
39   arm64  umount2                  sys_umount
40   arm64  mount                    sys_mount
41   arm64  pivot_root               sys_pivot_root
42   arm64  nfsservctl               sys_ni_syscall
43   arm64  statfs                   sys_statfs
44   arm64  fstatfs                  sys_fstatfs
45   arm64  truncate                 sys_truncate
46   arm64  ftruncate                sys_ftruncate
47   arm64  fallocate                sys_fallocate
48   arm64  faccessat                sys_faccessat
49   arm64  chdir                    sys_chdir
50   arm64  fchdir                   sys_fchdir
51   arm64  chroot                   sys_chroot
52   arm64  fchmod                   sys_fchmod
53   arm64  fchmodat                 sys_fchmodat
54   arm64  fchownat                 sys_fchownat
55   arm64  fchown                   sys_fchown
56   arm64  openat                   sys_openat
57   arm64  close                    sys_close
58   arm64  vhangup                  sys_vhangup
59   arm64  pipe2                    sys_pipe2
60   arm64  quotactl                 sys_quotactl
61   arm64  getdents64               sys_getdents64
62   arm64  lseek                    sys_lseek
63   arm64  read                     sys_read
64   arm64  write                    sys_write
65   arm64  readv                    sys_readv
66   arm64  writev                   sys_writev
67   arm64  pread64                  sys_pread64
68   arm64  pwrite64                 sys_pwrite64
69   arm64  preadv                   sys_preadv
70   arm64  pwritev                  sys_pwritev
71   arm64  sendfile                 sys_sendfile64
72   arm64  pselect6                 sys_pselect6
73   arm64  ppoll                    sys_ppoll
74   arm64  signalfd4                sys_signalfd4
75   arm64  vmsplice                 sys_vmsplice
76   arm64  splice                   sys_splice
77   arm64  tee                      sys_tee
78   arm64  readlinkat               sys_readlinkat
79   arm64  fstatat                  sys_newfstatat
80   arm64  fstat                    sys_newfstat
81   arm64  sync                     sys_sync
82   arm64  fsync                    sys_fsync
83   arm64  fdatasync                sys_fdatasync
84   arm64  sync_file_range          sys_sync_file_range
85   arm64  timerfd_create           sys_timerfd_create
86   arm64  timerfd_settime          sys_timerfd_settime
87   arm64  timerfd_gettime          sys_timerfd_gettime
88   arm64  utimensat                sys_utimensat
89   arm64  acct                     sys_acct
90   arm64  capget                   sys_capget
91   arm64  capset                   sys_capset
92   arm64  personality              sys_personality
93   arm64  exit                     sys_exit
94   arm64  exit_group               sys_exit_group
95   arm64  waitid                   sys_waitid
96   arm64  set_tid_address          sys_set_tid_address
97   arm64  unshare                  sys_unshare
98   arm64  futex                    sys_futex
99   arm64  set_robust_list          sys_set_robust_list
100  arm64  get_robust_list          sys_get_robust_list
101  arm64  nanosleep                sys_nanosleep
102  arm64  getitimer                sys_getitimer
103  arm64  setitimer                sys_setitimer
104  arm64  kexec_load               sys_kexec_load
105  arm64  init_module              sys_init_module
106  arm64  delete_module            sys_delete_module
107  arm64  timer_create             sys_timer_create
108  arm64  timer_gettime            sys_timer_gettime
109  arm64  timer_getoverrun         sys_timer_getoverrun
110  arm64  timer_settime            sys_timer_settime
111  arm64  timer_delete             sys_timer_delete
112  arm64  clock_settime            sys_clock_settime
113  arm64  clock_gettime            sys_clock_gettime
114  arm64  clock_getres             sys_clock_getres
115  arm64  clock_nanosleep          sys_clock_nanosleep
116  arm64  syslog                   sys_syslog
117  arm64  ptrace                   sys_ptrace
118  arm64  sched_setparam           sys_sched_setparam
119  arm64  sched_setscheduler       sys_sched_setscheduler
120  arm64  sched_getscheduler       sys_sched_getscheduler
121  arm64  sched_getparam           sys_sched_getparam
122  arm64  sched_setaffinity        sys_sched_setaffinity
123  arm64  sched_getaffinity        sys_sched_getaffinity
124  arm64  sched_yield              sys_sched_yield
125  arm64  sched_get_priority_max   sys_sched_get_priority_max
126  arm64  sched_get_priority_min   sys_sched_get_priority_min
127  arm64  sched_rr_get_interval    sys_sched_rr_get_interval
128  arm64  restart_syscall          sys_restart_syscall
129  arm64  kill                     sys_kill
130  arm64  tkill                    sys_tkill
131  arm64  tgkill                   sys_tgkill
132  arm64  sigaltstack              sys_sigaltstack
133  arm64  rt_sigsuspend            sys_rt_sigsuspend
134  arm64  rt_sigaction             sys_rt_sigaction
135  arm64  rt_sigprocmask           sys_rt_sigprocmask
136  arm64  rt_sigpending            sys_rt_sigpending
137  arm64  rt_sigtimedwait          sys_rt_sigtimedwait
138  arm64  rt_sigqueueinfo          sys_rt_sigqueueinfo
139  arm64  rt_sigreturn             sys_rt_sigreturn
140  arm64  setpriority              sys_setpriority
141  arm64  getpriority              sys_getpriority
142  arm64  reboot                   sys_reboot
143  arm64  setregid                 sys_setregid
144  arm64  setgid                   sys_setgid
145  arm64  setreuid                 sys_setreuid
146  arm64  setuid                   sys_setuid
147  arm64  setresuid                sys_setresuid
148  arm64  getresuid                sys_getresuid
149  arm64  setresgid                sys_setresgid
150  arm64  getresgid                sys_getresgid
151  arm64  setfsuid                 sys_setfsuid
152  arm64  setfsgid                 sys_setfsgid
153  arm64  times                    sys_times
154  arm64  setpgid                  sys_setpgid
155  arm64  getpgid                  sys_getpgid
156  arm64  getsid                   sys_getsid
157  arm64  setsid                   sys_setsid
158  arm64  getgroups                sys_getgroups
159  arm64  setgroups                sys_setgroups
160  arm64  uname                    sys_newuname
161  arm64  sethostname              sys_sethostname
162  arm64  setdomainname            sys_setdomainname
163  arm64  getrlimit                sys_getrlimit
164  arm64  setrlimit                sys_setrlimit
165  arm64  getrusage                sys_getrusage
166  arm64  umask                    sys_umask
167  arm64  prctl                    sys_prctl
168  arm64  getcpu                   sys_getcpu
169  arm64  gettimeofday             sys_gettimeofday
170  arm64  settimeofday             sys_settimeofday
171  arm64  adjtimex                 sys_adjtimex
172  arm64  getpid                   sys_getpid
173  arm64  getppid                  sys_getppid
174  arm64  getuid                   sys_getuid
175  arm64  geteuid                  sys_geteuid
176  arm64  getgid                   sys_getgid
177  arm64  getegid                  sys_getegid
178  arm64  gettid                   sys_gettid
179  arm64  sysinfo                  sys_sysinfo
180  arm64  mq_open                  sys_mq_open
181  arm64  mq_unlink                sys_mq_unlink
182  arm64  mq_timedsend             sys_mq_timedsend
183  arm64  mq_timedreceive          sys_mq_timedreceive
184  arm64  mq_notify                sys_mq_notify
185  arm64  mq_getsetattr            sys_mq_getsetattr
186  arm64  msgget                   sys_msgget
187  arm64  msgctl                   sys_msgctl
188  arm64  msgrcv                   sys_msgrcv
189  arm64  msgsnd                   sys_msgsnd
190  arm64  semget                   sys_semget
191  arm64  semctl                   sys_semctl
192  arm64  semtimedop               sys_semtimedop
193  arm64  semop                    sys_semop
194  arm64  shmget                   sys_shmget
195  arm64  shmctl                   sys_shmctl
196  arm64  shmat                    sys_shmat
197  arm64  shmdt                    sys_shmdt
198  arm64  socket                   sys_socket
199  arm64  socketpair               sys_socketpair
200  arm64  bind                     sys_bind
201  arm64  listen                   sys_listen
202  arm64  accept                   sys_accept
203  arm64  connect                  sys_connect
204  arm64  getsockname              sys_getsockname
205  arm64  getpeername              sys_getpeername
206  arm64  sendto                   sys_sendto
207  arm64  recvfrom                 sys_recvfrom
208  arm64  setsockopt               sys_setsockopt
209  arm64  getsockopt               sys_getsockopt
210  arm64  shutdown                 sys_shutdown
211  arm64  sendmsg                  sys_sendmsg
212  arm64  recvmsg                  sys_recvmsg
213  arm64  readahead                sys_readahead
214  arm64  brk                      sys_brk
215  arm64  munmap                   sys_munmap
216  arm64  mremap                   sys_mremap
217  arm64  add_key                  sys_add_key
218  arm64  request_key              sys_request_key
219  arm64  keyctl                   sys_keyctl
220  arm64  clone                    sys_clone
221  arm64  execve                   sys_execve
222  arm64  mmap                     sys_mmap
223  arm64  fadvise64                sys_fadvise64_64
224  arm64  swapon                   sys_swapon
225  arm64  swapoff                  sys_swapoff
226  arm64  mprotect                 sys_mprotect
227  arm64  msync                    sys_msync
228  arm64  mlock                    sys_mlock
229  arm64  munlock                  sys_munlock
230  arm64  mlockall                 sys_mlockall
231  arm64  munlockall               sys_munlockall
232  arm64  mincore                  sys_mincore
233  arm64  madvise                  sys_madvise
234  arm64  remap_file_pages         sys_remap_file_pages
235  arm64  mbind                    sys_mbind
236  arm64  get_mempolicy            sys_get_mempolicy
237  arm64  set_mempolicy            sys_set_mempolicy
238  arm64  migrate_pages            sys_migrate_pages
239  arm64  move_pages               sys_move_pages
240  arm64  rt_tgsigqueueinfo        sys_rt_tgsigqueueinfo
241  arm64  perf_event_open          sys_perf_event_open
242  arm64  accept4                  sys_accept4
243  arm64  recvmmsg                 sys_recvmmsg
260  arm64  wait4                    sys_wait4
261  arm64  prlimit64                sys_prlimit64
262  arm64  fanotify_init            sys_fanotify_init
263  arm64  fanotify_mark            sys_fanotify_mark
264  arm64  name_to_handle_at        sys_name_to_handle_at
265  arm64  open_by_handle_at        sys_open_by_handle_at
266  arm64  clock_adjtime            sys_clock_adjtime
267  arm64  syncfs                   sys_syncfs
268  arm64  setns                    sys_setns
269  arm64  sendmmsg                 sys_sendmmsg
270  arm64  process_vm_readv         sys_process_vm_readv
271  arm64  process_vm_writev        sys_process_vm_writev
272  arm64  kcmp                     sys_kcmp
273  arm64  finit_module             sys_finit_module
274  arm64  sched_setattr            sys_sched_setattr
275  arm64  sched_getattr            sys_sched_getattr
276  arm64  renameat2                sys_renameat2
277  arm64  seccomp                  sys_seccomp
278  arm64  getrandom                sys_getrandom
279  arm64  memfd_create             sys_memfd_create
280  arm64  bpf                      sys_bpf
281  arm64  execveat                 sys_execveat
282  arm64  userfaultfd              sys_userfaultfd
283  arm64  membarrier               sys_membarrier
284  arm64  mlock2                   sys_mlock2
285  arm64  copy_file_range          sys_copy_file_range
286  arm64  preadv2                  sys_preadv2
287  arm64  pwritev2                 sys_pwritev2
288  arm64  pkey_mprotect            sys_pkey_mprotect
289  arm64  pkey_alloc               sys_pkey_alloc
290  arm64  pkey_free                sys_pkey_free
291  arm64  statx                    sys_statx
292  arm64  io_pgetevents            sys_io_pgetevents
293  arm64  rseq                     sys_rseq
294  arm64  kexec_file_load          sys_kexec_file_load
424  arm64  pidfd_send_signal        sys_pidfd_send_signal
425  arm64  io_uring_setup           sys_io_uring_setup
426  arm64  io_uring_enter           sys_io_uring_enter
427  arm64  io_uring_register        sys_io_uring_register
428  arm64  open_tree                sys_open_tree
429  arm64  move_mount               sys_move_mount
430  arm64  fsopen                   sys_fsopen
431  arm64  fsconfig                 sys_fsconfig
432  arm64  fsmount                  sys_fsmount
433  arm64  fspick                   sys_fspick
434  arm64  pidfd_open               sys_pidfd_open
435  arm64  clone3                   sys_clone3
436  arm64  close_range              sys_close_range
437  arm64  openat2                  sys_openat2
438  arm64  pidfd_getfd              sys_pidfd_getfd
439  arm64  faccessat2               sys_faccessat2
440  arm64  process_madvise          sys_process_madvise
441  arm64  epoll_pwait2             sys_epoll_pwait2
442  arm64  mount_setattr            sys_mount_setattr
443  arm64  quotactl_fd              sys_quotactl_fd
444  arm64  landlock_create_ruleset  sys_landlock_create_ruleset
445  arm64  landlock_add_rule        sys_landlock_add_rule
446  arm64  landlock_restrict_self   sys_landlock_restrict_self
447  arm64  memfd_secret             sys_memfd_secret
448  arm64  process_mrelease         sys_process_mrelease
449  arm64  futex_waitv              sys_futex_waitv
450  arm64  set_mempolicy_home_node  sys_set_mempolicy_home_node
451  arm64  cachestat                sys_cachestat
452  arm64  fchmodat2                sys_fchmodat2
453  arm64  map_shadow_stack         sys_map_shadow_stack
454  arm64  futex_wake               sys_futex_wake
455  arm64  futex_wait               sys_futex_wait
456  arm64  futex_requeue            sys_futex_requeue
457  arm64  statmount                sys_statmount
458  arm64  listmount                sys_listmount
459  arm64  lsm_get_self_attr        sys_lsm_get_self_attr
460  arm64  lsm_set_self_attr        sys_lsm_set_self_attr
461  arm64  lsm_list_modules         sys_lsm_list_modules
462  arm64  mseal                    sys_mseal
"""


# ARM (compat(emulated))
#
# [How to make]
# cd /path/to/linux-6.*/
# gcc -E -D__SYSCALL=SYSCALL arch/arm64/include/asm/unistd32.h \
# | grep ^SYSCALL | sed -e 's/SYSCALL(//;s/[,)]//g' > /tmp/a
# grep -oP "__NR\S+\s+\d+" arch/arm64/include/asm/unistd32.h > /tmp/b
# join -2 2 -o 1.1,1.10,2.1,1.2 -e arm /tmp/a /tmp/b | sed -e 's/__NR_//g' | column -t
#
arm_compat_syscall_tbl = """
0    arm  restart_syscall               sys_restart_syscall
1    arm  exit                          sys_exit
2    arm  fork                          sys_fork
3    arm  read                          sys_read
4    arm  write                         sys_write
5    arm  open                          compat_sys_open
6    arm  close                         sys_close
8    arm  creat                         sys_creat
9    arm  link                          sys_link
10   arm  unlink                        sys_unlink
11   arm  execve                        compat_sys_execve
12   arm  chdir                         sys_chdir
14   arm  mknod                         sys_mknod
15   arm  chmod                         sys_chmod
16   arm  lchown                        sys_lchown16
19   arm  lseek                         compat_sys_lseek
20   arm  getpid                        sys_getpid
21   arm  mount                         sys_mount
23   arm  setuid                        sys_setuid16
24   arm  getuid                        sys_getuid16
26   arm  ptrace                        compat_sys_ptrace
29   arm  pause                         sys_pause
33   arm  access                        sys_access
34   arm  nice                          sys_nice
36   arm  sync                          sys_sync
37   arm  kill                          sys_kill
38   arm  rename                        sys_rename
39   arm  mkdir                         sys_mkdir
40   arm  rmdir                         sys_rmdir
41   arm  dup                           sys_dup
42   arm  pipe                          sys_pipe
43   arm  times                         compat_sys_times
45   arm  brk                           sys_brk
46   arm  setgid                        sys_setgid16
47   arm  getgid                        sys_getgid16
49   arm  geteuid                       sys_geteuid16
50   arm  getegid                       sys_getegid16
51   arm  acct                          sys_acct
52   arm  umount2                       sys_umount
54   arm  ioctl                         compat_sys_ioctl
55   arm  fcntl                         compat_sys_fcntl
57   arm  setpgid                       sys_setpgid
60   arm  umask                         sys_umask
61   arm  chroot                        sys_chroot
62   arm  ustat                         compat_sys_ustat
63   arm  dup2                          sys_dup2
64   arm  getppid                       sys_getppid
65   arm  getpgrp                       sys_getpgrp
66   arm  setsid                        sys_setsid
67   arm  sigaction                     compat_sys_sigaction
70   arm  setreuid                      sys_setreuid16
71   arm  setregid                      sys_setregid16
72   arm  sigsuspend                    sys_sigsuspend
73   arm  sigpending                    compat_sys_sigpending
74   arm  sethostname                   sys_sethostname
75   arm  setrlimit                     compat_sys_setrlimit
77   arm  getrusage                     compat_sys_getrusage
78   arm  gettimeofday                  compat_sys_gettimeofday
79   arm  settimeofday                  compat_sys_settimeofday
80   arm  getgroups                     sys_getgroups16
81   arm  setgroups                     sys_setgroups16
83   arm  symlink                       sys_symlink
85   arm  readlink                      sys_readlink
86   arm  uselib                        sys_uselib
87   arm  swapon                        sys_swapon
88   arm  reboot                        sys_reboot
91   arm  munmap                        sys_munmap
92   arm  truncate                      compat_sys_truncate
93   arm  ftruncate                     compat_sys_ftruncate
94   arm  fchmod                        sys_fchmod
95   arm  fchown                        sys_fchown16
96   arm  getpriority                   sys_getpriority
97   arm  setpriority                   sys_setpriority
99   arm  statfs                        compat_sys_statfs
100  arm  fstatfs                       compat_sys_fstatfs
103  arm  syslog                        sys_syslog
104  arm  setitimer                     compat_sys_setitimer
105  arm  getitimer                     compat_sys_getitimer
106  arm  stat                          compat_sys_newstat
107  arm  lstat                         compat_sys_newlstat
108  arm  fstat                         compat_sys_newfstat
111  arm  vhangup                       sys_vhangup
114  arm  wait4                         compat_sys_wait4
115  arm  swapoff                       sys_swapoff
116  arm  sysinfo                       compat_sys_sysinfo
118  arm  fsync                         sys_fsync
119  arm  sigreturn                     compat_sys_sigreturn
120  arm  clone                         sys_clone
121  arm  setdomainname                 sys_setdomainname
122  arm  uname                         sys_newuname
124  arm  adjtimex                      sys_adjtimex_time32
125  arm  mprotect                      sys_mprotect
126  arm  sigprocmask                   compat_sys_sigprocmask
128  arm  init_module                   sys_init_module
129  arm  delete_module                 sys_delete_module
131  arm  quotactl                      sys_quotactl
132  arm  getpgid                       sys_getpgid
133  arm  fchdir                        sys_fchdir
134  arm  bdflush                       sys_ni_syscall
135  arm  sysfs                         sys_sysfs
136  arm  personality                   sys_personality
138  arm  setfsuid                      sys_setfsuid16
139  arm  setfsgid                      sys_setfsgid16
140  arm  _llseek                       sys_llseek
141  arm  getdents                      compat_sys_getdents
142  arm  _newselect                    compat_sys_select
143  arm  flock                         sys_flock
144  arm  msync                         sys_msync
145  arm  readv                         sys_readv
146  arm  writev                        sys_writev
147  arm  getsid                        sys_getsid
148  arm  fdatasync                     sys_fdatasync
150  arm  mlock                         sys_mlock
151  arm  munlock                       sys_munlock
152  arm  mlockall                      sys_mlockall
153  arm  munlockall                    sys_munlockall
154  arm  sched_setparam                sys_sched_setparam
155  arm  sched_getparam                sys_sched_getparam
156  arm  sched_setscheduler            sys_sched_setscheduler
157  arm  sched_getscheduler            sys_sched_getscheduler
158  arm  sched_yield                   sys_sched_yield
159  arm  sched_get_priority_max        sys_sched_get_priority_max
160  arm  sched_get_priority_min        sys_sched_get_priority_min
161  arm  sched_rr_get_interval         sys_sched_rr_get_interval_time32
162  arm  nanosleep                     sys_nanosleep_time32
163  arm  mremap                        sys_mremap
164  arm  setresuid                     sys_setresuid16
165  arm  getresuid                     sys_getresuid16
168  arm  poll                          sys_poll
169  arm  nfsservctl                    sys_ni_syscall
170  arm  setresgid                     sys_setresgid16
171  arm  getresgid                     sys_getresgid16
172  arm  prctl                         sys_prctl
173  arm  rt_sigreturn                  compat_sys_rt_sigreturn
174  arm  rt_sigaction                  compat_sys_rt_sigaction
175  arm  rt_sigprocmask                compat_sys_rt_sigprocmask
176  arm  rt_sigpending                 compat_sys_rt_sigpending
177  arm  rt_sigtimedwait               compat_sys_rt_sigtimedwait_time32
178  arm  rt_sigqueueinfo               compat_sys_rt_sigqueueinfo
179  arm  rt_sigsuspend                 compat_sys_rt_sigsuspend
180  arm  pread64                       compat_sys_aarch32_pread64
181  arm  pwrite64                      compat_sys_aarch32_pwrite64
182  arm  chown                         sys_chown16
183  arm  getcwd                        sys_getcwd
184  arm  capget                        sys_capget
185  arm  capset                        sys_capset
186  arm  sigaltstack                   compat_sys_sigaltstack
187  arm  sendfile                      compat_sys_sendfile
190  arm  vfork                         sys_vfork
191  arm  ugetrlimit                    compat_sys_getrlimit
192  arm  mmap2                         compat_sys_aarch32_mmap2
193  arm  truncate64                    compat_sys_aarch32_truncate64
194  arm  ftruncate64                   compat_sys_aarch32_ftruncate64
195  arm  stat64                        sys_stat64
196  arm  lstat64                       sys_lstat64
197  arm  fstat64                       sys_fstat64
198  arm  lchown32                      sys_lchown
199  arm  getuid32                      sys_getuid
200  arm  getgid32                      sys_getgid
201  arm  geteuid32                     sys_geteuid
202  arm  getegid32                     sys_getegid
203  arm  setreuid32                    sys_setreuid
204  arm  setregid32                    sys_setregid
205  arm  getgroups32                   sys_getgroups
206  arm  setgroups32                   sys_setgroups
207  arm  fchown32                      sys_fchown
208  arm  setresuid32                   sys_setresuid
209  arm  getresuid32                   sys_getresuid
210  arm  setresgid32                   sys_setresgid
211  arm  getresgid32                   sys_getresgid
212  arm  chown32                       sys_chown
213  arm  setuid32                      sys_setuid
214  arm  setgid32                      sys_setgid
215  arm  setfsuid32                    sys_setfsuid
216  arm  setfsgid32                    sys_setfsgid
217  arm  getdents64                    sys_getdents64
218  arm  pivot_root                    sys_pivot_root
219  arm  mincore                       sys_mincore
220  arm  madvise                       sys_madvise
221  arm  fcntl64                       compat_sys_fcntl64
224  arm  gettid                        sys_gettid
225  arm  readahead                     compat_sys_aarch32_readahead
226  arm  setxattr                      sys_setxattr
227  arm  lsetxattr                     sys_lsetxattr
228  arm  fsetxattr                     sys_fsetxattr
229  arm  getxattr                      sys_getxattr
230  arm  lgetxattr                     sys_lgetxattr
231  arm  fgetxattr                     sys_fgetxattr
232  arm  listxattr                     sys_listxattr
233  arm  llistxattr                    sys_llistxattr
234  arm  flistxattr                    sys_flistxattr
235  arm  removexattr                   sys_removexattr
236  arm  lremovexattr                  sys_lremovexattr
237  arm  fremovexattr                  sys_fremovexattr
238  arm  tkill                         sys_tkill
239  arm  sendfile64                    sys_sendfile64
240  arm  futex                         sys_futex_time32
241  arm  sched_setaffinity             compat_sys_sched_setaffinity
242  arm  sched_getaffinity             compat_sys_sched_getaffinity
243  arm  io_setup                      compat_sys_io_setup
244  arm  io_destroy                    sys_io_destroy
245  arm  io_getevents                  sys_io_getevents_time32
246  arm  io_submit                     compat_sys_io_submit
247  arm  io_cancel                     sys_io_cancel
248  arm  exit_group                    sys_exit_group
250  arm  epoll_create                  sys_epoll_create
251  arm  epoll_ctl                     sys_epoll_ctl
252  arm  epoll_wait                    sys_epoll_wait
253  arm  remap_file_pages              sys_remap_file_pages
256  arm  set_tid_address               sys_set_tid_address
257  arm  timer_create                  compat_sys_timer_create
258  arm  timer_settime                 sys_timer_settime32
259  arm  timer_gettime                 sys_timer_gettime32
260  arm  timer_getoverrun              sys_timer_getoverrun
261  arm  timer_delete                  sys_timer_delete
262  arm  clock_settime                 sys_clock_settime32
263  arm  clock_gettime                 sys_clock_gettime32
264  arm  clock_getres                  sys_clock_getres_time32
265  arm  clock_nanosleep               sys_clock_nanosleep_time32
266  arm  statfs64                      compat_sys_aarch32_statfs64
267  arm  fstatfs64                     compat_sys_aarch32_fstatfs64
268  arm  tgkill                        sys_tgkill
269  arm  utimes                        sys_utimes_time32
270  arm  arm_fadvise64_64              compat_sys_aarch32_fadvise64_64
271  arm  pciconfig_iobase              sys_pciconfig_iobase
272  arm  pciconfig_read                sys_pciconfig_read
273  arm  pciconfig_write               sys_pciconfig_write
274  arm  mq_open                       compat_sys_mq_open
275  arm  mq_unlink                     sys_mq_unlink
276  arm  mq_timedsend                  sys_mq_timedsend_time32
277  arm  mq_timedreceive               sys_mq_timedreceive_time32
278  arm  mq_notify                     compat_sys_mq_notify
279  arm  mq_getsetattr                 compat_sys_mq_getsetattr
280  arm  waitid                        compat_sys_waitid
281  arm  socket                        sys_socket
282  arm  bind                          sys_bind
283  arm  connect                       sys_connect
284  arm  listen                        sys_listen
285  arm  accept                        sys_accept
286  arm  getsockname                   sys_getsockname
287  arm  getpeername                   sys_getpeername
288  arm  socketpair                    sys_socketpair
289  arm  send                          sys_send
290  arm  sendto                        sys_sendto
291  arm  recv                          compat_sys_recv
292  arm  recvfrom                      compat_sys_recvfrom
293  arm  shutdown                      sys_shutdown
294  arm  setsockopt                    sys_setsockopt
295  arm  getsockopt                    sys_getsockopt
296  arm  sendmsg                       compat_sys_sendmsg
297  arm  recvmsg                       compat_sys_recvmsg
298  arm  semop                         sys_semop
299  arm  semget                        sys_semget
300  arm  semctl                        compat_sys_old_semctl
301  arm  msgsnd                        compat_sys_msgsnd
302  arm  msgrcv                        compat_sys_msgrcv
303  arm  msgget                        sys_msgget
304  arm  msgctl                        compat_sys_old_msgctl
305  arm  shmat                         compat_sys_shmat
306  arm  shmdt                         sys_shmdt
307  arm  shmget                        sys_shmget
308  arm  shmctl                        compat_sys_old_shmctl
309  arm  add_key                       sys_add_key
310  arm  request_key                   sys_request_key
311  arm  keyctl                        compat_sys_keyctl
312  arm  semtimedop                    sys_semtimedop_time32
313  arm  vserver                       sys_ni_syscall
314  arm  ioprio_set                    sys_ioprio_set
315  arm  ioprio_get                    sys_ioprio_get
316  arm  inotify_init                  sys_inotify_init
317  arm  inotify_add_watch             sys_inotify_add_watch
318  arm  inotify_rm_watch              sys_inotify_rm_watch
319  arm  mbind                         sys_mbind
320  arm  get_mempolicy                 sys_get_mempolicy
321  arm  set_mempolicy                 sys_set_mempolicy
322  arm  openat                        compat_sys_openat
323  arm  mkdirat                       sys_mkdirat
324  arm  mknodat                       sys_mknodat
325  arm  fchownat                      sys_fchownat
326  arm  futimesat                     sys_futimesat_time32
327  arm  fstatat64                     sys_fstatat64
328  arm  unlinkat                      sys_unlinkat
329  arm  renameat                      sys_renameat
330  arm  linkat                        sys_linkat
331  arm  symlinkat                     sys_symlinkat
332  arm  readlinkat                    sys_readlinkat
333  arm  fchmodat                      sys_fchmodat
334  arm  faccessat                     sys_faccessat
335  arm  pselect6                      compat_sys_pselect6_time32
336  arm  ppoll                         compat_sys_ppoll_time32
337  arm  unshare                       sys_unshare
338  arm  set_robust_list               compat_sys_set_robust_list
339  arm  get_robust_list               compat_sys_get_robust_list
340  arm  splice                        sys_splice
341  arm  sync_file_range2              compat_sys_aarch32_sync_file_range2
342  arm  tee                           sys_tee
343  arm  vmsplice                      sys_vmsplice
344  arm  move_pages                    sys_move_pages
345  arm  getcpu                        sys_getcpu
346  arm  epoll_pwait                   compat_sys_epoll_pwait
347  arm  kexec_load                    compat_sys_kexec_load
348  arm  utimensat                     sys_utimensat_time32
349  arm  signalfd                      compat_sys_signalfd
350  arm  timerfd_create                sys_timerfd_create
351  arm  eventfd                       sys_eventfd
352  arm  fallocate                     compat_sys_aarch32_fallocate
353  arm  timerfd_settime               sys_timerfd_settime32
354  arm  timerfd_gettime               sys_timerfd_gettime32
355  arm  signalfd4                     compat_sys_signalfd4
356  arm  eventfd2                      sys_eventfd2
357  arm  epoll_create1                 sys_epoll_create1
358  arm  dup3                          sys_dup3
359  arm  pipe2                         sys_pipe2
360  arm  inotify_init1                 sys_inotify_init1
361  arm  preadv                        compat_sys_preadv
362  arm  pwritev                       compat_sys_pwritev
363  arm  rt_tgsigqueueinfo             compat_sys_rt_tgsigqueueinfo
364  arm  perf_event_open               sys_perf_event_open
365  arm  recvmmsg                      compat_sys_recvmmsg_time32
366  arm  accept4                       sys_accept4
367  arm  fanotify_init                 sys_fanotify_init
368  arm  fanotify_mark                 compat_sys_fanotify_mark
369  arm  prlimit64                     sys_prlimit64
370  arm  name_to_handle_at             sys_name_to_handle_at
371  arm  open_by_handle_at             compat_sys_open_by_handle_at
372  arm  clock_adjtime                 sys_clock_adjtime32
373  arm  syncfs                        sys_syncfs
374  arm  sendmmsg                      compat_sys_sendmmsg
375  arm  setns                         sys_setns
376  arm  process_vm_readv              sys_process_vm_readv
377  arm  process_vm_writev             sys_process_vm_writev
378  arm  kcmp                          sys_kcmp
379  arm  finit_module                  sys_finit_module
380  arm  sched_setattr                 sys_sched_setattr
381  arm  sched_getattr                 sys_sched_getattr
382  arm  renameat2                     sys_renameat2
383  arm  seccomp                       sys_seccomp
384  arm  getrandom                     sys_getrandom
385  arm  memfd_create                  sys_memfd_create
386  arm  bpf                           sys_bpf
387  arm  execveat                      compat_sys_execveat
388  arm  userfaultfd                   sys_userfaultfd
389  arm  membarrier                    sys_membarrier
390  arm  mlock2                        sys_mlock2
391  arm  copy_file_range               sys_copy_file_range
392  arm  preadv2                       compat_sys_preadv2
393  arm  pwritev2                      compat_sys_pwritev2
394  arm  pkey_mprotect                 sys_pkey_mprotect
395  arm  pkey_alloc                    sys_pkey_alloc
396  arm  pkey_free                     sys_pkey_free
397  arm  statx                         sys_statx
398  arm  rseq                          sys_rseq
399  arm  io_pgetevents                 compat_sys_io_pgetevents
400  arm  migrate_pages                 sys_migrate_pages
401  arm  kexec_file_load               sys_kexec_file_load
403  arm  clock_gettime64               sys_clock_gettime
404  arm  clock_settime64               sys_clock_settime
405  arm  clock_adjtime64               sys_clock_adjtime
406  arm  clock_getres_time64           sys_clock_getres
407  arm  clock_nanosleep_time64        sys_clock_nanosleep
408  arm  timer_gettime64               sys_timer_gettime
409  arm  timer_settime64               sys_timer_settime
410  arm  timerfd_gettime64             sys_timerfd_gettime
411  arm  timerfd_settime64             sys_timerfd_settime
412  arm  utimensat_time64              sys_utimensat
413  arm  pselect6_time64               compat_sys_pselect6_time64
414  arm  ppoll_time64                  compat_sys_ppoll_time64
416  arm  io_pgetevents_time64          compat_sys_io_pgetevents_time64
417  arm  recvmmsg_time64               compat_sys_recvmmsg_time64
418  arm  mq_timedsend_time64           sys_mq_timedsend
419  arm  mq_timedreceive_time64        sys_mq_timedreceive
420  arm  semtimedop_time64             sys_semtimedop
421  arm  rt_sigtimedwait_time64        compat_sys_rt_sigtimedwait_time64
422  arm  futex_time64                  sys_futex
423  arm  sched_rr_get_interval_time64  sys_sched_rr_get_interval
424  arm  pidfd_send_signal             sys_pidfd_send_signal
425  arm  io_uring_setup                sys_io_uring_setup
426  arm  io_uring_enter                sys_io_uring_enter
427  arm  io_uring_register             sys_io_uring_register
428  arm  open_tree                     sys_open_tree
429  arm  move_mount                    sys_move_mount
430  arm  fsopen                        sys_fsopen
431  arm  fsconfig                      sys_fsconfig
432  arm  fsmount                       sys_fsmount
433  arm  fspick                        sys_fspick
434  arm  pidfd_open                    sys_pidfd_open
435  arm  clone3                        sys_clone3
436  arm  close_range                   sys_close_range
437  arm  openat2                       sys_openat2
438  arm  pidfd_getfd                   sys_pidfd_getfd
439  arm  faccessat2                    sys_faccessat2
440  arm  process_madvise               sys_process_madvise
441  arm  epoll_pwait2                  compat_sys_epoll_pwait2
442  arm  mount_setattr                 sys_mount_setattr
443  arm  quotactl_fd                   sys_quotactl_fd
444  arm  landlock_create_ruleset       sys_landlock_create_ruleset
445  arm  landlock_add_rule             sys_landlock_add_rule
446  arm  landlock_restrict_self        sys_landlock_restrict_self
448  arm  process_mrelease              sys_process_mrelease
449  arm  futex_waitv                   sys_futex_waitv
450  arm  set_mempolicy_home_node       sys_set_mempolicy_home_node
451  arm  cachestat                     sys_cachestat
452  arm  fchmodat2                     sys_fchmodat2
453  arm  map_shadow_stack              sys_map_shadow_stack
454  arm  futex_wake                    sys_futex_wake
455  arm  futex_wait                    sys_futex_wait
456  arm  futex_requeue                 sys_futex_requeue
457  arm  statmount                     sys_statmount
458  arm  listmount                     sys_listmount
459  arm  lsm_get_self_attr             sys_lsm_get_self_attr
460  arm  lsm_set_self_attr             sys_lsm_set_self_attr
461  arm  lsm_list_modules              sys_lsm_list_modules
462  arm  mseal                         sys_mseal
"""

# ARM (native)
# - arch/arm/tools/syscall.tbl
arm_native_syscall_tbl = """
#
# Linux system call numbers and entry vectors
#
# The format is:
# <num> <abi>   <name>                  [<entry point>                  [<oabi compat entry point>]]
#
# Where abi is:
#  common - for system calls shared between oabi and eabi (may have compat)
#  oabi   - for oabi-only system calls (may have compat)
#  eabi   - for eabi-only system calls
#
# For each syscall number, "common" is mutually exclusive with oabi and eabi
#
0       common  restart_syscall         sys_restart_syscall
1       common  exit                    sys_exit
2       common  fork                    sys_fork
3       common  read                    sys_read
4       common  write                   sys_write
5       common  open                    sys_open
6       common  close                   sys_close
# 7 was sys_waitpid
8       common  creat                   sys_creat
9       common  link                    sys_link
10      common  unlink                  sys_unlink
11      common  execve                  sys_execve
12      common  chdir                   sys_chdir
13      oabi    time                    sys_time32
14      common  mknod                   sys_mknod
15      common  chmod                   sys_chmod
16      common  lchown                  sys_lchown16
# 17 was sys_break
# 18 was sys_stat
19      common  lseek                   sys_lseek
20      common  getpid                  sys_getpid
21      common  mount                   sys_mount
22      oabi    umount                  sys_oldumount
23      common  setuid                  sys_setuid16
24      common  getuid                  sys_getuid16
25      oabi    stime                   sys_stime32
26      common  ptrace                  sys_ptrace
27      oabi    alarm                   sys_alarm
# 28 was sys_fstat
29      common  pause                   sys_pause
30      oabi    utime                   sys_utime32
# 31 was sys_stty
# 32 was sys_gtty
33      common  access                  sys_access
34      common  nice                    sys_nice
# 35 was sys_ftime
36      common  sync                    sys_sync
37      common  kill                    sys_kill
38      common  rename                  sys_rename
39      common  mkdir                   sys_mkdir
40      common  rmdir                   sys_rmdir
41      common  dup                     sys_dup
42      common  pipe                    sys_pipe
43      common  times                   sys_times
# 44 was sys_prof
45      common  brk                     sys_brk
46      common  setgid                  sys_setgid16
47      common  getgid                  sys_getgid16
# 48 was sys_signal
49      common  geteuid                 sys_geteuid16
50      common  getegid                 sys_getegid16
51      common  acct                    sys_acct
52      common  umount2                 sys_umount
# 53 was sys_lock
54      common  ioctl                   sys_ioctl
55      common  fcntl                   sys_fcntl
# 56 was sys_mpx
57      common  setpgid                 sys_setpgid
# 58 was sys_ulimit
# 59 was sys_olduname
60      common  umask                   sys_umask
61      common  chroot                  sys_chroot
62      common  ustat                   sys_ustat
63      common  dup2                    sys_dup2
64      common  getppid                 sys_getppid
65      common  getpgrp                 sys_getpgrp
66      common  setsid                  sys_setsid
67      common  sigaction               sys_sigaction
# 68 was sys_sgetmask
# 69 was sys_ssetmask
70      common  setreuid                sys_setreuid16
71      common  setregid                sys_setregid16
72      common  sigsuspend              sys_sigsuspend
73      common  sigpending              sys_sigpending
74      common  sethostname             sys_sethostname
75      common  setrlimit               sys_setrlimit
# Back compat 2GB limited rlimit
76      oabi    getrlimit               sys_old_getrlimit
77      common  getrusage               sys_getrusage
78      common  gettimeofday            sys_gettimeofday
79      common  settimeofday            sys_settimeofday
80      common  getgroups               sys_getgroups16
81      common  setgroups               sys_setgroups16
82      oabi    select                  sys_old_select
83      common  symlink                 sys_symlink
# 84 was sys_lstat
85      common  readlink                sys_readlink
86      common  uselib                  sys_uselib
87      common  swapon                  sys_swapon
88      common  reboot                  sys_reboot
89      oabi    readdir                 sys_old_readdir
90      oabi    mmap                    sys_old_mmap
91      common  munmap                  sys_munmap
92      common  truncate                sys_truncate
93      common  ftruncate               sys_ftruncate
94      common  fchmod                  sys_fchmod
95      common  fchown                  sys_fchown16
96      common  getpriority             sys_getpriority
97      common  setpriority             sys_setpriority
# 98 was sys_profil
99      common  statfs                  sys_statfs
100     common  fstatfs                 sys_fstatfs
# 101 was sys_ioperm
102     oabi    socketcall              sys_socketcall          sys_oabi_socketcall
103     common  syslog                  sys_syslog
104     common  setitimer               sys_setitimer
105     common  getitimer               sys_getitimer
106     common  stat                    sys_newstat
107     common  lstat                   sys_newlstat
108     common  fstat                   sys_newfstat
# 109 was sys_uname
# 110 was sys_iopl
111     common  vhangup                 sys_vhangup
# 112 was sys_idle
# syscall to call a syscall!
113     oabi    syscall                 sys_syscall
114     common  wait4                   sys_wait4
115     common  swapoff                 sys_swapoff
116     common  sysinfo                 sys_sysinfo
117     oabi    ipc                     sys_ipc                 sys_oabi_ipc
118     common  fsync                   sys_fsync
119     common  sigreturn               sys_sigreturn_wrapper
120     common  clone                   sys_clone
121     common  setdomainname           sys_setdomainname
122     common  uname                   sys_newuname
# 123 was sys_modify_ldt
124     common  adjtimex                sys_adjtimex_time32
125     common  mprotect                sys_mprotect
126     common  sigprocmask             sys_sigprocmask
# 127 was sys_create_module
128     common  init_module             sys_init_module
129     common  delete_module           sys_delete_module
# 130 was sys_get_kernel_syms
131     common  quotactl                sys_quotactl
132     common  getpgid                 sys_getpgid
133     common  fchdir                  sys_fchdir
134     common  bdflush                 sys_ni_syscall
135     common  sysfs                   sys_sysfs
136     common  personality             sys_personality
# 137 was sys_afs_syscall
138     common  setfsuid                sys_setfsuid16
139     common  setfsgid                sys_setfsgid16
140     common  _llseek                 sys_llseek
141     common  getdents                sys_getdents
142     common  _newselect              sys_select
143     common  flock                   sys_flock
144     common  msync                   sys_msync
145     common  readv                   sys_readv
146     common  writev                  sys_writev
147     common  getsid                  sys_getsid
148     common  fdatasync               sys_fdatasync
149     common  _sysctl                 sys_ni_syscall
150     common  mlock                   sys_mlock
151     common  munlock                 sys_munlock
152     common  mlockall                sys_mlockall
153     common  munlockall              sys_munlockall
154     common  sched_setparam          sys_sched_setparam
155     common  sched_getparam          sys_sched_getparam
156     common  sched_setscheduler      sys_sched_setscheduler
157     common  sched_getscheduler      sys_sched_getscheduler
158     common  sched_yield             sys_sched_yield
159     common  sched_get_priority_max  sys_sched_get_priority_max
160     common  sched_get_priority_min  sys_sched_get_priority_min
161     common  sched_rr_get_interval   sys_sched_rr_get_interval_time32
162     common  nanosleep               sys_nanosleep_time32
163     common  mremap                  sys_mremap
164     common  setresuid               sys_setresuid16
165     common  getresuid               sys_getresuid16
# 166 was sys_vm86
# 167 was sys_query_module
168     common  poll                    sys_poll
169     common  nfsservctl
170     common  setresgid               sys_setresgid16
171     common  getresgid               sys_getresgid16
172     common  prctl                   sys_prctl
173     common  rt_sigreturn            sys_rt_sigreturn_wrapper
174     common  rt_sigaction            sys_rt_sigaction
175     common  rt_sigprocmask          sys_rt_sigprocmask
176     common  rt_sigpending           sys_rt_sigpending
177     common  rt_sigtimedwait         sys_rt_sigtimedwait_time32
178     common  rt_sigqueueinfo         sys_rt_sigqueueinfo
179     common  rt_sigsuspend           sys_rt_sigsuspend
180     common  pread64                 sys_pread64             sys_oabi_pread64
181     common  pwrite64                sys_pwrite64            sys_oabi_pwrite64
182     common  chown                   sys_chown16
183     common  getcwd                  sys_getcwd
184     common  capget                  sys_capget
185     common  capset                  sys_capset
186     common  sigaltstack             sys_sigaltstack
187     common  sendfile                sys_sendfile
# 188 reserved
# 189 reserved
190     common  vfork                   sys_vfork
# SuS compliant getrlimit
191     common  ugetrlimit              sys_getrlimit
192     common  mmap2                   sys_mmap2
193     common  truncate64              sys_truncate64          sys_oabi_truncate64
194     common  ftruncate64             sys_ftruncate64         sys_oabi_ftruncate64
195     common  stat64                  sys_stat64              sys_oabi_stat64
196     common  lstat64                 sys_lstat64             sys_oabi_lstat64
197     common  fstat64                 sys_fstat64             sys_oabi_fstat64
198     common  lchown32                sys_lchown
199     common  getuid32                sys_getuid
200     common  getgid32                sys_getgid
201     common  geteuid32               sys_geteuid
202     common  getegid32               sys_getegid
203     common  setreuid32              sys_setreuid
204     common  setregid32              sys_setregid
205     common  getgroups32             sys_getgroups
206     common  setgroups32             sys_setgroups
207     common  fchown32                sys_fchown
208     common  setresuid32             sys_setresuid
209     common  getresuid32             sys_getresuid
210     common  setresgid32             sys_setresgid
211     common  getresgid32             sys_getresgid
212     common  chown32                 sys_chown
213     common  setuid32                sys_setuid
214     common  setgid32                sys_setgid
215     common  setfsuid32              sys_setfsuid
216     common  setfsgid32              sys_setfsgid
217     common  getdents64              sys_getdents64
218     common  pivot_root              sys_pivot_root
219     common  mincore                 sys_mincore
220     common  madvise                 sys_madvise
221     common  fcntl64                 sys_fcntl64             sys_oabi_fcntl64
# 222 for tux
# 223 is unused
224     common  gettid                  sys_gettid
225     common  readahead               sys_readahead           sys_oabi_readahead
226     common  setxattr                sys_setxattr
227     common  lsetxattr               sys_lsetxattr
228     common  fsetxattr               sys_fsetxattr
229     common  getxattr                sys_getxattr
230     common  lgetxattr               sys_lgetxattr
231     common  fgetxattr               sys_fgetxattr
232     common  listxattr               sys_listxattr
233     common  llistxattr              sys_llistxattr
234     common  flistxattr              sys_flistxattr
235     common  removexattr             sys_removexattr
236     common  lremovexattr            sys_lremovexattr
237     common  fremovexattr            sys_fremovexattr
238     common  tkill                   sys_tkill
239     common  sendfile64              sys_sendfile64
240     common  futex                   sys_futex_time32
241     common  sched_setaffinity       sys_sched_setaffinity
242     common  sched_getaffinity       sys_sched_getaffinity
243     common  io_setup                sys_io_setup
244     common  io_destroy              sys_io_destroy
245     common  io_getevents            sys_io_getevents_time32
246     common  io_submit               sys_io_submit
247     common  io_cancel               sys_io_cancel
248     common  exit_group              sys_exit_group
249     common  lookup_dcookie          sys_ni_syscall
250     common  epoll_create            sys_epoll_create
251     common  epoll_ctl               sys_epoll_ctl           sys_oabi_epoll_ctl
252     common  epoll_wait              sys_epoll_wait
253     common  remap_file_pages        sys_remap_file_pages
# 254 for set_thread_area
# 255 for get_thread_area
256     common  set_tid_address         sys_set_tid_address
257     common  timer_create            sys_timer_create
258     common  timer_settime           sys_timer_settime32
259     common  timer_gettime           sys_timer_gettime32
260     common  timer_getoverrun        sys_timer_getoverrun
261     common  timer_delete            sys_timer_delete
262     common  clock_settime           sys_clock_settime32
263     common  clock_gettime           sys_clock_gettime32
264     common  clock_getres            sys_clock_getres_time32
265     common  clock_nanosleep         sys_clock_nanosleep_time32
266     common  statfs64                sys_statfs64_wrapper
267     common  fstatfs64               sys_fstatfs64_wrapper
268     common  tgkill                  sys_tgkill
269     common  utimes                  sys_utimes_time32
270     common  arm_fadvise64_64        sys_arm_fadvise64_64
271     common  pciconfig_iobase        sys_pciconfig_iobase
272     common  pciconfig_read          sys_pciconfig_read
273     common  pciconfig_write         sys_pciconfig_write
274     common  mq_open                 sys_mq_open
275     common  mq_unlink               sys_mq_unlink
276     common  mq_timedsend            sys_mq_timedsend_time32
277     common  mq_timedreceive         sys_mq_timedreceive_time32
278     common  mq_notify               sys_mq_notify
279     common  mq_getsetattr           sys_mq_getsetattr
280     common  waitid                  sys_waitid
281     common  socket                  sys_socket
282     common  bind                    sys_bind                sys_oabi_bind
283     common  connect                 sys_connect             sys_oabi_connect
284     common  listen                  sys_listen
285     common  accept                  sys_accept
286     common  getsockname             sys_getsockname
287     common  getpeername             sys_getpeername
288     common  socketpair              sys_socketpair
289     common  send                    sys_send
290     common  sendto                  sys_sendto              sys_oabi_sendto
291     common  recv                    sys_recv
292     common  recvfrom                sys_recvfrom
293     common  shutdown                sys_shutdown
294     common  setsockopt              sys_setsockopt
295     common  getsockopt              sys_getsockopt
296     common  sendmsg                 sys_sendmsg             sys_oabi_sendmsg
297     common  recvmsg                 sys_recvmsg
298     common  semop                   sys_semop               sys_oabi_semop
299     common  semget                  sys_semget
300     common  semctl                  sys_old_semctl
301     common  msgsnd                  sys_msgsnd
302     common  msgrcv                  sys_msgrcv
303     common  msgget                  sys_msgget
304     common  msgctl                  sys_old_msgctl
305     common  shmat                   sys_shmat
306     common  shmdt                   sys_shmdt
307     common  shmget                  sys_shmget
308     common  shmctl                  sys_old_shmctl
309     common  add_key                 sys_add_key
310     common  request_key             sys_request_key
311     common  keyctl                  sys_keyctl
312     common  semtimedop              sys_semtimedop_time32   sys_oabi_semtimedop
313     common  vserver
314     common  ioprio_set              sys_ioprio_set
315     common  ioprio_get              sys_ioprio_get
316     common  inotify_init            sys_inotify_init
317     common  inotify_add_watch       sys_inotify_add_watch
318     common  inotify_rm_watch        sys_inotify_rm_watch
319     common  mbind                   sys_mbind
320     common  get_mempolicy           sys_get_mempolicy
321     common  set_mempolicy           sys_set_mempolicy
322     common  openat                  sys_openat
323     common  mkdirat                 sys_mkdirat
324     common  mknodat                 sys_mknodat
325     common  fchownat                sys_fchownat
326     common  futimesat               sys_futimesat_time32
327     common  fstatat64               sys_fstatat64           sys_oabi_fstatat64
328     common  unlinkat                sys_unlinkat
329     common  renameat                sys_renameat
330     common  linkat                  sys_linkat
331     common  symlinkat               sys_symlinkat
332     common  readlinkat              sys_readlinkat
333     common  fchmodat                sys_fchmodat
334     common  faccessat               sys_faccessat
335     common  pselect6                sys_pselect6_time32
336     common  ppoll                   sys_ppoll_time32
337     common  unshare                 sys_unshare
338     common  set_robust_list         sys_set_robust_list
339     common  get_robust_list         sys_get_robust_list
340     common  splice                  sys_splice
341     common  arm_sync_file_range     sys_sync_file_range2
342     common  tee                     sys_tee
343     common  vmsplice                sys_vmsplice
344     common  move_pages              sys_move_pages
345     common  getcpu                  sys_getcpu
346     common  epoll_pwait             sys_epoll_pwait
347     common  kexec_load              sys_kexec_load
348     common  utimensat               sys_utimensat_time32
349     common  signalfd                sys_signalfd
350     common  timerfd_create          sys_timerfd_create
351     common  eventfd                 sys_eventfd
352     common  fallocate               sys_fallocate
353     common  timerfd_settime         sys_timerfd_settime32
354     common  timerfd_gettime         sys_timerfd_gettime32
355     common  signalfd4               sys_signalfd4
356     common  eventfd2                sys_eventfd2
357     common  epoll_create1           sys_epoll_create1
358     common  dup3                    sys_dup3
359     common  pipe2                   sys_pipe2
360     common  inotify_init1           sys_inotify_init1
361     common  preadv                  sys_preadv
362     common  pwritev                 sys_pwritev
363     common  rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo
364     common  perf_event_open         sys_perf_event_open
365     common  recvmmsg                sys_recvmmsg_time32
366     common  accept4                 sys_accept4
367     common  fanotify_init           sys_fanotify_init
368     common  fanotify_mark           sys_fanotify_mark
369     common  prlimit64               sys_prlimit64
370     common  name_to_handle_at       sys_name_to_handle_at
371     common  open_by_handle_at       sys_open_by_handle_at
372     common  clock_adjtime           sys_clock_adjtime32
373     common  syncfs                  sys_syncfs
374     common  sendmmsg                sys_sendmmsg
375     common  setns                   sys_setns
376     common  process_vm_readv        sys_process_vm_readv
377     common  process_vm_writev       sys_process_vm_writev
378     common  kcmp                    sys_kcmp
379     common  finit_module            sys_finit_module
380     common  sched_setattr           sys_sched_setattr
381     common  sched_getattr           sys_sched_getattr
382     common  renameat2               sys_renameat2
383     common  seccomp                 sys_seccomp
384     common  getrandom               sys_getrandom
385     common  memfd_create            sys_memfd_create
386     common  bpf                     sys_bpf
387     common  execveat                sys_execveat
388     common  userfaultfd             sys_userfaultfd
389     common  membarrier              sys_membarrier
390     common  mlock2                  sys_mlock2
391     common  copy_file_range         sys_copy_file_range
392     common  preadv2                 sys_preadv2
393     common  pwritev2                sys_pwritev2
394     common  pkey_mprotect           sys_pkey_mprotect
395     common  pkey_alloc              sys_pkey_alloc
396     common  pkey_free               sys_pkey_free
397     common  statx                   sys_statx
398     common  rseq                    sys_rseq
399     common  io_pgetevents           sys_io_pgetevents_time32
400     common  migrate_pages           sys_migrate_pages
401     common  kexec_file_load         sys_kexec_file_load
# 402 is unused
403     common  clock_gettime64                 sys_clock_gettime
404     common  clock_settime64                 sys_clock_settime
405     common  clock_adjtime64                 sys_clock_adjtime
406     common  clock_getres_time64             sys_clock_getres
407     common  clock_nanosleep_time64          sys_clock_nanosleep
408     common  timer_gettime64                 sys_timer_gettime
409     common  timer_settime64                 sys_timer_settime
410     common  timerfd_gettime64               sys_timerfd_gettime
411     common  timerfd_settime64               sys_timerfd_settime
412     common  utimensat_time64                sys_utimensat
413     common  pselect6_time64                 sys_pselect6
414     common  ppoll_time64                    sys_ppoll
416     common  io_pgetevents_time64            sys_io_pgetevents
417     common  recvmmsg_time64                 sys_recvmmsg
418     common  mq_timedsend_time64             sys_mq_timedsend
419     common  mq_timedreceive_time64          sys_mq_timedreceive
420     common  semtimedop_time64               sys_semtimedop
421     common  rt_sigtimedwait_time64          sys_rt_sigtimedwait
422     common  futex_time64                    sys_futex
423     common  sched_rr_get_interval_time64    sys_sched_rr_get_interval
424     common  pidfd_send_signal               sys_pidfd_send_signal
425     common  io_uring_setup                  sys_io_uring_setup
426     common  io_uring_enter                  sys_io_uring_enter
427     common  io_uring_register               sys_io_uring_register
428     common  open_tree                       sys_open_tree
429     common  move_mount                      sys_move_mount
430     common  fsopen                          sys_fsopen
431     common  fsconfig                        sys_fsconfig
432     common  fsmount                         sys_fsmount
433     common  fspick                          sys_fspick
434     common  pidfd_open                      sys_pidfd_open
435     common  clone3                          sys_clone3
436     common  close_range                     sys_close_range
437     common  openat2                         sys_openat2
438     common  pidfd_getfd                     sys_pidfd_getfd
439     common  faccessat2                      sys_faccessat2
440     common  process_madvise                 sys_process_madvise
441     common  epoll_pwait2                    sys_epoll_pwait2
442     common  mount_setattr                   sys_mount_setattr
443     common  quotactl_fd                     sys_quotactl_fd
444     common  landlock_create_ruleset         sys_landlock_create_ruleset
445     common  landlock_add_rule               sys_landlock_add_rule
446     common  landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     common  process_mrelease                sys_process_mrelease
449     common  futex_waitv                     sys_futex_waitv
450     common  set_mempolicy_home_node         sys_set_mempolicy_home_node
451     common  cachestat                       sys_cachestat
452     common  fchmodat2                       sys_fchmodat2
453     common  map_shadow_stack                sys_map_shadow_stack
454     common  futex_wake                      sys_futex_wake
455     common  futex_wait                      sys_futex_wait
456     common  futex_requeue                   sys_futex_requeue
457     common  statmount                       sys_statmount
458     common  listmount                       sys_listmount
459     common  lsm_get_self_attr               sys_lsm_get_self_attr
460     common  lsm_set_self_attr               sys_lsm_set_self_attr
461     common  lsm_list_modules                sys_lsm_list_modules
462     common  mseal                           sys_mseal
"""


# MIPS o32 (backward compatible ABI, present in /lib)
# - arch/mips/kernel/syscalls/syscall_o32.tbl
mips_o32_syscall_tbl = """
# system call numbers and entry vectors for mips
#
# The format is:
# <number> <abi> <name> <entry point> <compat entry point>
#
# The <abi> is always "o32" for this file.
#
0       o32     syscall                         sys_syscall                     sys32_syscall
1       o32     exit                            sys_exit
2       o32     fork                            __sys_fork
3       o32     read                            sys_read
4       o32     write                           sys_write
5       o32     open                            sys_open                        compat_sys_open
6       o32     close                           sys_close
7       o32     waitpid                         sys_waitpid
8       o32     creat                           sys_creat
9       o32     link                            sys_link
10      o32     unlink                          sys_unlink
11      o32     execve                          sys_execve                      compat_sys_execve
12      o32     chdir                           sys_chdir
13      o32     time                            sys_time32
14      o32     mknod                           sys_mknod
15      o32     chmod                           sys_chmod
16      o32     lchown                          sys_lchown
17      o32     break                           sys_ni_syscall
# 18 was sys_stat
18      o32     unused18                        sys_ni_syscall
19      o32     lseek                           sys_lseek                       compat_sys_lseek
20      o32     getpid                          sys_getpid
21      o32     mount                           sys_mount
22      o32     umount                          sys_oldumount
23      o32     setuid                          sys_setuid
24      o32     getuid                          sys_getuid
25      o32     stime                           sys_stime32
26      o32     ptrace                          sys_ptrace                      compat_sys_ptrace
27      o32     alarm                           sys_alarm
# 28 was sys_fstat
28      o32     unused28                        sys_ni_syscall
29      o32     pause                           sys_pause
30      o32     utime                           sys_utime32
31      o32     stty                            sys_ni_syscall
32      o32     gtty                            sys_ni_syscall
33      o32     access                          sys_access
34      o32     nice                            sys_nice
35      o32     ftime                           sys_ni_syscall
36      o32     sync                            sys_sync
37      o32     kill                            sys_kill
38      o32     rename                          sys_rename
39      o32     mkdir                           sys_mkdir
40      o32     rmdir                           sys_rmdir
41      o32     dup                             sys_dup
42      o32     pipe                            sysm_pipe
43      o32     times                           sys_times                       compat_sys_times
44      o32     prof                            sys_ni_syscall
45      o32     brk                             sys_brk
46      o32     setgid                          sys_setgid
47      o32     getgid                          sys_getgid
48      o32     signal                          sys_ni_syscall
49      o32     geteuid                         sys_geteuid
50      o32     getegid                         sys_getegid
51      o32     acct                            sys_acct
52      o32     umount2                         sys_umount
53      o32     lock                            sys_ni_syscall
54      o32     ioctl                           sys_ioctl                       compat_sys_ioctl
55      o32     fcntl                           sys_fcntl                       compat_sys_fcntl
56      o32     mpx                             sys_ni_syscall
57      o32     setpgid                         sys_setpgid
58      o32     ulimit                          sys_ni_syscall
59      o32     unused59                        sys_olduname
60      o32     umask                           sys_umask
61      o32     chroot                          sys_chroot
62      o32     ustat                           sys_ustat                       compat_sys_ustat
63      o32     dup2                            sys_dup2
64      o32     getppid                         sys_getppid
65      o32     getpgrp                         sys_getpgrp
66      o32     setsid                          sys_setsid
67      o32     sigaction                       sys_sigaction                   sys_32_sigaction
68      o32     sgetmask                        sys_sgetmask
69      o32     ssetmask                        sys_ssetmask
70      o32     setreuid                        sys_setreuid
71      o32     setregid                        sys_setregid
72      o32     sigsuspend                      sys_sigsuspend                  sys32_sigsuspend
73      o32     sigpending                      sys_sigpending                  compat_sys_sigpending
74      o32     sethostname                     sys_sethostname
75      o32     setrlimit                       sys_setrlimit                   compat_sys_setrlimit
76      o32     getrlimit                       sys_getrlimit                   compat_sys_getrlimit
77      o32     getrusage                       sys_getrusage                   compat_sys_getrusage
78      o32     gettimeofday                    sys_gettimeofday                compat_sys_gettimeofday
79      o32     settimeofday                    sys_settimeofday                compat_sys_settimeofday
80      o32     getgroups                       sys_getgroups
81      o32     setgroups                       sys_setgroups
# 82 was old_select
82      o32     reserved82                      sys_ni_syscall
83      o32     symlink                         sys_symlink
# 84 was sys_lstat
84      o32     unused84                        sys_ni_syscall
85      o32     readlink                        sys_readlink
86      o32     uselib                          sys_uselib
87      o32     swapon                          sys_swapon
88      o32     reboot                          sys_reboot
89      o32     readdir                         sys_old_readdir                 compat_sys_old_readdir
90      o32     mmap                            sys_mips_mmap
91      o32     munmap                          sys_munmap
92      o32     truncate                        sys_truncate                    compat_sys_truncate
93      o32     ftruncate                       sys_ftruncate                   compat_sys_ftruncate
94      o32     fchmod                          sys_fchmod
95      o32     fchown                          sys_fchown
96      o32     getpriority                     sys_getpriority
97      o32     setpriority                     sys_setpriority
98      o32     profil                          sys_ni_syscall
99      o32     statfs                          sys_statfs                      compat_sys_statfs
100     o32     fstatfs                         sys_fstatfs                     compat_sys_fstatfs
101     o32     ioperm                          sys_ni_syscall
102     o32     socketcall                      sys_socketcall                  compat_sys_socketcall
103     o32     syslog                          sys_syslog
104     o32     setitimer                       sys_setitimer                   compat_sys_setitimer
105     o32     getitimer                       sys_getitimer                   compat_sys_getitimer
106     o32     stat                            sys_newstat                     compat_sys_newstat
107     o32     lstat                           sys_newlstat                    compat_sys_newlstat
108     o32     fstat                           sys_newfstat                    compat_sys_newfstat
109     o32     unused109                       sys_uname
110     o32     iopl                            sys_ni_syscall
111     o32     vhangup                         sys_vhangup
112     o32     idle                            sys_ni_syscall
113     o32     vm86                            sys_ni_syscall
114     o32     wait4                           sys_wait4                       compat_sys_wait4
115     o32     swapoff                         sys_swapoff
116     o32     sysinfo                         sys_sysinfo                     compat_sys_sysinfo
117     o32     ipc                             sys_ipc                         compat_sys_ipc
118     o32     fsync                           sys_fsync
119     o32     sigreturn                       sys_sigreturn                   sys32_sigreturn
120     o32     clone                           __sys_clone
121     o32     setdomainname                   sys_setdomainname
122     o32     uname                           sys_newuname
123     o32     modify_ldt                      sys_ni_syscall
124     o32     adjtimex                        sys_adjtimex_time32
125     o32     mprotect                        sys_mprotect
126     o32     sigprocmask                     sys_sigprocmask                 compat_sys_sigprocmask
127     o32     create_module                   sys_ni_syscall
128     o32     init_module                     sys_init_module
129     o32     delete_module                   sys_delete_module
130     o32     get_kernel_syms                 sys_ni_syscall
131     o32     quotactl                        sys_quotactl
132     o32     getpgid                         sys_getpgid
133     o32     fchdir                          sys_fchdir
134     o32     bdflush                         sys_ni_syscall
135     o32     sysfs                           sys_sysfs
136     o32     personality                     sys_personality                 sys_32_personality
137     o32     afs_syscall                     sys_ni_syscall
138     o32     setfsuid                        sys_setfsuid
139     o32     setfsgid                        sys_setfsgid
140     o32     _llseek                         sys_llseek                      sys_32_llseek
141     o32     getdents                        sys_getdents                    compat_sys_getdents
142     o32     _newselect                      sys_select                      compat_sys_select
143     o32     flock                           sys_flock
144     o32     msync                           sys_msync
145     o32     readv                           sys_readv
146     o32     writev                          sys_writev
147     o32     cacheflush                      sys_cacheflush
148     o32     cachectl                        sys_cachectl
149     o32     sysmips                         __sys_sysmips
150     o32     unused150                       sys_ni_syscall
151     o32     getsid                          sys_getsid
152     o32     fdatasync                       sys_fdatasync
153     o32     _sysctl                         sys_ni_syscall
154     o32     mlock                           sys_mlock
155     o32     munlock                         sys_munlock
156     o32     mlockall                        sys_mlockall
157     o32     munlockall                      sys_munlockall
158     o32     sched_setparam                  sys_sched_setparam
159     o32     sched_getparam                  sys_sched_getparam
160     o32     sched_setscheduler              sys_sched_setscheduler
161     o32     sched_getscheduler              sys_sched_getscheduler
162     o32     sched_yield                     sys_sched_yield
163     o32     sched_get_priority_max          sys_sched_get_priority_max
164     o32     sched_get_priority_min          sys_sched_get_priority_min
165     o32     sched_rr_get_interval           sys_sched_rr_get_interval_time32
166     o32     nanosleep                       sys_nanosleep_time32
167     o32     mremap                          sys_mremap
168     o32     accept                          sys_accept
169     o32     bind                            sys_bind
170     o32     connect                         sys_connect
171     o32     getpeername                     sys_getpeername
172     o32     getsockname                     sys_getsockname
173     o32     getsockopt                      sys_getsockopt                  sys_getsockopt
174     o32     listen                          sys_listen
175     o32     recv                            sys_recv                        compat_sys_recv
176     o32     recvfrom                        sys_recvfrom                    compat_sys_recvfrom
177     o32     recvmsg                         sys_recvmsg                     compat_sys_recvmsg
178     o32     send                            sys_send
179     o32     sendmsg                         sys_sendmsg                     compat_sys_sendmsg
180     o32     sendto                          sys_sendto
181     o32     setsockopt                      sys_setsockopt                  sys_setsockopt
182     o32     shutdown                        sys_shutdown
183     o32     socket                          sys_socket
184     o32     socketpair                      sys_socketpair
185     o32     setresuid                       sys_setresuid
186     o32     getresuid                       sys_getresuid
187     o32     query_module                    sys_ni_syscall
188     o32     poll                            sys_poll
189     o32     nfsservctl                      sys_ni_syscall
190     o32     setresgid                       sys_setresgid
191     o32     getresgid                       sys_getresgid
192     o32     prctl                           sys_prctl
193     o32     rt_sigreturn                    sys_rt_sigreturn                sys32_rt_sigreturn
194     o32     rt_sigaction                    sys_rt_sigaction                compat_sys_rt_sigaction
195     o32     rt_sigprocmask                  sys_rt_sigprocmask              compat_sys_rt_sigprocmask
196     o32     rt_sigpending                   sys_rt_sigpending               compat_sys_rt_sigpending
197     o32     rt_sigtimedwait                 sys_rt_sigtimedwait_time32      compat_sys_rt_sigtimedwait_time32
198     o32     rt_sigqueueinfo                 sys_rt_sigqueueinfo             compat_sys_rt_sigqueueinfo
199     o32     rt_sigsuspend                   sys_rt_sigsuspend               compat_sys_rt_sigsuspend
200     o32     pread64                         sys_pread64                     sys_32_pread
201     o32     pwrite64                        sys_pwrite64                    sys_32_pwrite
202     o32     chown                           sys_chown
203     o32     getcwd                          sys_getcwd
204     o32     capget                          sys_capget
205     o32     capset                          sys_capset
206     o32     sigaltstack                     sys_sigaltstack                 compat_sys_sigaltstack
207     o32     sendfile                        sys_sendfile                    compat_sys_sendfile
208     o32     getpmsg                         sys_ni_syscall
209     o32     putpmsg                         sys_ni_syscall
210     o32     mmap2                           sys_mips_mmap2
211     o32     truncate64                      sys_truncate64                  sys_32_truncate64
212     o32     ftruncate64                     sys_ftruncate64                 sys_32_ftruncate64
213     o32     stat64                          sys_stat64                      sys_newstat
214     o32     lstat64                         sys_lstat64                     sys_newlstat
215     o32     fstat64                         sys_fstat64                     sys_newfstat
216     o32     pivot_root                      sys_pivot_root
217     o32     mincore                         sys_mincore
218     o32     madvise                         sys_madvise
219     o32     getdents64                      sys_getdents64
220     o32     fcntl64                         sys_fcntl64                     compat_sys_fcntl64
221     o32     reserved221                     sys_ni_syscall
222     o32     gettid                          sys_gettid
223     o32     readahead                       sys_readahead                   sys32_readahead
224     o32     setxattr                        sys_setxattr
225     o32     lsetxattr                       sys_lsetxattr
226     o32     fsetxattr                       sys_fsetxattr
227     o32     getxattr                        sys_getxattr
228     o32     lgetxattr                       sys_lgetxattr
229     o32     fgetxattr                       sys_fgetxattr
230     o32     listxattr                       sys_listxattr
231     o32     llistxattr                      sys_llistxattr
232     o32     flistxattr                      sys_flistxattr
233     o32     removexattr                     sys_removexattr
234     o32     lremovexattr                    sys_lremovexattr
235     o32     fremovexattr                    sys_fremovexattr
236     o32     tkill                           sys_tkill
237     o32     sendfile64                      sys_sendfile64
238     o32     futex                           sys_futex_time32
239     o32     sched_setaffinity               sys_sched_setaffinity           compat_sys_sched_setaffinity
240     o32     sched_getaffinity               sys_sched_getaffinity           compat_sys_sched_getaffinity
241     o32     io_setup                        sys_io_setup                    compat_sys_io_setup
242     o32     io_destroy                      sys_io_destroy
243     o32     io_getevents                    sys_io_getevents_time32
244     o32     io_submit                       sys_io_submit                   compat_sys_io_submit
245     o32     io_cancel                       sys_io_cancel
246     o32     exit_group                      sys_exit_group
247     o32     lookup_dcookie                  sys_ni_syscall
248     o32     epoll_create                    sys_epoll_create
249     o32     epoll_ctl                       sys_epoll_ctl
250     o32     epoll_wait                      sys_epoll_wait
251     o32     remap_file_pages                sys_remap_file_pages
252     o32     set_tid_address                 sys_set_tid_address
253     o32     restart_syscall                 sys_restart_syscall
254     o32     fadvise64                       sys_fadvise64_64                sys32_fadvise64_64
255     o32     statfs64                        sys_statfs64                    compat_sys_statfs64
256     o32     fstatfs64                       sys_fstatfs64                   compat_sys_fstatfs64
257     o32     timer_create                    sys_timer_create                compat_sys_timer_create
258     o32     timer_settime                   sys_timer_settime32
259     o32     timer_gettime                   sys_timer_gettime32
260     o32     timer_getoverrun                sys_timer_getoverrun
261     o32     timer_delete                    sys_timer_delete
262     o32     clock_settime                   sys_clock_settime32
263     o32     clock_gettime                   sys_clock_gettime32
264     o32     clock_getres                    sys_clock_getres_time32
265     o32     clock_nanosleep                 sys_clock_nanosleep_time32
266     o32     tgkill                          sys_tgkill
267     o32     utimes                          sys_utimes_time32
268     o32     mbind                           sys_mbind
269     o32     get_mempolicy                   sys_get_mempolicy
270     o32     set_mempolicy                   sys_set_mempolicy
271     o32     mq_open                         sys_mq_open                     compat_sys_mq_open
272     o32     mq_unlink                       sys_mq_unlink
273     o32     mq_timedsend                    sys_mq_timedsend_time32
274     o32     mq_timedreceive                 sys_mq_timedreceive_time32
275     o32     mq_notify                       sys_mq_notify                   compat_sys_mq_notify
276     o32     mq_getsetattr                   sys_mq_getsetattr               compat_sys_mq_getsetattr
277     o32     vserver                         sys_ni_syscall
278     o32     waitid                          sys_waitid                      compat_sys_waitid
# 279 was sys_setaltroot
280     o32     add_key                         sys_add_key
281     o32     request_key                     sys_request_key
282     o32     keyctl                          sys_keyctl                      compat_sys_keyctl
283     o32     set_thread_area                 sys_set_thread_area
284     o32     inotify_init                    sys_inotify_init
285     o32     inotify_add_watch               sys_inotify_add_watch
286     o32     inotify_rm_watch                sys_inotify_rm_watch
287     o32     migrate_pages                   sys_migrate_pages
288     o32     openat                          sys_openat                      compat_sys_openat
289     o32     mkdirat                         sys_mkdirat
290     o32     mknodat                         sys_mknodat
291     o32     fchownat                        sys_fchownat
292     o32     futimesat                       sys_futimesat_time32
293     o32     fstatat64                       sys_fstatat64                   sys_newfstatat
294     o32     unlinkat                        sys_unlinkat
295     o32     renameat                        sys_renameat
296     o32     linkat                          sys_linkat
297     o32     symlinkat                       sys_symlinkat
298     o32     readlinkat                      sys_readlinkat
299     o32     fchmodat                        sys_fchmodat
300     o32     faccessat                       sys_faccessat
301     o32     pselect6                        sys_pselect6_time32             compat_sys_pselect6_time32
302     o32     ppoll                           sys_ppoll_time32                compat_sys_ppoll_time32
303     o32     unshare                         sys_unshare
304     o32     splice                          sys_splice
305     o32     sync_file_range                 sys_sync_file_range             sys32_sync_file_range
306     o32     tee                             sys_tee
307     o32     vmsplice                        sys_vmsplice
308     o32     move_pages                      sys_move_pages
309     o32     set_robust_list                 sys_set_robust_list             compat_sys_set_robust_list
310     o32     get_robust_list                 sys_get_robust_list             compat_sys_get_robust_list
311     o32     kexec_load                      sys_kexec_load                  compat_sys_kexec_load
312     o32     getcpu                          sys_getcpu
313     o32     epoll_pwait                     sys_epoll_pwait                 compat_sys_epoll_pwait
314     o32     ioprio_set                      sys_ioprio_set
315     o32     ioprio_get                      sys_ioprio_get
316     o32     utimensat                       sys_utimensat_time32
317     o32     signalfd                        sys_signalfd                    compat_sys_signalfd
318     o32     timerfd                         sys_ni_syscall
319     o32     eventfd                         sys_eventfd
320     o32     fallocate                       sys_fallocate                   sys32_fallocate
321     o32     timerfd_create                  sys_timerfd_create
322     o32     timerfd_gettime                 sys_timerfd_gettime32
323     o32     timerfd_settime                 sys_timerfd_settime32
324     o32     signalfd4                       sys_signalfd4                   compat_sys_signalfd4
325     o32     eventfd2                        sys_eventfd2
326     o32     epoll_create1                   sys_epoll_create1
327     o32     dup3                            sys_dup3
328     o32     pipe2                           sys_pipe2
329     o32     inotify_init1                   sys_inotify_init1
330     o32     preadv                          sys_preadv                      compat_sys_preadv
331     o32     pwritev                         sys_pwritev                     compat_sys_pwritev
332     o32     rt_tgsigqueueinfo               sys_rt_tgsigqueueinfo           compat_sys_rt_tgsigqueueinfo
333     o32     perf_event_open                 sys_perf_event_open
334     o32     accept4                         sys_accept4
335     o32     recvmmsg                        sys_recvmmsg_time32             compat_sys_recvmmsg_time32
336     o32     fanotify_init                   sys_fanotify_init
337     o32     fanotify_mark                   sys_fanotify_mark               compat_sys_fanotify_mark
338     o32     prlimit64                       sys_prlimit64
339     o32     name_to_handle_at               sys_name_to_handle_at
340     o32     open_by_handle_at               sys_open_by_handle_at           compat_sys_open_by_handle_at
341     o32     clock_adjtime                   sys_clock_adjtime32
342     o32     syncfs                          sys_syncfs
343     o32     sendmmsg                        sys_sendmmsg                    compat_sys_sendmmsg
344     o32     setns                           sys_setns
345     o32     process_vm_readv                sys_process_vm_readv
346     o32     process_vm_writev               sys_process_vm_writev
347     o32     kcmp                            sys_kcmp
348     o32     finit_module                    sys_finit_module
349     o32     sched_setattr                   sys_sched_setattr
350     o32     sched_getattr                   sys_sched_getattr
351     o32     renameat2                       sys_renameat2
352     o32     seccomp                         sys_seccomp
353     o32     getrandom                       sys_getrandom
354     o32     memfd_create                    sys_memfd_create
355     o32     bpf                             sys_bpf
356     o32     execveat                        sys_execveat                    compat_sys_execveat
357     o32     userfaultfd                     sys_userfaultfd
358     o32     membarrier                      sys_membarrier
359     o32     mlock2                          sys_mlock2
360     o32     copy_file_range                 sys_copy_file_range
361     o32     preadv2                         sys_preadv2                     compat_sys_preadv2
362     o32     pwritev2                        sys_pwritev2                    compat_sys_pwritev2
363     o32     pkey_mprotect                   sys_pkey_mprotect
364     o32     pkey_alloc                      sys_pkey_alloc
365     o32     pkey_free                       sys_pkey_free
366     o32     statx                           sys_statx
367     o32     rseq                            sys_rseq
368     o32     io_pgetevents                   sys_io_pgetevents_time32        compat_sys_io_pgetevents
# room for arch specific calls
393     o32     semget                          sys_semget
394     o32     semctl                          sys_semctl                      compat_sys_semctl
395     o32     shmget                          sys_shmget
396     o32     shmctl                          sys_shmctl                      compat_sys_shmctl
397     o32     shmat                           sys_shmat                       compat_sys_shmat
398     o32     shmdt                           sys_shmdt
399     o32     msgget                          sys_msgget
400     o32     msgsnd                          sys_msgsnd                      compat_sys_msgsnd
401     o32     msgrcv                          sys_msgrcv                      compat_sys_msgrcv
402     o32     msgctl                          sys_msgctl                      compat_sys_msgctl
403     o32     clock_gettime64                 sys_clock_gettime               sys_clock_gettime
404     o32     clock_settime64                 sys_clock_settime               sys_clock_settime
405     o32     clock_adjtime64                 sys_clock_adjtime               sys_clock_adjtime
406     o32     clock_getres_time64             sys_clock_getres                sys_clock_getres
407     o32     clock_nanosleep_time64          sys_clock_nanosleep             sys_clock_nanosleep
408     o32     timer_gettime64                 sys_timer_gettime               sys_timer_gettime
409     o32     timer_settime64                 sys_timer_settime               sys_timer_settime
410     o32     timerfd_gettime64               sys_timerfd_gettime             sys_timerfd_gettime
411     o32     timerfd_settime64               sys_timerfd_settime             sys_timerfd_settime
412     o32     utimensat_time64                sys_utimensat                   sys_utimensat
413     o32     pselect6_time64                 sys_pselect6                    compat_sys_pselect6_time64
414     o32     ppoll_time64                    sys_ppoll                       compat_sys_ppoll_time64
416     o32     io_pgetevents_time64            sys_io_pgetevents               compat_sys_io_pgetevents_time64
417     o32     recvmmsg_time64                 sys_recvmmsg                    compat_sys_recvmmsg_time64
418     o32     mq_timedsend_time64             sys_mq_timedsend                sys_mq_timedsend
419     o32     mq_timedreceive_time64          sys_mq_timedreceive             sys_mq_timedreceive
420     o32     semtimedop_time64               sys_semtimedop                  sys_semtimedop
421     o32     rt_sigtimedwait_time64          sys_rt_sigtimedwait             compat_sys_rt_sigtimedwait_time64
422     o32     futex_time64                    sys_futex                       sys_futex
423     o32     sched_rr_get_interval_time64    sys_sched_rr_get_interval       sys_sched_rr_get_interval
424     o32     pidfd_send_signal               sys_pidfd_send_signal
425     o32     io_uring_setup                  sys_io_uring_setup
426     o32     io_uring_enter                  sys_io_uring_enter
427     o32     io_uring_register               sys_io_uring_register
428     o32     open_tree                       sys_open_tree
429     o32     move_mount                      sys_move_mount
430     o32     fsopen                          sys_fsopen
431     o32     fsconfig                        sys_fsconfig
432     o32     fsmount                         sys_fsmount
433     o32     fspick                          sys_fspick
434     o32     pidfd_open                      sys_pidfd_open
435     o32     clone3                          __sys_clone3
436     o32     close_range                     sys_close_range
437     o32     openat2                         sys_openat2
438     o32     pidfd_getfd                     sys_pidfd_getfd
439     o32     faccessat2                      sys_faccessat2
440     o32     process_madvise                 sys_process_madvise
441     o32     epoll_pwait2                    sys_epoll_pwait2                compat_sys_epoll_pwait2
442     o32     mount_setattr                   sys_mount_setattr
443     o32     quotactl_fd                     sys_quotactl_fd
444     o32     landlock_create_ruleset         sys_landlock_create_ruleset
445     o32     landlock_add_rule               sys_landlock_add_rule
446     o32     landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     o32     process_mrelease                sys_process_mrelease
449     o32     futex_waitv                     sys_futex_waitv
450     o32     set_mempolicy_home_node         sys_set_mempolicy_home_node
451     o32     cachestat                       sys_cachestat
452     o32     fchmodat2                       sys_fchmodat2
453     o32     map_shadow_stack                sys_map_shadow_stack
454     o32     futex_wake                      sys_futex_wake
455     o32     futex_wait                      sys_futex_wait
456     o32     futex_requeue                   sys_futex_requeue
457     o32     statmount                       sys_statmount
458     o32     listmount                       sys_listmount
459     o32     lsm_get_self_attr               sys_lsm_get_self_attr
460     o32     lsm_set_self_attr               sys_lsm_set_self_attr
461     o32     lsm_list_modules                sys_lsm_list_modules
462     o32     mseal                           sys_mseal
"""


# MIPS n32 (default ABI, present in /lib32)
# - arch/mips/kernel/syscalls/syscall_n32.tbl
mips_n32_syscall_tbl = """
# system call numbers and entry vectors for mips
#
# The format is:
# <number> <abi> <name> <entry point> <compat entry point>
#
# The <abi> is always "n32" for this file.
#
0       n32     read                            sys_read
1       n32     write                           sys_write
2       n32     open                            sys_open
3       n32     close                           sys_close
4       n32     stat                            sys_newstat
5       n32     fstat                           sys_newfstat
6       n32     lstat                           sys_newlstat
7       n32     poll                            sys_poll
8       n32     lseek                           sys_lseek
9       n32     mmap                            sys_mips_mmap
10      n32     mprotect                        sys_mprotect
11      n32     munmap                          sys_munmap
12      n32     brk                             sys_brk
13      n32     rt_sigaction                    compat_sys_rt_sigaction
14      n32     rt_sigprocmask                  compat_sys_rt_sigprocmask
15      n32     ioctl                           compat_sys_ioctl
16      n32     pread64                         sys_pread64
17      n32     pwrite64                        sys_pwrite64
18      n32     readv                           sys_readv
19      n32     writev                          sys_writev
20      n32     access                          sys_access
21      n32     pipe                            sysm_pipe
22      n32     _newselect                      compat_sys_select
23      n32     sched_yield                     sys_sched_yield
24      n32     mremap                          sys_mremap
25      n32     msync                           sys_msync
26      n32     mincore                         sys_mincore
27      n32     madvise                         sys_madvise
28      n32     shmget                          sys_shmget
29      n32     shmat                           sys_shmat
30      n32     shmctl                          compat_sys_old_shmctl
31      n32     dup                             sys_dup
32      n32     dup2                            sys_dup2
33      n32     pause                           sys_pause
34      n32     nanosleep                       sys_nanosleep_time32
35      n32     getitimer                       compat_sys_getitimer
36      n32     setitimer                       compat_sys_setitimer
37      n32     alarm                           sys_alarm
38      n32     getpid                          sys_getpid
39      n32     sendfile                        compat_sys_sendfile
40      n32     socket                          sys_socket
41      n32     connect                         sys_connect
42      n32     accept                          sys_accept
43      n32     sendto                          sys_sendto
44      n32     recvfrom                        compat_sys_recvfrom
45      n32     sendmsg                         compat_sys_sendmsg
46      n32     recvmsg                         compat_sys_recvmsg
47      n32     shutdown                        sys_shutdown
48      n32     bind                            sys_bind
49      n32     listen                          sys_listen
50      n32     getsockname                     sys_getsockname
51      n32     getpeername                     sys_getpeername
52      n32     socketpair                      sys_socketpair
53      n32     setsockopt                      sys_setsockopt
54      n32     getsockopt                      sys_getsockopt
55      n32     clone                           __sys_clone
56      n32     fork                            __sys_fork
57      n32     execve                          compat_sys_execve
58      n32     exit                            sys_exit
59      n32     wait4                           compat_sys_wait4
60      n32     kill                            sys_kill
61      n32     uname                           sys_newuname
62      n32     semget                          sys_semget
63      n32     semop                           sys_semop
64      n32     semctl                          compat_sys_old_semctl
65      n32     shmdt                           sys_shmdt
66      n32     msgget                          sys_msgget
67      n32     msgsnd                          compat_sys_msgsnd
68      n32     msgrcv                          compat_sys_msgrcv
69      n32     msgctl                          compat_sys_old_msgctl
70      n32     fcntl                           compat_sys_fcntl
71      n32     flock                           sys_flock
72      n32     fsync                           sys_fsync
73      n32     fdatasync                       sys_fdatasync
74      n32     truncate                        sys_truncate
75      n32     ftruncate                       sys_ftruncate
76      n32     getdents                        compat_sys_getdents
77      n32     getcwd                          sys_getcwd
78      n32     chdir                           sys_chdir
79      n32     fchdir                          sys_fchdir
80      n32     rename                          sys_rename
81      n32     mkdir                           sys_mkdir
82      n32     rmdir                           sys_rmdir
83      n32     creat                           sys_creat
84      n32     link                            sys_link
85      n32     unlink                          sys_unlink
86      n32     symlink                         sys_symlink
87      n32     readlink                        sys_readlink
88      n32     chmod                           sys_chmod
89      n32     fchmod                          sys_fchmod
90      n32     chown                           sys_chown
91      n32     fchown                          sys_fchown
92      n32     lchown                          sys_lchown
93      n32     umask                           sys_umask
94      n32     gettimeofday                    compat_sys_gettimeofday
95      n32     getrlimit                       compat_sys_getrlimit
96      n32     getrusage                       compat_sys_getrusage
97      n32     sysinfo                         compat_sys_sysinfo
98      n32     times                           compat_sys_times
99      n32     ptrace                          compat_sys_ptrace
100     n32     getuid                          sys_getuid
101     n32     syslog                          sys_syslog
102     n32     getgid                          sys_getgid
103     n32     setuid                          sys_setuid
104     n32     setgid                          sys_setgid
105     n32     geteuid                         sys_geteuid
106     n32     getegid                         sys_getegid
107     n32     setpgid                         sys_setpgid
108     n32     getppid                         sys_getppid
109     n32     getpgrp                         sys_getpgrp
110     n32     setsid                          sys_setsid
111     n32     setreuid                        sys_setreuid
112     n32     setregid                        sys_setregid
113     n32     getgroups                       sys_getgroups
114     n32     setgroups                       sys_setgroups
115     n32     setresuid                       sys_setresuid
116     n32     getresuid                       sys_getresuid
117     n32     setresgid                       sys_setresgid
118     n32     getresgid                       sys_getresgid
119     n32     getpgid                         sys_getpgid
120     n32     setfsuid                        sys_setfsuid
121     n32     setfsgid                        sys_setfsgid
122     n32     getsid                          sys_getsid
123     n32     capget                          sys_capget
124     n32     capset                          sys_capset
125     n32     rt_sigpending                   compat_sys_rt_sigpending
126     n32     rt_sigtimedwait                 compat_sys_rt_sigtimedwait_time32
127     n32     rt_sigqueueinfo                 compat_sys_rt_sigqueueinfo
128     n32     rt_sigsuspend                   compat_sys_rt_sigsuspend
129     n32     sigaltstack                     compat_sys_sigaltstack
130     n32     utime                           sys_utime32
131     n32     mknod                           sys_mknod
132     n32     personality                     sys_32_personality
133     n32     ustat                           compat_sys_ustat
134     n32     statfs                          compat_sys_statfs
135     n32     fstatfs                         compat_sys_fstatfs
136     n32     sysfs                           sys_sysfs
137     n32     getpriority                     sys_getpriority
138     n32     setpriority                     sys_setpriority
139     n32     sched_setparam                  sys_sched_setparam
140     n32     sched_getparam                  sys_sched_getparam
141     n32     sched_setscheduler              sys_sched_setscheduler
142     n32     sched_getscheduler              sys_sched_getscheduler
143     n32     sched_get_priority_max          sys_sched_get_priority_max
144     n32     sched_get_priority_min          sys_sched_get_priority_min
145     n32     sched_rr_get_interval           sys_sched_rr_get_interval_time32
146     n32     mlock                           sys_mlock
147     n32     munlock                         sys_munlock
148     n32     mlockall                        sys_mlockall
149     n32     munlockall                      sys_munlockall
150     n32     vhangup                         sys_vhangup
151     n32     pivot_root                      sys_pivot_root
152     n32     _sysctl                         sys_ni_syscall
153     n32     prctl                           sys_prctl
154     n32     adjtimex                        sys_adjtimex_time32
155     n32     setrlimit                       compat_sys_setrlimit
156     n32     chroot                          sys_chroot
157     n32     sync                            sys_sync
158     n32     acct                            sys_acct
159     n32     settimeofday                    compat_sys_settimeofday
160     n32     mount                           sys_mount
161     n32     umount2                         sys_umount
162     n32     swapon                          sys_swapon
163     n32     swapoff                         sys_swapoff
164     n32     reboot                          sys_reboot
165     n32     sethostname                     sys_sethostname
166     n32     setdomainname                   sys_setdomainname
167     n32     create_module                   sys_ni_syscall
168     n32     init_module                     sys_init_module
169     n32     delete_module                   sys_delete_module
170     n32     get_kernel_syms                 sys_ni_syscall
171     n32     query_module                    sys_ni_syscall
172     n32     quotactl                        sys_quotactl
173     n32     nfsservctl                      sys_ni_syscall
174     n32     getpmsg                         sys_ni_syscall
175     n32     putpmsg                         sys_ni_syscall
176     n32     afs_syscall                     sys_ni_syscall
# 177 reserved for security
177     n32     reserved177                     sys_ni_syscall
178     n32     gettid                          sys_gettid
179     n32     readahead                       sys_readahead
180     n32     setxattr                        sys_setxattr
181     n32     lsetxattr                       sys_lsetxattr
182     n32     fsetxattr                       sys_fsetxattr
183     n32     getxattr                        sys_getxattr
184     n32     lgetxattr                       sys_lgetxattr
185     n32     fgetxattr                       sys_fgetxattr
186     n32     listxattr                       sys_listxattr
187     n32     llistxattr                      sys_llistxattr
188     n32     flistxattr                      sys_flistxattr
189     n32     removexattr                     sys_removexattr
190     n32     lremovexattr                    sys_lremovexattr
191     n32     fremovexattr                    sys_fremovexattr
192     n32     tkill                           sys_tkill
193     n32     reserved193                     sys_ni_syscall
194     n32     futex                           sys_futex_time32
195     n32     sched_setaffinity               compat_sys_sched_setaffinity
196     n32     sched_getaffinity               compat_sys_sched_getaffinity
197     n32     cacheflush                      sys_cacheflush
198     n32     cachectl                        sys_cachectl
199     n32     sysmips                         __sys_sysmips
200     n32     io_setup                        compat_sys_io_setup
201     n32     io_destroy                      sys_io_destroy
202     n32     io_getevents                    sys_io_getevents_time32
203     n32     io_submit                       compat_sys_io_submit
204     n32     io_cancel                       sys_io_cancel
205     n32     exit_group                      sys_exit_group
206     n32     lookup_dcookie                  sys_ni_syscall
207     n32     epoll_create                    sys_epoll_create
208     n32     epoll_ctl                       sys_epoll_ctl
209     n32     epoll_wait                      sys_epoll_wait
210     n32     remap_file_pages                sys_remap_file_pages
211     n32     rt_sigreturn                    sysn32_rt_sigreturn
212     n32     fcntl64                         compat_sys_fcntl64
213     n32     set_tid_address                 sys_set_tid_address
214     n32     restart_syscall                 sys_restart_syscall
215     n32     semtimedop                      sys_semtimedop_time32
216     n32     fadvise64                       sys_fadvise64_64
217     n32     statfs64                        compat_sys_statfs64
218     n32     fstatfs64                       compat_sys_fstatfs64
219     n32     sendfile64                      sys_sendfile64
220     n32     timer_create                    compat_sys_timer_create
221     n32     timer_settime                   sys_timer_settime32
222     n32     timer_gettime                   sys_timer_gettime32
223     n32     timer_getoverrun                sys_timer_getoverrun
224     n32     timer_delete                    sys_timer_delete
225     n32     clock_settime                   sys_clock_settime32
226     n32     clock_gettime                   sys_clock_gettime32
227     n32     clock_getres                    sys_clock_getres_time32
228     n32     clock_nanosleep                 sys_clock_nanosleep_time32
229     n32     tgkill                          sys_tgkill
230     n32     utimes                          sys_utimes_time32
231     n32     mbind                           sys_mbind
232     n32     get_mempolicy                   sys_get_mempolicy
233     n32     set_mempolicy                   sys_set_mempolicy
234     n32     mq_open                         compat_sys_mq_open
235     n32     mq_unlink                       sys_mq_unlink
236     n32     mq_timedsend                    sys_mq_timedsend_time32
237     n32     mq_timedreceive                 sys_mq_timedreceive_time32
238     n32     mq_notify                       compat_sys_mq_notify
239     n32     mq_getsetattr                   compat_sys_mq_getsetattr
240     n32     vserver                         sys_ni_syscall
241     n32     waitid                          compat_sys_waitid
# 242 was sys_setaltroot
243     n32     add_key                         sys_add_key
244     n32     request_key                     sys_request_key
245     n32     keyctl                          compat_sys_keyctl
246     n32     set_thread_area                 sys_set_thread_area
247     n32     inotify_init                    sys_inotify_init
248     n32     inotify_add_watch               sys_inotify_add_watch
249     n32     inotify_rm_watch                sys_inotify_rm_watch
250     n32     migrate_pages                   sys_migrate_pages
251     n32     openat                          sys_openat
252     n32     mkdirat                         sys_mkdirat
253     n32     mknodat                         sys_mknodat
254     n32     fchownat                        sys_fchownat
255     n32     futimesat                       sys_futimesat_time32
256     n32     newfstatat                      sys_newfstatat
257     n32     unlinkat                        sys_unlinkat
258     n32     renameat                        sys_renameat
259     n32     linkat                          sys_linkat
260     n32     symlinkat                       sys_symlinkat
261     n32     readlinkat                      sys_readlinkat
262     n32     fchmodat                        sys_fchmodat
263     n32     faccessat                       sys_faccessat
264     n32     pselect6                        compat_sys_pselect6_time32
265     n32     ppoll                           compat_sys_ppoll_time32
266     n32     unshare                         sys_unshare
267     n32     splice                          sys_splice
268     n32     sync_file_range                 sys_sync_file_range
269     n32     tee                             sys_tee
270     n32     vmsplice                        sys_vmsplice
271     n32     move_pages                      sys_move_pages
272     n32     set_robust_list                 compat_sys_set_robust_list
273     n32     get_robust_list                 compat_sys_get_robust_list
274     n32     kexec_load                      compat_sys_kexec_load
275     n32     getcpu                          sys_getcpu
276     n32     epoll_pwait                     compat_sys_epoll_pwait
277     n32     ioprio_set                      sys_ioprio_set
278     n32     ioprio_get                      sys_ioprio_get
279     n32     utimensat                       sys_utimensat_time32
280     n32     signalfd                        compat_sys_signalfd
281     n32     timerfd                         sys_ni_syscall
282     n32     eventfd                         sys_eventfd
283     n32     fallocate                       sys_fallocate
284     n32     timerfd_create                  sys_timerfd_create
285     n32     timerfd_gettime                 sys_timerfd_gettime32
286     n32     timerfd_settime                 sys_timerfd_settime32
287     n32     signalfd4                       compat_sys_signalfd4
288     n32     eventfd2                        sys_eventfd2
289     n32     epoll_create1                   sys_epoll_create1
290     n32     dup3                            sys_dup3
291     n32     pipe2                           sys_pipe2
292     n32     inotify_init1                   sys_inotify_init1
293     n32     preadv                          compat_sys_preadv
294     n32     pwritev                         compat_sys_pwritev
295     n32     rt_tgsigqueueinfo               compat_sys_rt_tgsigqueueinfo
296     n32     perf_event_open                 sys_perf_event_open
297     n32     accept4                         sys_accept4
298     n32     recvmmsg                        compat_sys_recvmmsg_time32
299     n32     getdents64                      sys_getdents64
300     n32     fanotify_init                   sys_fanotify_init
301     n32     fanotify_mark                   sys_fanotify_mark
302     n32     prlimit64                       sys_prlimit64
303     n32     name_to_handle_at               sys_name_to_handle_at
304     n32     open_by_handle_at               sys_open_by_handle_at
305     n32     clock_adjtime                   sys_clock_adjtime32
306     n32     syncfs                          sys_syncfs
307     n32     sendmmsg                        compat_sys_sendmmsg
308     n32     setns                           sys_setns
309     n32     process_vm_readv                sys_process_vm_readv
310     n32     process_vm_writev               sys_process_vm_writev
311     n32     kcmp                            sys_kcmp
312     n32     finit_module                    sys_finit_module
313     n32     sched_setattr                   sys_sched_setattr
314     n32     sched_getattr                   sys_sched_getattr
315     n32     renameat2                       sys_renameat2
316     n32     seccomp                         sys_seccomp
317     n32     getrandom                       sys_getrandom
318     n32     memfd_create                    sys_memfd_create
319     n32     bpf                             sys_bpf
320     n32     execveat                        compat_sys_execveat
321     n32     userfaultfd                     sys_userfaultfd
322     n32     membarrier                      sys_membarrier
323     n32     mlock2                          sys_mlock2
324     n32     copy_file_range                 sys_copy_file_range
325     n32     preadv2                         compat_sys_preadv2
326     n32     pwritev2                        compat_sys_pwritev2
327     n32     pkey_mprotect                   sys_pkey_mprotect
328     n32     pkey_alloc                      sys_pkey_alloc
329     n32     pkey_free                       sys_pkey_free
330     n32     statx                           sys_statx
331     n32     rseq                            sys_rseq
332     n32     io_pgetevents                   compat_sys_io_pgetevents
# 333 through 402 are unassigned to sync up with generic numbers
403     n32     clock_gettime64                 sys_clock_gettime
404     n32     clock_settime64                 sys_clock_settime
405     n32     clock_adjtime64                 sys_clock_adjtime
406     n32     clock_getres_time64             sys_clock_getres
407     n32     clock_nanosleep_time64          sys_clock_nanosleep
408     n32     timer_gettime64                 sys_timer_gettime
409     n32     timer_settime64                 sys_timer_settime
410     n32     timerfd_gettime64               sys_timerfd_gettime
411     n32     timerfd_settime64               sys_timerfd_settime
412     n32     utimensat_time64                sys_utimensat
413     n32     pselect6_time64                 compat_sys_pselect6_time64
414     n32     ppoll_time64                    compat_sys_ppoll_time64
416     n32     io_pgetevents_time64            compat_sys_io_pgetevents_time64
417     n32     recvmmsg_time64                 compat_sys_recvmmsg_time64
418     n32     mq_timedsend_time64             sys_mq_timedsend
419     n32     mq_timedreceive_time64          sys_mq_timedreceive
420     n32     semtimedop_time64               sys_semtimedop
421     n32     rt_sigtimedwait_time64          compat_sys_rt_sigtimedwait_time64
422     n32     futex_time64                    sys_futex
423     n32     sched_rr_get_interval_time64    sys_sched_rr_get_interval
424     n32     pidfd_send_signal               sys_pidfd_send_signal
425     n32     io_uring_setup                  sys_io_uring_setup
426     n32     io_uring_enter                  sys_io_uring_enter
427     n32     io_uring_register               sys_io_uring_register
428     n32     open_tree                       sys_open_tree
429     n32     move_mount                      sys_move_mount
430     n32     fsopen                          sys_fsopen
431     n32     fsconfig                        sys_fsconfig
432     n32     fsmount                         sys_fsmount
433     n32     fspick                          sys_fspick
434     n32     pidfd_open                      sys_pidfd_open
435     n32     clone3                          __sys_clone3
436     n32     close_range                     sys_close_range
437     n32     openat2                         sys_openat2
438     n32     pidfd_getfd                     sys_pidfd_getfd
439     n32     faccessat2                      sys_faccessat2
440     n32     process_madvise                 sys_process_madvise
441     n32     epoll_pwait2                    compat_sys_epoll_pwait2
442     n32     mount_setattr                   sys_mount_setattr
443     n32     quotactl_fd                     sys_quotactl_fd
444     n32     landlock_create_ruleset         sys_landlock_create_ruleset
445     n32     landlock_add_rule               sys_landlock_add_rule
446     n32     landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     n32     process_mrelease                sys_process_mrelease
449     n32     futex_waitv                     sys_futex_waitv
450     n32     set_mempolicy_home_node         sys_set_mempolicy_home_node
451     n32     cachestat                       sys_cachestat
452     n32     fchmodat2                       sys_fchmodat2
453     n32     map_shadow_stack                sys_map_shadow_stack
454     n32     futex_wake                      sys_futex_wake
455     n32     futex_wait                      sys_futex_wait
456     n32     futex_requeue                   sys_futex_requeue
457     n32     statmount                       sys_statmount
458     n32     listmount                       sys_listmount
459     n32     lsm_get_self_attr               sys_lsm_get_self_attr
460     n32     lsm_set_self_attr               sys_lsm_set_self_attr
461     n32     lsm_list_modules                sys_lsm_list_modules
462     n32     mseal                           sys_mseal
"""


# MIPS n64 (for 64-bit ABI, present in /lib64)
# - arch/mips/kernel/syscalls/syscall_n64.tbl
mips_n64_syscall_tbl = """
# system call numbers and entry vectors for mips
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The <abi> is always "n64" for this file.
#
0       n64     read                            sys_read
1       n64     write                           sys_write
2       n64     open                            sys_open
3       n64     close                           sys_close
4       n64     stat                            sys_newstat
5       n64     fstat                           sys_newfstat
6       n64     lstat                           sys_newlstat
7       n64     poll                            sys_poll
8       n64     lseek                           sys_lseek
9       n64     mmap                            sys_mips_mmap
10      n64     mprotect                        sys_mprotect
11      n64     munmap                          sys_munmap
12      n64     brk                             sys_brk
13      n64     rt_sigaction                    sys_rt_sigaction
14      n64     rt_sigprocmask                  sys_rt_sigprocmask
15      n64     ioctl                           sys_ioctl
16      n64     pread64                         sys_pread64
17      n64     pwrite64                        sys_pwrite64
18      n64     readv                           sys_readv
19      n64     writev                          sys_writev
20      n64     access                          sys_access
21      n64     pipe                            sysm_pipe
22      n64     _newselect                      sys_select
23      n64     sched_yield                     sys_sched_yield
24      n64     mremap                          sys_mremap
25      n64     msync                           sys_msync
26      n64     mincore                         sys_mincore
27      n64     madvise                         sys_madvise
28      n64     shmget                          sys_shmget
29      n64     shmat                           sys_shmat
30      n64     shmctl                          sys_old_shmctl
31      n64     dup                             sys_dup
32      n64     dup2                            sys_dup2
33      n64     pause                           sys_pause
34      n64     nanosleep                       sys_nanosleep
35      n64     getitimer                       sys_getitimer
36      n64     setitimer                       sys_setitimer
37      n64     alarm                           sys_alarm
38      n64     getpid                          sys_getpid
39      n64     sendfile                        sys_sendfile64
40      n64     socket                          sys_socket
41      n64     connect                         sys_connect
42      n64     accept                          sys_accept
43      n64     sendto                          sys_sendto
44      n64     recvfrom                        sys_recvfrom
45      n64     sendmsg                         sys_sendmsg
46      n64     recvmsg                         sys_recvmsg
47      n64     shutdown                        sys_shutdown
48      n64     bind                            sys_bind
49      n64     listen                          sys_listen
50      n64     getsockname                     sys_getsockname
51      n64     getpeername                     sys_getpeername
52      n64     socketpair                      sys_socketpair
53      n64     setsockopt                      sys_setsockopt
54      n64     getsockopt                      sys_getsockopt
55      n64     clone                           __sys_clone
56      n64     fork                            __sys_fork
57      n64     execve                          sys_execve
58      n64     exit                            sys_exit
59      n64     wait4                           sys_wait4
60      n64     kill                            sys_kill
61      n64     uname                           sys_newuname
62      n64     semget                          sys_semget
63      n64     semop                           sys_semop
64      n64     semctl                          sys_old_semctl
65      n64     shmdt                           sys_shmdt
66      n64     msgget                          sys_msgget
67      n64     msgsnd                          sys_msgsnd
68      n64     msgrcv                          sys_msgrcv
69      n64     msgctl                          sys_old_msgctl
70      n64     fcntl                           sys_fcntl
71      n64     flock                           sys_flock
72      n64     fsync                           sys_fsync
73      n64     fdatasync                       sys_fdatasync
74      n64     truncate                        sys_truncate
75      n64     ftruncate                       sys_ftruncate
76      n64     getdents                        sys_getdents
77      n64     getcwd                          sys_getcwd
78      n64     chdir                           sys_chdir
79      n64     fchdir                          sys_fchdir
80      n64     rename                          sys_rename
81      n64     mkdir                           sys_mkdir
82      n64     rmdir                           sys_rmdir
83      n64     creat                           sys_creat
84      n64     link                            sys_link
85      n64     unlink                          sys_unlink
86      n64     symlink                         sys_symlink
87      n64     readlink                        sys_readlink
88      n64     chmod                           sys_chmod
89      n64     fchmod                          sys_fchmod
90      n64     chown                           sys_chown
91      n64     fchown                          sys_fchown
92      n64     lchown                          sys_lchown
93      n64     umask                           sys_umask
94      n64     gettimeofday                    sys_gettimeofday
95      n64     getrlimit                       sys_getrlimit
96      n64     getrusage                       sys_getrusage
97      n64     sysinfo                         sys_sysinfo
98      n64     times                           sys_times
99      n64     ptrace                          sys_ptrace
100     n64     getuid                          sys_getuid
101     n64     syslog                          sys_syslog
102     n64     getgid                          sys_getgid
103     n64     setuid                          sys_setuid
104     n64     setgid                          sys_setgid
105     n64     geteuid                         sys_geteuid
106     n64     getegid                         sys_getegid
107     n64     setpgid                         sys_setpgid
108     n64     getppid                         sys_getppid
109     n64     getpgrp                         sys_getpgrp
110     n64     setsid                          sys_setsid
111     n64     setreuid                        sys_setreuid
112     n64     setregid                        sys_setregid
113     n64     getgroups                       sys_getgroups
114     n64     setgroups                       sys_setgroups
115     n64     setresuid                       sys_setresuid
116     n64     getresuid                       sys_getresuid
117     n64     setresgid                       sys_setresgid
118     n64     getresgid                       sys_getresgid
119     n64     getpgid                         sys_getpgid
120     n64     setfsuid                        sys_setfsuid
121     n64     setfsgid                        sys_setfsgid
122     n64     getsid                          sys_getsid
123     n64     capget                          sys_capget
124     n64     capset                          sys_capset
125     n64     rt_sigpending                   sys_rt_sigpending
126     n64     rt_sigtimedwait                 sys_rt_sigtimedwait
127     n64     rt_sigqueueinfo                 sys_rt_sigqueueinfo
128     n64     rt_sigsuspend                   sys_rt_sigsuspend
129     n64     sigaltstack                     sys_sigaltstack
130     n64     utime                           sys_utime
131     n64     mknod                           sys_mknod
132     n64     personality                     sys_personality
133     n64     ustat                           sys_ustat
134     n64     statfs                          sys_statfs
135     n64     fstatfs                         sys_fstatfs
136     n64     sysfs                           sys_sysfs
137     n64     getpriority                     sys_getpriority
138     n64     setpriority                     sys_setpriority
139     n64     sched_setparam                  sys_sched_setparam
140     n64     sched_getparam                  sys_sched_getparam
141     n64     sched_setscheduler              sys_sched_setscheduler
142     n64     sched_getscheduler              sys_sched_getscheduler
143     n64     sched_get_priority_max          sys_sched_get_priority_max
144     n64     sched_get_priority_min          sys_sched_get_priority_min
145     n64     sched_rr_get_interval           sys_sched_rr_get_interval
146     n64     mlock                           sys_mlock
147     n64     munlock                         sys_munlock
148     n64     mlockall                        sys_mlockall
149     n64     munlockall                      sys_munlockall
150     n64     vhangup                         sys_vhangup
151     n64     pivot_root                      sys_pivot_root
152     n64     _sysctl                         sys_ni_syscall
153     n64     prctl                           sys_prctl
154     n64     adjtimex                        sys_adjtimex
155     n64     setrlimit                       sys_setrlimit
156     n64     chroot                          sys_chroot
157     n64     sync                            sys_sync
158     n64     acct                            sys_acct
159     n64     settimeofday                    sys_settimeofday
160     n64     mount                           sys_mount
161     n64     umount2                         sys_umount
162     n64     swapon                          sys_swapon
163     n64     swapoff                         sys_swapoff
164     n64     reboot                          sys_reboot
165     n64     sethostname                     sys_sethostname
166     n64     setdomainname                   sys_setdomainname
167     n64     create_module                   sys_ni_syscall
168     n64     init_module                     sys_init_module
169     n64     delete_module                   sys_delete_module
170     n64     get_kernel_syms                 sys_ni_syscall
171     n64     query_module                    sys_ni_syscall
172     n64     quotactl                        sys_quotactl
173     n64     nfsservctl                      sys_ni_syscall
174     n64     getpmsg                         sys_ni_syscall
175     n64     putpmsg                         sys_ni_syscall
176     n64     afs_syscall                     sys_ni_syscall
# 177 reserved for security
177     n64     reserved177                     sys_ni_syscall
178     n64     gettid                          sys_gettid
179     n64     readahead                       sys_readahead
180     n64     setxattr                        sys_setxattr
181     n64     lsetxattr                       sys_lsetxattr
182     n64     fsetxattr                       sys_fsetxattr
183     n64     getxattr                        sys_getxattr
184     n64     lgetxattr                       sys_lgetxattr
185     n64     fgetxattr                       sys_fgetxattr
186     n64     listxattr                       sys_listxattr
187     n64     llistxattr                      sys_llistxattr
188     n64     flistxattr                      sys_flistxattr
189     n64     removexattr                     sys_removexattr
190     n64     lremovexattr                    sys_lremovexattr
191     n64     fremovexattr                    sys_fremovexattr
192     n64     tkill                           sys_tkill
193     n64     reserved193                     sys_ni_syscall
194     n64     futex                           sys_futex
195     n64     sched_setaffinity               sys_sched_setaffinity
196     n64     sched_getaffinity               sys_sched_getaffinity
197     n64     cacheflush                      sys_cacheflush
198     n64     cachectl                        sys_cachectl
199     n64     sysmips                         __sys_sysmips
200     n64     io_setup                        sys_io_setup
201     n64     io_destroy                      sys_io_destroy
202     n64     io_getevents                    sys_io_getevents
203     n64     io_submit                       sys_io_submit
204     n64     io_cancel                       sys_io_cancel
205     n64     exit_group                      sys_exit_group
206     n64     lookup_dcookie                  sys_ni_syscall
207     n64     epoll_create                    sys_epoll_create
208     n64     epoll_ctl                       sys_epoll_ctl
209     n64     epoll_wait                      sys_epoll_wait
210     n64     remap_file_pages                sys_remap_file_pages
211     n64     rt_sigreturn                    sys_rt_sigreturn
212     n64     set_tid_address                 sys_set_tid_address
213     n64     restart_syscall                 sys_restart_syscall
214     n64     semtimedop                      sys_semtimedop
215     n64     fadvise64                       sys_fadvise64_64
216     n64     timer_create                    sys_timer_create
217     n64     timer_settime                   sys_timer_settime
218     n64     timer_gettime                   sys_timer_gettime
219     n64     timer_getoverrun                sys_timer_getoverrun
220     n64     timer_delete                    sys_timer_delete
221     n64     clock_settime                   sys_clock_settime
222     n64     clock_gettime                   sys_clock_gettime
223     n64     clock_getres                    sys_clock_getres
224     n64     clock_nanosleep                 sys_clock_nanosleep
225     n64     tgkill                          sys_tgkill
226     n64     utimes                          sys_utimes
227     n64     mbind                           sys_mbind
228     n64     get_mempolicy                   sys_get_mempolicy
229     n64     set_mempolicy                   sys_set_mempolicy
230     n64     mq_open                         sys_mq_open
231     n64     mq_unlink                       sys_mq_unlink
232     n64     mq_timedsend                    sys_mq_timedsend
233     n64     mq_timedreceive                 sys_mq_timedreceive
234     n64     mq_notify                       sys_mq_notify
235     n64     mq_getsetattr                   sys_mq_getsetattr
236     n64     vserver                         sys_ni_syscall
237     n64     waitid                          sys_waitid
# 238 was sys_setaltroot
239     n64     add_key                         sys_add_key
240     n64     request_key                     sys_request_key
241     n64     keyctl                          sys_keyctl
242     n64     set_thread_area                 sys_set_thread_area
243     n64     inotify_init                    sys_inotify_init
244     n64     inotify_add_watch               sys_inotify_add_watch
245     n64     inotify_rm_watch                sys_inotify_rm_watch
246     n64     migrate_pages                   sys_migrate_pages
247     n64     openat                          sys_openat
248     n64     mkdirat                         sys_mkdirat
249     n64     mknodat                         sys_mknodat
250     n64     fchownat                        sys_fchownat
251     n64     futimesat                       sys_futimesat
252     n64     newfstatat                      sys_newfstatat
253     n64     unlinkat                        sys_unlinkat
254     n64     renameat                        sys_renameat
255     n64     linkat                          sys_linkat
256     n64     symlinkat                       sys_symlinkat
257     n64     readlinkat                      sys_readlinkat
258     n64     fchmodat                        sys_fchmodat
259     n64     faccessat                       sys_faccessat
260     n64     pselect6                        sys_pselect6
261     n64     ppoll                           sys_ppoll
262     n64     unshare                         sys_unshare
263     n64     splice                          sys_splice
264     n64     sync_file_range                 sys_sync_file_range
265     n64     tee                             sys_tee
266     n64     vmsplice                        sys_vmsplice
267     n64     move_pages                      sys_move_pages
268     n64     set_robust_list                 sys_set_robust_list
269     n64     get_robust_list                 sys_get_robust_list
270     n64     kexec_load                      sys_kexec_load
271     n64     getcpu                          sys_getcpu
272     n64     epoll_pwait                     sys_epoll_pwait
273     n64     ioprio_set                      sys_ioprio_set
274     n64     ioprio_get                      sys_ioprio_get
275     n64     utimensat                       sys_utimensat
276     n64     signalfd                        sys_signalfd
277     n64     timerfd                         sys_ni_syscall
278     n64     eventfd                         sys_eventfd
279     n64     fallocate                       sys_fallocate
280     n64     timerfd_create                  sys_timerfd_create
281     n64     timerfd_gettime                 sys_timerfd_gettime
282     n64     timerfd_settime                 sys_timerfd_settime
283     n64     signalfd4                       sys_signalfd4
284     n64     eventfd2                        sys_eventfd2
285     n64     epoll_create1                   sys_epoll_create1
286     n64     dup3                            sys_dup3
287     n64     pipe2                           sys_pipe2
288     n64     inotify_init1                   sys_inotify_init1
289     n64     preadv                          sys_preadv
290     n64     pwritev                         sys_pwritev
291     n64     rt_tgsigqueueinfo               sys_rt_tgsigqueueinfo
292     n64     perf_event_open                 sys_perf_event_open
293     n64     accept4                         sys_accept4
294     n64     recvmmsg                        sys_recvmmsg
295     n64     fanotify_init                   sys_fanotify_init
296     n64     fanotify_mark                   sys_fanotify_mark
297     n64     prlimit64                       sys_prlimit64
298     n64     name_to_handle_at               sys_name_to_handle_at
299     n64     open_by_handle_at               sys_open_by_handle_at
300     n64     clock_adjtime                   sys_clock_adjtime
301     n64     syncfs                          sys_syncfs
302     n64     sendmmsg                        sys_sendmmsg
303     n64     setns                           sys_setns
304     n64     process_vm_readv                sys_process_vm_readv
305     n64     process_vm_writev               sys_process_vm_writev
306     n64     kcmp                            sys_kcmp
307     n64     finit_module                    sys_finit_module
308     n64     getdents64                      sys_getdents64
309     n64     sched_setattr                   sys_sched_setattr
310     n64     sched_getattr                   sys_sched_getattr
311     n64     renameat2                       sys_renameat2
312     n64     seccomp                         sys_seccomp
313     n64     getrandom                       sys_getrandom
314     n64     memfd_create                    sys_memfd_create
315     n64     bpf                             sys_bpf
316     n64     execveat                        sys_execveat
317     n64     userfaultfd                     sys_userfaultfd
318     n64     membarrier                      sys_membarrier
319     n64     mlock2                          sys_mlock2
320     n64     copy_file_range                 sys_copy_file_range
321     n64     preadv2                         sys_preadv2
322     n64     pwritev2                        sys_pwritev2
323     n64     pkey_mprotect                   sys_pkey_mprotect
324     n64     pkey_alloc                      sys_pkey_alloc
325     n64     pkey_free                       sys_pkey_free
326     n64     statx                           sys_statx
327     n64     rseq                            sys_rseq
328     n64     io_pgetevents                   sys_io_pgetevents
# 329 through 423 are reserved to sync up with other architectures
424     n64     pidfd_send_signal               sys_pidfd_send_signal
425     n64     io_uring_setup                  sys_io_uring_setup
426     n64     io_uring_enter                  sys_io_uring_enter
427     n64     io_uring_register               sys_io_uring_register
428     n64     open_tree                       sys_open_tree
429     n64     move_mount                      sys_move_mount
430     n64     fsopen                          sys_fsopen
431     n64     fsconfig                        sys_fsconfig
432     n64     fsmount                         sys_fsmount
433     n64     fspick                          sys_fspick
434     n64     pidfd_open                      sys_pidfd_open
435     n64     clone3                          __sys_clone3
436     n64     close_range                     sys_close_range
437     n64     openat2                         sys_openat2
438     n64     pidfd_getfd                     sys_pidfd_getfd
439     n64     faccessat2                      sys_faccessat2
440     n64     process_madvise                 sys_process_madvise
441     n64     epoll_pwait2                    sys_epoll_pwait2
442     n64     mount_setattr                   sys_mount_setattr
443     n64     quotactl_fd                     sys_quotactl_fd
444     n64     landlock_create_ruleset         sys_landlock_create_ruleset
445     n64     landlock_add_rule               sys_landlock_add_rule
446     n64     landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     n64     process_mrelease                sys_process_mrelease
449     n64     futex_waitv                     sys_futex_waitv
450     common  set_mempolicy_home_node         sys_set_mempolicy_home_node
451     n64     cachestat                       sys_cachestat
452     n64     fchmodat2                       sys_fchmodat2
453     n64     map_shadow_stack                sys_map_shadow_stack
454     n64     futex_wake                      sys_futex_wake
455     n64     futex_wait                      sys_futex_wait
456     n64     futex_requeue                   sys_futex_requeue
457     n64     statmount                       sys_statmount
458     n64     listmount                       sys_listmount
459     n64     lsm_get_self_attr               sys_lsm_get_self_attr
460     n64     lsm_set_self_attr               sys_lsm_set_self_attr
461     n64     lsm_list_modules                sys_lsm_list_modules
462     n64     mseal                           sys_mseal
"""


# PowerPC
# - arch/powerpc/kernel/syscalls/syscall.tbl
ppc_syscall_tbl = """
# system call numbers and entry vectors for powerpc
#
# The format is:
# <number> <abi> <name> <entry point> <compat entry point>
#
# The <abi> can be common, spu, nospu, 64, or 32 for this file.
#
0       nospu   restart_syscall                 sys_restart_syscall
1       nospu   exit                            sys_exit
2       nospu   fork                            sys_fork
3       common  read                            sys_read
4       common  write                           sys_write
5       common  open                            sys_open                        compat_sys_open
6       common  close                           sys_close
7       common  waitpid                         sys_waitpid
8       common  creat                           sys_creat
9       common  link                            sys_link
10      common  unlink                          sys_unlink
11      nospu   execve                          sys_execve                      compat_sys_execve
12      common  chdir                           sys_chdir
13      32      time                            sys_time32
13      64      time                            sys_time
13      spu     time                            sys_time
14      common  mknod                           sys_mknod
15      common  chmod                           sys_chmod
16      common  lchown                          sys_lchown
17      common  break                           sys_ni_syscall
18      32      oldstat                         sys_stat                        sys_ni_syscall
18      64      oldstat                         sys_ni_syscall
18      spu     oldstat                         sys_ni_syscall
19      common  lseek                           sys_lseek                       compat_sys_lseek
20      common  getpid                          sys_getpid
21      nospu   mount                           sys_mount
22      32      umount                          sys_oldumount
22      64      umount                          sys_ni_syscall
22      spu     umount                          sys_ni_syscall
23      common  setuid                          sys_setuid
24      common  getuid                          sys_getuid
25      32      stime                           sys_stime32
25      64      stime                           sys_stime
25      spu     stime                           sys_stime
26      nospu   ptrace                          sys_ptrace                      compat_sys_ptrace
27      common  alarm                           sys_alarm
28      32      oldfstat                        sys_fstat                       sys_ni_syscall
28      64      oldfstat                        sys_ni_syscall
28      spu     oldfstat                        sys_ni_syscall
29      nospu   pause                           sys_pause
30      32      utime                           sys_utime32
30      64      utime                           sys_utime
31      common  stty                            sys_ni_syscall
32      common  gtty                            sys_ni_syscall
33      common  access                          sys_access
34      common  nice                            sys_nice
35      common  ftime                           sys_ni_syscall
36      common  sync                            sys_sync
37      common  kill                            sys_kill
38      common  rename                          sys_rename
39      common  mkdir                           sys_mkdir
40      common  rmdir                           sys_rmdir
41      common  dup                             sys_dup
42      common  pipe                            sys_pipe
43      common  times                           sys_times                       compat_sys_times
44      common  prof                            sys_ni_syscall
45      common  brk                             sys_brk
46      common  setgid                          sys_setgid
47      common  getgid                          sys_getgid
48      nospu   signal                          sys_signal
49      common  geteuid                         sys_geteuid
50      common  getegid                         sys_getegid
51      nospu   acct                            sys_acct
52      nospu   umount2                         sys_umount
53      common  lock                            sys_ni_syscall
54      common  ioctl                           sys_ioctl                       compat_sys_ioctl
55      common  fcntl                           sys_fcntl                       compat_sys_fcntl
56      common  mpx                             sys_ni_syscall
57      common  setpgid                         sys_setpgid
58      common  ulimit                          sys_ni_syscall
59      32      oldolduname                     sys_olduname
59      64      oldolduname                     sys_ni_syscall
59      spu     oldolduname                     sys_ni_syscall
60      common  umask                           sys_umask
61      common  chroot                          sys_chroot
62      nospu   ustat                           sys_ustat                       compat_sys_ustat
63      common  dup2                            sys_dup2
64      common  getppid                         sys_getppid
65      common  getpgrp                         sys_getpgrp
66      common  setsid                          sys_setsid
67      32      sigaction                       sys_sigaction                   compat_sys_sigaction
67      64      sigaction                       sys_ni_syscall
67      spu     sigaction                       sys_ni_syscall
68      common  sgetmask                        sys_sgetmask
69      common  ssetmask                        sys_ssetmask
70      common  setreuid                        sys_setreuid
71      common  setregid                        sys_setregid
72      32      sigsuspend                      sys_sigsuspend
72      64      sigsuspend                      sys_ni_syscall
72      spu     sigsuspend                      sys_ni_syscall
73      32      sigpending                      sys_sigpending                  compat_sys_sigpending
73      64      sigpending                      sys_ni_syscall
73      spu     sigpending                      sys_ni_syscall
74      common  sethostname                     sys_sethostname
75      common  setrlimit                       sys_setrlimit                   compat_sys_setrlimit
76      32      getrlimit                       sys_old_getrlimit               compat_sys_old_getrlimit
76      64      getrlimit                       sys_ni_syscall
76      spu     getrlimit                       sys_ni_syscall
77      common  getrusage                       sys_getrusage                   compat_sys_getrusage
78      common  gettimeofday                    sys_gettimeofday                compat_sys_gettimeofday
79      common  settimeofday                    sys_settimeofday                compat_sys_settimeofday
80      common  getgroups                       sys_getgroups
81      common  setgroups                       sys_setgroups
82      32      select                          sys_old_select                  compat_sys_old_select
82      64      select                          sys_ni_syscall
82      spu     select                          sys_ni_syscall
83      common  symlink                         sys_symlink
84      32      oldlstat                        sys_lstat                       sys_ni_syscall
84      64      oldlstat                        sys_ni_syscall
84      spu     oldlstat                        sys_ni_syscall
85      common  readlink                        sys_readlink
86      nospu   uselib                          sys_uselib
87      nospu   swapon                          sys_swapon
88      nospu   reboot                          sys_reboot
89      32      readdir                         sys_old_readdir                 compat_sys_old_readdir
89      64      readdir                         sys_ni_syscall
89      spu     readdir                         sys_ni_syscall
90      common  mmap                            sys_mmap
91      common  munmap                          sys_munmap
92      common  truncate                        sys_truncate                    compat_sys_truncate
93      common  ftruncate                       sys_ftruncate                   compat_sys_ftruncate
94      common  fchmod                          sys_fchmod
95      common  fchown                          sys_fchown
96      common  getpriority                     sys_getpriority
97      common  setpriority                     sys_setpriority
98      common  profil                          sys_ni_syscall
99      nospu   statfs                          sys_statfs                      compat_sys_statfs
100     nospu   fstatfs                         sys_fstatfs                     compat_sys_fstatfs
101     common  ioperm                          sys_ni_syscall
102     common  socketcall                      sys_socketcall                  compat_sys_socketcall
103     common  syslog                          sys_syslog
104     common  setitimer                       sys_setitimer                   compat_sys_setitimer
105     common  getitimer                       sys_getitimer                   compat_sys_getitimer
106     common  stat                            sys_newstat                     compat_sys_newstat
107     common  lstat                           sys_newlstat                    compat_sys_newlstat
108     common  fstat                           sys_newfstat                    compat_sys_newfstat
109     32      olduname                        sys_uname
109     64      olduname                        sys_ni_syscall
109     spu     olduname                        sys_ni_syscall
110     common  iopl                            sys_ni_syscall
111     common  vhangup                         sys_vhangup
112     common  idle                            sys_ni_syscall
113     common  vm86                            sys_ni_syscall
114     common  wait4                           sys_wait4                       compat_sys_wait4
115     nospu   swapoff                         sys_swapoff
116     common  sysinfo                         sys_sysinfo                     compat_sys_sysinfo
117     nospu   ipc                             sys_ipc                         compat_sys_ipc
118     common  fsync                           sys_fsync
119     32      sigreturn                       sys_sigreturn                   compat_sys_sigreturn
119     64      sigreturn                       sys_ni_syscall
119     spu     sigreturn                       sys_ni_syscall
120     nospu   clone                           sys_clone
121     common  setdomainname                   sys_setdomainname
122     common  uname                           sys_newuname
123     common  modify_ldt                      sys_ni_syscall
124     32      adjtimex                        sys_adjtimex_time32
124     64      adjtimex                        sys_adjtimex
124     spu     adjtimex                        sys_adjtimex
125     common  mprotect                        sys_mprotect
126     32      sigprocmask                     sys_sigprocmask                 compat_sys_sigprocmask
126     64      sigprocmask                     sys_ni_syscall
126     spu     sigprocmask                     sys_ni_syscall
127     common  create_module                   sys_ni_syscall
128     nospu   init_module                     sys_init_module
129     nospu   delete_module                   sys_delete_module
130     common  get_kernel_syms                 sys_ni_syscall
131     nospu   quotactl                        sys_quotactl
132     common  getpgid                         sys_getpgid
133     common  fchdir                          sys_fchdir
134     common  bdflush                         sys_ni_syscall
135     common  sysfs                           sys_sysfs
136     32      personality                     sys_personality                 compat_sys_ppc64_personality
136     64      personality                     sys_ppc64_personality
136     spu     personality                     sys_ppc64_personality
137     common  afs_syscall                     sys_ni_syscall
138     common  setfsuid                        sys_setfsuid
139     common  setfsgid                        sys_setfsgid
140     common  _llseek                         sys_llseek
141     common  getdents                        sys_getdents                    compat_sys_getdents
142     common  _newselect                      sys_select                      compat_sys_select
143     common  flock                           sys_flock
144     common  msync                           sys_msync
145     common  readv                           sys_readv
146     common  writev                          sys_writev
147     common  getsid                          sys_getsid
148     common  fdatasync                       sys_fdatasync
149     nospu   _sysctl                         sys_ni_syscall
150     common  mlock                           sys_mlock
151     common  munlock                         sys_munlock
152     common  mlockall                        sys_mlockall
153     common  munlockall                      sys_munlockall
154     common  sched_setparam                  sys_sched_setparam
155     common  sched_getparam                  sys_sched_getparam
156     common  sched_setscheduler              sys_sched_setscheduler
157     common  sched_getscheduler              sys_sched_getscheduler
158     common  sched_yield                     sys_sched_yield
159     common  sched_get_priority_max          sys_sched_get_priority_max
160     common  sched_get_priority_min          sys_sched_get_priority_min
161     32      sched_rr_get_interval           sys_sched_rr_get_interval_time32
161     64      sched_rr_get_interval           sys_sched_rr_get_interval
161     spu     sched_rr_get_interval           sys_sched_rr_get_interval
162     32      nanosleep                       sys_nanosleep_time32
162     64      nanosleep                       sys_nanosleep
162     spu     nanosleep                       sys_nanosleep
163     common  mremap                          sys_mremap
164     common  setresuid                       sys_setresuid
165     common  getresuid                       sys_getresuid
166     common  query_module                    sys_ni_syscall
167     common  poll                            sys_poll
168     common  nfsservctl                      sys_ni_syscall
169     common  setresgid                       sys_setresgid
170     common  getresgid                       sys_getresgid
171     common  prctl                           sys_prctl
172     nospu   rt_sigreturn                    sys_rt_sigreturn                compat_sys_rt_sigreturn
173     nospu   rt_sigaction                    sys_rt_sigaction                compat_sys_rt_sigaction
174     nospu   rt_sigprocmask                  sys_rt_sigprocmask              compat_sys_rt_sigprocmask
175     nospu   rt_sigpending                   sys_rt_sigpending               compat_sys_rt_sigpending
176     32      rt_sigtimedwait                 sys_rt_sigtimedwait_time32      compat_sys_rt_sigtimedwait_time32
176     64      rt_sigtimedwait                 sys_rt_sigtimedwait
177     nospu   rt_sigqueueinfo                 sys_rt_sigqueueinfo             compat_sys_rt_sigqueueinfo
178     nospu   rt_sigsuspend                   sys_rt_sigsuspend               compat_sys_rt_sigsuspend
179     32      pread64                         sys_ppc_pread64                 compat_sys_ppc_pread64
179     64      pread64                         sys_pread64
179     spu     pread64                         sys_pread64
180     32      pwrite64                        sys_ppc_pwrite64                compat_sys_ppc_pwrite64
180     64      pwrite64                        sys_pwrite64
180     spu     pwrite64                        sys_pwrite64
181     common  chown                           sys_chown
182     common  getcwd                          sys_getcwd
183     common  capget                          sys_capget
184     common  capset                          sys_capset
185     nospu   sigaltstack                     sys_sigaltstack                 compat_sys_sigaltstack
186     32      sendfile                        sys_sendfile                    compat_sys_sendfile
186     64      sendfile                        sys_sendfile64
186     spu     sendfile                        sys_sendfile64
187     common  getpmsg                         sys_ni_syscall
188     common  putpmsg                         sys_ni_syscall
189     nospu   vfork                           sys_vfork
190     common  ugetrlimit                      sys_getrlimit                   compat_sys_getrlimit
191     32      readahead                       sys_ppc_readahead               compat_sys_ppc_readahead
191     64      readahead                       sys_readahead
191     spu     readahead                       sys_readahead
192     32      mmap2                           sys_mmap2                       compat_sys_mmap2
193     32      truncate64                      sys_ppc_truncate64              compat_sys_ppc_truncate64
194     32      ftruncate64                     sys_ppc_ftruncate64             compat_sys_ppc_ftruncate64
195     32      stat64                          sys_stat64
196     32      lstat64                         sys_lstat64
197     32      fstat64                         sys_fstat64
198     nospu   pciconfig_read                  sys_pciconfig_read
199     nospu   pciconfig_write                 sys_pciconfig_write
200     nospu   pciconfig_iobase                sys_pciconfig_iobase
201     common  multiplexer                     sys_ni_syscall
202     common  getdents64                      sys_getdents64
203     common  pivot_root                      sys_pivot_root
204     32      fcntl64                         sys_fcntl64                     compat_sys_fcntl64
205     common  madvise                         sys_madvise
206     common  mincore                         sys_mincore
207     common  gettid                          sys_gettid
208     common  tkill                           sys_tkill
209     common  setxattr                        sys_setxattr
210     common  lsetxattr                       sys_lsetxattr
211     common  fsetxattr                       sys_fsetxattr
212     common  getxattr                        sys_getxattr
213     common  lgetxattr                       sys_lgetxattr
214     common  fgetxattr                       sys_fgetxattr
215     common  listxattr                       sys_listxattr
216     common  llistxattr                      sys_llistxattr
217     common  flistxattr                      sys_flistxattr
218     common  removexattr                     sys_removexattr
219     common  lremovexattr                    sys_lremovexattr
220     common  fremovexattr                    sys_fremovexattr
221     32      futex                           sys_futex_time32
221     64      futex                           sys_futex
221     spu     futex                           sys_futex
222     common  sched_setaffinity               sys_sched_setaffinity           compat_sys_sched_setaffinity
223     common  sched_getaffinity               sys_sched_getaffinity           compat_sys_sched_getaffinity
# 224 unused
225     common  tuxcall                         sys_ni_syscall
226     32      sendfile64                      sys_sendfile64                  compat_sys_sendfile64
227     common  io_setup                        sys_io_setup                    compat_sys_io_setup
228     common  io_destroy                      sys_io_destroy
229     32      io_getevents                    sys_io_getevents_time32
229     64      io_getevents                    sys_io_getevents
229     spu     io_getevents                    sys_io_getevents
230     common  io_submit                       sys_io_submit                   compat_sys_io_submit
231     common  io_cancel                       sys_io_cancel
232     nospu   set_tid_address                 sys_set_tid_address
233     32      fadvise64                       sys_ppc32_fadvise64             compat_sys_ppc32_fadvise64
233     64      fadvise64                       sys_fadvise64
233     spu     fadvise64                       sys_fadvise64
234     nospu   exit_group                      sys_exit_group
235     nospu   lookup_dcookie                  sys_ni_syscall
236     common  epoll_create                    sys_epoll_create
237     common  epoll_ctl                       sys_epoll_ctl
238     common  epoll_wait                      sys_epoll_wait
239     common  remap_file_pages                sys_remap_file_pages
240     common  timer_create                    sys_timer_create                compat_sys_timer_create
241     32      timer_settime                   sys_timer_settime32
241     64      timer_settime                   sys_timer_settime
241     spu     timer_settime                   sys_timer_settime
242     32      timer_gettime                   sys_timer_gettime32
242     64      timer_gettime                   sys_timer_gettime
242     spu     timer_gettime                   sys_timer_gettime
243     common  timer_getoverrun                sys_timer_getoverrun
244     common  timer_delete                    sys_timer_delete
245     32      clock_settime                   sys_clock_settime32
245     64      clock_settime                   sys_clock_settime
245     spu     clock_settime                   sys_clock_settime
246     32      clock_gettime                   sys_clock_gettime32
246     64      clock_gettime                   sys_clock_gettime
246     spu     clock_gettime                   sys_clock_gettime
247     32      clock_getres                    sys_clock_getres_time32
247     64      clock_getres                    sys_clock_getres
247     spu     clock_getres                    sys_clock_getres
248     32      clock_nanosleep                 sys_clock_nanosleep_time32
248     64      clock_nanosleep                 sys_clock_nanosleep
248     spu     clock_nanosleep                 sys_clock_nanosleep
249     nospu   swapcontext                     sys_swapcontext                 compat_sys_swapcontext
250     common  tgkill                          sys_tgkill
251     32      utimes                          sys_utimes_time32
251     64      utimes                          sys_utimes
251     spu     utimes                          sys_utimes
252     common  statfs64                        sys_statfs64                    compat_sys_statfs64
253     common  fstatfs64                       sys_fstatfs64                   compat_sys_fstatfs64
254     32      fadvise64_64                    sys_ppc_fadvise64_64
254     spu     fadvise64_64                    sys_ni_syscall
255     common  rtas                            sys_rtas
256     32      sys_debug_setcontext            sys_debug_setcontext            sys_ni_syscall
256     64      sys_debug_setcontext            sys_ni_syscall
256     spu     sys_debug_setcontext            sys_ni_syscall
# 257 reserved for vserver
258     nospu   migrate_pages                   sys_migrate_pages
259     nospu   mbind                           sys_mbind
260     nospu   get_mempolicy                   sys_get_mempolicy
261     nospu   set_mempolicy                   sys_set_mempolicy
262     nospu   mq_open                         sys_mq_open                     compat_sys_mq_open
263     nospu   mq_unlink                       sys_mq_unlink
264     32      mq_timedsend                    sys_mq_timedsend_time32
264     64      mq_timedsend                    sys_mq_timedsend
265     32      mq_timedreceive                 sys_mq_timedreceive_time32
265     64      mq_timedreceive                 sys_mq_timedreceive
266     nospu   mq_notify                       sys_mq_notify                   compat_sys_mq_notify
267     nospu   mq_getsetattr                   sys_mq_getsetattr               compat_sys_mq_getsetattr
268     nospu   kexec_load                      sys_kexec_load                  compat_sys_kexec_load
269     nospu   add_key                         sys_add_key
270     nospu   request_key                     sys_request_key
271     nospu   keyctl                          sys_keyctl                      compat_sys_keyctl
272     nospu   waitid                          sys_waitid                      compat_sys_waitid
273     nospu   ioprio_set                      sys_ioprio_set
274     nospu   ioprio_get                      sys_ioprio_get
275     nospu   inotify_init                    sys_inotify_init
276     nospu   inotify_add_watch               sys_inotify_add_watch
277     nospu   inotify_rm_watch                sys_inotify_rm_watch
278     nospu   spu_run                         sys_spu_run
279     nospu   spu_create                      sys_spu_create
280     32      pselect6                        sys_pselect6_time32             compat_sys_pselect6_time32
280     64      pselect6                        sys_pselect6
281     32      ppoll                           sys_ppoll_time32                compat_sys_ppoll_time32
281     64      ppoll                           sys_ppoll
282     common  unshare                         sys_unshare
283     common  splice                          sys_splice
284     common  tee                             sys_tee
285     common  vmsplice                        sys_vmsplice
286     common  openat                          sys_openat                      compat_sys_openat
287     common  mkdirat                         sys_mkdirat
288     common  mknodat                         sys_mknodat
289     common  fchownat                        sys_fchownat
290     32      futimesat                       sys_futimesat_time32
290     64      futimesat                       sys_futimesat
290     spu     utimesat                        sys_futimesat
291     32      fstatat64                       sys_fstatat64
291     64      newfstatat                      sys_newfstatat
291     spu     newfstatat                      sys_newfstatat
292     common  unlinkat                        sys_unlinkat
293     common  renameat                        sys_renameat
294     common  linkat                          sys_linkat
295     common  symlinkat                       sys_symlinkat
296     common  readlinkat                      sys_readlinkat
297     common  fchmodat                        sys_fchmodat
298     common  faccessat                       sys_faccessat
299     common  get_robust_list                 sys_get_robust_list             compat_sys_get_robust_list
300     common  set_robust_list                 sys_set_robust_list             compat_sys_set_robust_list
301     common  move_pages                      sys_move_pages
302     common  getcpu                          sys_getcpu
303     nospu   epoll_pwait                     sys_epoll_pwait                 compat_sys_epoll_pwait
304     32      utimensat                       sys_utimensat_time32
304     64      utimensat                       sys_utimensat
304     spu     utimensat                       sys_utimensat
305     common  signalfd                        sys_signalfd                    compat_sys_signalfd
306     common  timerfd_create                  sys_timerfd_create
307     common  eventfd                         sys_eventfd
308     32      sync_file_range2                sys_ppc_sync_file_range2        compat_sys_ppc_sync_file_range2
308     64      sync_file_range2                sys_sync_file_range2
308     spu     sync_file_range2                sys_sync_file_range2
309     32      fallocate                       sys_ppc_fallocate               compat_sys_fallocate
309     64      fallocate                       sys_fallocate
310     nospu   subpage_prot                    sys_subpage_prot
311     32      timerfd_settime                 sys_timerfd_settime32
311     64      timerfd_settime                 sys_timerfd_settime
311     spu     timerfd_settime                 sys_timerfd_settime
312     32      timerfd_gettime                 sys_timerfd_gettime32
312     64      timerfd_gettime                 sys_timerfd_gettime
312     spu     timerfd_gettime                 sys_timerfd_gettime
313     common  signalfd4                       sys_signalfd4                   compat_sys_signalfd4
314     common  eventfd2                        sys_eventfd2
315     common  epoll_create1                   sys_epoll_create1
316     common  dup3                            sys_dup3
317     common  pipe2                           sys_pipe2
318     nospu   inotify_init1                   sys_inotify_init1
319     common  perf_event_open                 sys_perf_event_open
320     common  preadv                          sys_preadv                      compat_sys_preadv
321     common  pwritev                         sys_pwritev                     compat_sys_pwritev
322     nospu   rt_tgsigqueueinfo               sys_rt_tgsigqueueinfo           compat_sys_rt_tgsigqueueinfo
323     nospu   fanotify_init                   sys_fanotify_init
324     nospu   fanotify_mark                   sys_fanotify_mark               compat_sys_fanotify_mark
325     common  prlimit64                       sys_prlimit64
326     common  socket                          sys_socket
327     common  bind                            sys_bind
328     common  connect                         sys_connect
329     common  listen                          sys_listen
330     common  accept                          sys_accept
331     common  getsockname                     sys_getsockname
332     common  getpeername                     sys_getpeername
333     common  socketpair                      sys_socketpair
334     common  send                            sys_send
335     common  sendto                          sys_sendto
336     common  recv                            sys_recv                        compat_sys_recv
337     common  recvfrom                        sys_recvfrom                    compat_sys_recvfrom
338     common  shutdown                        sys_shutdown
339     common  setsockopt                      sys_setsockopt                  sys_setsockopt
340     common  getsockopt                      sys_getsockopt                  sys_getsockopt
341     common  sendmsg                         sys_sendmsg                     compat_sys_sendmsg
342     common  recvmsg                         sys_recvmsg                     compat_sys_recvmsg
343     32      recvmmsg                        sys_recvmmsg_time32             compat_sys_recvmmsg_time32
343     64      recvmmsg                        sys_recvmmsg
343     spu     recvmmsg                        sys_recvmmsg
344     common  accept4                         sys_accept4
345     common  name_to_handle_at               sys_name_to_handle_at
346     common  open_by_handle_at               sys_open_by_handle_at           compat_sys_open_by_handle_at
347     32      clock_adjtime                   sys_clock_adjtime32
347     64      clock_adjtime                   sys_clock_adjtime
347     spu     clock_adjtime                   sys_clock_adjtime
348     common  syncfs                          sys_syncfs
349     common  sendmmsg                        sys_sendmmsg                    compat_sys_sendmmsg
350     common  setns                           sys_setns
351     nospu   process_vm_readv                sys_process_vm_readv
352     nospu   process_vm_writev               sys_process_vm_writev
353     nospu   finit_module                    sys_finit_module
354     nospu   kcmp                            sys_kcmp
355     common  sched_setattr                   sys_sched_setattr
356     common  sched_getattr                   sys_sched_getattr
357     common  renameat2                       sys_renameat2
358     common  seccomp                         sys_seccomp
359     common  getrandom                       sys_getrandom
360     common  memfd_create                    sys_memfd_create
361     common  bpf                             sys_bpf
362     nospu   execveat                        sys_execveat                    compat_sys_execveat
363     32      switch_endian                   sys_ni_syscall
363     64      switch_endian                   sys_switch_endian
363     spu     switch_endian                   sys_ni_syscall
364     common  userfaultfd                     sys_userfaultfd
365     common  membarrier                      sys_membarrier
# 366-377 originally left for IPC, now unused
378     nospu   mlock2                          sys_mlock2
379     nospu   copy_file_range                 sys_copy_file_range
380     common  preadv2                         sys_preadv2                     compat_sys_preadv2
381     common  pwritev2                        sys_pwritev2                    compat_sys_pwritev2
382     nospu   kexec_file_load                 sys_kexec_file_load
383     nospu   statx                           sys_statx
384     nospu   pkey_alloc                      sys_pkey_alloc
385     nospu   pkey_free                       sys_pkey_free
386     nospu   pkey_mprotect                   sys_pkey_mprotect
387     nospu   rseq                            sys_rseq
388     32      io_pgetevents                   sys_io_pgetevents_time32        compat_sys_io_pgetevents
388     64      io_pgetevents                   sys_io_pgetevents
# room for arch specific syscalls
392     64      semtimedop                      sys_semtimedop
393     common  semget                          sys_semget
394     common  semctl                          sys_semctl                      compat_sys_semctl
395     common  shmget                          sys_shmget
396     common  shmctl                          sys_shmctl                      compat_sys_shmctl
397     common  shmat                           sys_shmat                       compat_sys_shmat
398     common  shmdt                           sys_shmdt
399     common  msgget                          sys_msgget
400     common  msgsnd                          sys_msgsnd                      compat_sys_msgsnd
401     common  msgrcv                          sys_msgrcv                      compat_sys_msgrcv
402     common  msgctl                          sys_msgctl                      compat_sys_msgctl
403     32      clock_gettime64                 sys_clock_gettime               sys_clock_gettime
404     32      clock_settime64                 sys_clock_settime               sys_clock_settime
405     32      clock_adjtime64                 sys_clock_adjtime               sys_clock_adjtime
406     32      clock_getres_time64             sys_clock_getres                sys_clock_getres
407     32      clock_nanosleep_time64          sys_clock_nanosleep             sys_clock_nanosleep
408     32      timer_gettime64                 sys_timer_gettime               sys_timer_gettime
409     32      timer_settime64                 sys_timer_settime               sys_timer_settime
410     32      timerfd_gettime64               sys_timerfd_gettime             sys_timerfd_gettime
411     32      timerfd_settime64               sys_timerfd_settime             sys_timerfd_settime
412     32      utimensat_time64                sys_utimensat                   sys_utimensat
413     32      pselect6_time64                 sys_pselect6                    compat_sys_pselect6_time64
414     32      ppoll_time64                    sys_ppoll                       compat_sys_ppoll_time64
416     32      io_pgetevents_time64            sys_io_pgetevents               compat_sys_io_pgetevents_time64
417     32      recvmmsg_time64                 sys_recvmmsg                    compat_sys_recvmmsg_time64
418     32      mq_timedsend_time64             sys_mq_timedsend                sys_mq_timedsend
419     32      mq_timedreceive_time64          sys_mq_timedreceive             sys_mq_timedreceive
420     32      semtimedop_time64               sys_semtimedop                  sys_semtimedop
421     32      rt_sigtimedwait_time64          sys_rt_sigtimedwait             compat_sys_rt_sigtimedwait_time64
422     32      futex_time64                    sys_futex                       sys_futex
423     32      sched_rr_get_interval_time64    sys_sched_rr_get_interval       sys_sched_rr_get_interval
424     common  pidfd_send_signal               sys_pidfd_send_signal
425     common  io_uring_setup                  sys_io_uring_setup
426     common  io_uring_enter                  sys_io_uring_enter
427     common  io_uring_register               sys_io_uring_register
428     common  open_tree                       sys_open_tree
429     common  move_mount                      sys_move_mount
430     common  fsopen                          sys_fsopen
431     common  fsconfig                        sys_fsconfig
432     common  fsmount                         sys_fsmount
433     common  fspick                          sys_fspick
434     common  pidfd_open                      sys_pidfd_open
435     nospu   clone3                          sys_clone3
436     common  close_range                     sys_close_range
437     common  openat2                         sys_openat2
438     common  pidfd_getfd                     sys_pidfd_getfd
439     common  faccessat2                      sys_faccessat2
440     common  process_madvise                 sys_process_madvise
441     common  epoll_pwait2                    sys_epoll_pwait2                compat_sys_epoll_pwait2
442     common  mount_setattr                   sys_mount_setattr
443     common  quotactl_fd                     sys_quotactl_fd
444     common  landlock_create_ruleset         sys_landlock_create_ruleset
445     common  landlock_add_rule               sys_landlock_add_rule
446     common  landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     common  process_mrelease                sys_process_mrelease
449     common  futex_waitv                     sys_futex_waitv
450     nospu   set_mempolicy_home_node         sys_set_mempolicy_home_node
451     common  cachestat                       sys_cachestat
452     common  fchmodat2                       sys_fchmodat2
453     common  map_shadow_stack                sys_ni_syscall
454     common  futex_wake                      sys_futex_wake
455     common  futex_wait                      sys_futex_wait
456     common  futex_requeue                   sys_futex_requeue
457     common  statmount                       sys_statmount
458     common  listmount                       sys_listmount
459     common  lsm_get_self_attr               sys_lsm_get_self_attr
460     common  lsm_set_self_attr               sys_lsm_set_self_attr
461     common  lsm_list_modules                sys_lsm_list_modules
462     common  mseal                           sys_mseal
"""


# SPARC
# - arch/sparc/kernel/syscalls/syscall.tbl
sparc_syscall_tbl = """
# system call numbers and entry vectors for sparc
#
# The format is:
# <number> <abi> <name> <entry point> <compat entry point>
#
# The <abi> can be common, 64, or 32 for this file.
#
0       common  restart_syscall         sys_restart_syscall
1       32      exit                    sys_exit                        sparc_exit
1       64      exit                    sparc_exit
2       common  fork                    sys_fork
3       common  read                    sys_read
4       common  write                   sys_write
5       common  open                    sys_open                        compat_sys_open
6       common  close                   sys_close
7       common  wait4                   sys_wait4                       compat_sys_wait4
8       common  creat                   sys_creat
9       common  link                    sys_link
10      common  unlink                  sys_unlink
11      32      execv                   sunos_execv
11      64      execv                   sys_nis_syscall
12      common  chdir                   sys_chdir
13      32      chown                   sys_chown16
13      64      chown                   sys_chown
14      common  mknod                   sys_mknod
15      common  chmod                   sys_chmod
16      32      lchown                  sys_lchown16
16      64      lchown                  sys_lchown
17      common  brk                     sys_brk
18      common  perfctr                 sys_nis_syscall
19      common  lseek                   sys_lseek                       compat_sys_lseek
20      common  getpid                  sys_getpid
21      common  capget                  sys_capget
22      common  capset                  sys_capset
23      32      setuid                  sys_setuid16
23      64      setuid                  sys_setuid
24      32      getuid                  sys_getuid16
24      64      getuid                  sys_getuid
25      common  vmsplice                sys_vmsplice
26      common  ptrace                  sys_ptrace                      compat_sys_ptrace
27      common  alarm                   sys_alarm
28      common  sigaltstack             sys_sigaltstack                 compat_sys_sigaltstack
29      32      pause                   sys_pause
29      64      pause                   sys_nis_syscall
30      32      utime                   sys_utime32
30      64      utime                   sys_utime
31      32      lchown32                sys_lchown
32      32      fchown32                sys_fchown
33      common  access                  sys_access
34      common  nice                    sys_nice
35      32      chown32                 sys_chown
36      common  sync                    sys_sync
37      common  kill                    sys_kill
38      common  stat                    sys_newstat                     compat_sys_newstat
39      32      sendfile                sys_sendfile                    compat_sys_sendfile
39      64      sendfile                sys_sendfile64
40      common  lstat                   sys_newlstat                    compat_sys_newlstat
41      common  dup                     sys_dup
42      common  pipe                    sys_sparc_pipe
43      common  times                   sys_times                       compat_sys_times
44      32      getuid32                sys_getuid
45      common  umount2                 sys_umount
46      32      setgid                  sys_setgid16
46      64      setgid                  sys_setgid
47      32      getgid                  sys_getgid16
47      64      getgid                  sys_getgid
48      common  signal                  sys_signal
49      32      geteuid                 sys_geteuid16
49      64      geteuid                 sys_geteuid
50      32      getegid                 sys_getegid16
50      64      getegid                 sys_getegid
51      common  acct                    sys_acct
52      64      memory_ordering         sys_memory_ordering
53      32      getgid32                sys_getgid
54      common  ioctl                   sys_ioctl                       compat_sys_ioctl
55      common  reboot                  sys_reboot
56      32      mmap2                   sys_mmap2                       sys32_mmap2
57      common  symlink                 sys_symlink
58      common  readlink                sys_readlink
59      32      execve                  sys_execve                      sys32_execve
59      64      execve                  sys64_execve
60      common  umask                   sys_umask
61      common  chroot                  sys_chroot
62      common  fstat                   sys_newfstat                    compat_sys_newfstat
63      common  fstat64                 sys_fstat64                     compat_sys_fstat64
64      common  getpagesize             sys_getpagesize
65      common  msync                   sys_msync
66      common  vfork                   sys_vfork
67      common  pread64                 sys_pread64                     compat_sys_pread64
68      common  pwrite64                sys_pwrite64                    compat_sys_pwrite64
69      32      geteuid32               sys_geteuid
70      32      getegid32               sys_getegid
71      common  mmap                    sys_mmap
72      32      setreuid32              sys_setreuid
73      32      munmap                  sys_munmap
73      64      munmap                  sys_64_munmap
74      common  mprotect                sys_mprotect
75      common  madvise                 sys_madvise
76      common  vhangup                 sys_vhangup
77      32      truncate64              sys_truncate64                  compat_sys_truncate64
78      common  mincore                 sys_mincore
79      32      getgroups               sys_getgroups16
79      64      getgroups               sys_getgroups
80      32      setgroups               sys_setgroups16
80      64      setgroups               sys_setgroups
81      common  getpgrp                 sys_getpgrp
82      32      setgroups32             sys_setgroups
83      common  setitimer               sys_setitimer                   compat_sys_setitimer
84      32      ftruncate64             sys_ftruncate64                 compat_sys_ftruncate64
85      common  swapon                  sys_swapon
86      common  getitimer               sys_getitimer                   compat_sys_getitimer
87      32      setuid32                sys_setuid
88      common  sethostname             sys_sethostname
89      32      setgid32                sys_setgid
90      common  dup2                    sys_dup2
91      32      setfsuid32              sys_setfsuid
92      common  fcntl                   sys_fcntl                       compat_sys_fcntl
93      common  select                  sys_select                      compat_sys_select
94      32      setfsgid32              sys_setfsgid
95      common  fsync                   sys_fsync
96      common  setpriority             sys_setpriority
97      common  socket                  sys_socket
98      common  connect                 sys_connect
99      common  accept                  sys_accept
100     common  getpriority             sys_getpriority
101     common  rt_sigreturn            sys_rt_sigreturn                sys32_rt_sigreturn
102     common  rt_sigaction            sys_rt_sigaction                compat_sys_rt_sigaction
103     common  rt_sigprocmask          sys_rt_sigprocmask              compat_sys_rt_sigprocmask
104     common  rt_sigpending           sys_rt_sigpending               compat_sys_rt_sigpending
105     32      rt_sigtimedwait         sys_rt_sigtimedwait_time32      compat_sys_rt_sigtimedwait_time32
105     64      rt_sigtimedwait         sys_rt_sigtimedwait
106     common  rt_sigqueueinfo         sys_rt_sigqueueinfo             compat_sys_rt_sigqueueinfo
107     common  rt_sigsuspend           sys_rt_sigsuspend               compat_sys_rt_sigsuspend
108     32      setresuid32             sys_setresuid
108     64      setresuid               sys_setresuid
109     32      getresuid32             sys_getresuid
109     64      getresuid               sys_getresuid
110     32      setresgid32             sys_setresgid
110     64      setresgid               sys_setresgid
111     32      getresgid32             sys_getresgid
111     64      getresgid               sys_getresgid
112     32      setregid32              sys_setregid
113     common  recvmsg                 sys_recvmsg                     compat_sys_recvmsg
114     common  sendmsg                 sys_sendmsg                     compat_sys_sendmsg
115     32      getgroups32             sys_getgroups
116     common  gettimeofday            sys_gettimeofday                compat_sys_gettimeofday
117     common  getrusage               sys_getrusage                   compat_sys_getrusage
118     common  getsockopt              sys_getsockopt                  sys_getsockopt
119     common  getcwd                  sys_getcwd
120     common  readv                   sys_readv
121     common  writev                  sys_writev
122     common  settimeofday            sys_settimeofday                compat_sys_settimeofday
123     32      fchown                  sys_fchown16
123     64      fchown                  sys_fchown
124     common  fchmod                  sys_fchmod
125     common  recvfrom                sys_recvfrom                    compat_sys_recvfrom
126     32      setreuid                sys_setreuid16
126     64      setreuid                sys_setreuid
127     32      setregid                sys_setregid16
127     64      setregid                sys_setregid
128     common  rename                  sys_rename
129     common  truncate                sys_truncate                    compat_sys_truncate
130     common  ftruncate               sys_ftruncate                   compat_sys_ftruncate
131     common  flock                   sys_flock
132     common  lstat64                 sys_lstat64                     compat_sys_lstat64
133     common  sendto                  sys_sendto
134     common  shutdown                sys_shutdown
135     common  socketpair              sys_socketpair
136     common  mkdir                   sys_mkdir
137     common  rmdir                   sys_rmdir
138     32      utimes                  sys_utimes_time32
138     64      utimes                  sys_utimes
139     common  stat64                  sys_stat64                      compat_sys_stat64
140     common  sendfile64              sys_sendfile64
141     common  getpeername             sys_getpeername
142     32      futex                   sys_futex_time32
142     64      futex                   sys_futex
143     common  gettid                  sys_gettid
144     common  getrlimit               sys_getrlimit                   compat_sys_getrlimit
145     common  setrlimit               sys_setrlimit                   compat_sys_setrlimit
146     common  pivot_root              sys_pivot_root
147     common  prctl                   sys_prctl
148     common  pciconfig_read          sys_pciconfig_read
149     common  pciconfig_write         sys_pciconfig_write
150     common  getsockname             sys_getsockname
151     common  inotify_init            sys_inotify_init
152     common  inotify_add_watch       sys_inotify_add_watch
153     common  poll                    sys_poll
154     common  getdents64              sys_getdents64
155     32      fcntl64                 sys_fcntl64                     compat_sys_fcntl64
156     common  inotify_rm_watch        sys_inotify_rm_watch
157     common  statfs                  sys_statfs                      compat_sys_statfs
158     common  fstatfs                 sys_fstatfs                     compat_sys_fstatfs
159     common  umount                  sys_oldumount
160     common  sched_set_affinity      sys_sched_setaffinity           compat_sys_sched_setaffinity
161     common  sched_get_affinity      sys_sched_getaffinity           compat_sys_sched_getaffinity
162     common  getdomainname           sys_getdomainname
163     common  setdomainname           sys_setdomainname
164     64      utrap_install           sys_utrap_install
165     common  quotactl                sys_quotactl
166     common  set_tid_address         sys_set_tid_address
167     common  mount                   sys_mount
168     common  ustat                   sys_ustat                       compat_sys_ustat
169     common  setxattr                sys_setxattr
170     common  lsetxattr               sys_lsetxattr
171     common  fsetxattr               sys_fsetxattr
172     common  getxattr                sys_getxattr
173     common  lgetxattr               sys_lgetxattr
174     common  getdents                sys_getdents                    compat_sys_getdents
175     common  setsid                  sys_setsid
176     common  fchdir                  sys_fchdir
177     common  fgetxattr               sys_fgetxattr
178     common  listxattr               sys_listxattr
179     common  llistxattr              sys_llistxattr
180     common  flistxattr              sys_flistxattr
181     common  removexattr             sys_removexattr
182     common  lremovexattr            sys_lremovexattr
183     32      sigpending              sys_sigpending                  compat_sys_sigpending
183     64      sigpending              sys_nis_syscall
184     common  query_module            sys_ni_syscall
185     common  setpgid                 sys_setpgid
186     common  fremovexattr            sys_fremovexattr
187     common  tkill                   sys_tkill
188     32      exit_group              sys_exit_group                  sparc_exit_group
188     64      exit_group              sparc_exit_group
189     common  uname                   sys_newuname
190     common  init_module             sys_init_module
191     32      personality             sys_personality                 sys_sparc64_personality
191     64      personality             sys_sparc64_personality
192     32      remap_file_pages        sys_sparc_remap_file_pages      sys_remap_file_pages
192     64      remap_file_pages        sys_remap_file_pages
193     common  epoll_create            sys_epoll_create
194     common  epoll_ctl               sys_epoll_ctl
195     common  epoll_wait              sys_epoll_wait
196     common  ioprio_set              sys_ioprio_set
197     common  getppid                 sys_getppid
198     32      sigaction               sys_sparc_sigaction             compat_sys_sparc_sigaction
198     64      sigaction               sys_nis_syscall
199     common  sgetmask                sys_sgetmask
200     common  ssetmask                sys_ssetmask
201     32      sigsuspend              sys_sigsuspend
201     64      sigsuspend              sys_nis_syscall
202     common  oldlstat                sys_newlstat                    compat_sys_newlstat
203     common  uselib                  sys_uselib
204     32      readdir                 sys_old_readdir                 compat_sys_old_readdir
204     64      readdir                 sys_nis_syscall
205     common  readahead               sys_readahead                   compat_sys_readahead
206     common  socketcall              sys_socketcall                  compat_sys_socketcall
207     common  syslog                  sys_syslog
208     common  lookup_dcookie          sys_ni_syscall
209     common  fadvise64               sys_fadvise64                   compat_sys_fadvise64
210     common  fadvise64_64            sys_fadvise64_64                compat_sys_fadvise64_64
211     common  tgkill                  sys_tgkill
212     common  waitpid                 sys_waitpid
213     common  swapoff                 sys_swapoff
214     common  sysinfo                 sys_sysinfo                     compat_sys_sysinfo
215     32      ipc                     sys_ipc                         compat_sys_ipc
215     64      ipc                     sys_sparc_ipc
216     32      sigreturn               sys_sigreturn                   sys32_sigreturn
216     64      sigreturn               sys_nis_syscall
217     common  clone                   sys_clone
218     common  ioprio_get              sys_ioprio_get
219     32      adjtimex                sys_adjtimex_time32
219     64      adjtimex                sys_sparc_adjtimex
220     32      sigprocmask             sys_sigprocmask                 compat_sys_sigprocmask
220     64      sigprocmask             sys_nis_syscall
221     common  create_module           sys_ni_syscall
222     common  delete_module           sys_delete_module
223     common  get_kernel_syms         sys_ni_syscall
224     common  getpgid                 sys_getpgid
225     common  bdflush                 sys_ni_syscall
226     common  sysfs                   sys_sysfs
227     common  afs_syscall             sys_nis_syscall
228     common  setfsuid                sys_setfsuid16
229     common  setfsgid                sys_setfsgid16
230     common  _newselect              sys_select                      compat_sys_select
231     32      time                    sys_time32
232     common  splice                  sys_splice
233     32      stime                   sys_stime32
233     64      stime                   sys_stime
234     common  statfs64                sys_statfs64                    compat_sys_statfs64
235     common  fstatfs64               sys_fstatfs64                   compat_sys_fstatfs64
236     common  _llseek                 sys_llseek
237     common  mlock                   sys_mlock
238     common  munlock                 sys_munlock
239     common  mlockall                sys_mlockall
240     common  munlockall              sys_munlockall
241     common  sched_setparam          sys_sched_setparam
242     common  sched_getparam          sys_sched_getparam
243     common  sched_setscheduler      sys_sched_setscheduler
244     common  sched_getscheduler      sys_sched_getscheduler
245     common  sched_yield             sys_sched_yield
246     common  sched_get_priority_max  sys_sched_get_priority_max
247     common  sched_get_priority_min  sys_sched_get_priority_min
248     32      sched_rr_get_interval   sys_sched_rr_get_interval_time32
248     64      sched_rr_get_interval   sys_sched_rr_get_interval
249     32      nanosleep               sys_nanosleep_time32
249     64      nanosleep               sys_nanosleep
250     32      mremap                  sys_mremap
250     64      mremap                  sys_64_mremap
251     common  _sysctl                 sys_ni_syscall
252     common  getsid                  sys_getsid
253     common  fdatasync               sys_fdatasync
254     32      nfsservctl              sys_ni_syscall                  sys_nis_syscall
254     64      nfsservctl              sys_nis_syscall
255     common  sync_file_range         sys_sync_file_range             compat_sys_sync_file_range
256     32      clock_settime           sys_clock_settime32
256     64      clock_settime           sys_clock_settime
257     32      clock_gettime           sys_clock_gettime32
257     64      clock_gettime           sys_clock_gettime
258     32      clock_getres            sys_clock_getres_time32
258     64      clock_getres            sys_clock_getres
259     32      clock_nanosleep         sys_clock_nanosleep_time32
259     64      clock_nanosleep         sys_clock_nanosleep
260     common  sched_getaffinity       sys_sched_getaffinity           compat_sys_sched_getaffinity
261     common  sched_setaffinity       sys_sched_setaffinity           compat_sys_sched_setaffinity
262     32      timer_settime           sys_timer_settime32
262     64      timer_settime           sys_timer_settime
263     32      timer_gettime           sys_timer_gettime32
263     64      timer_gettime           sys_timer_gettime
264     common  timer_getoverrun        sys_timer_getoverrun
265     common  timer_delete            sys_timer_delete
266     common  timer_create            sys_timer_create                compat_sys_timer_create
# 267 was vserver
267     common  vserver                 sys_nis_syscall
268     common  io_setup                sys_io_setup                    compat_sys_io_setup
269     common  io_destroy              sys_io_destroy
270     common  io_submit               sys_io_submit                   compat_sys_io_submit
271     common  io_cancel               sys_io_cancel
272     32      io_getevents            sys_io_getevents_time32
272     64      io_getevents            sys_io_getevents
273     common  mq_open                 sys_mq_open                     compat_sys_mq_open
274     common  mq_unlink               sys_mq_unlink
275     32      mq_timedsend            sys_mq_timedsend_time32
275     64      mq_timedsend            sys_mq_timedsend
276     32      mq_timedreceive         sys_mq_timedreceive_time32
276     64      mq_timedreceive         sys_mq_timedreceive
277     common  mq_notify               sys_mq_notify                   compat_sys_mq_notify
278     common  mq_getsetattr           sys_mq_getsetattr               compat_sys_mq_getsetattr
279     common  waitid                  sys_waitid                      compat_sys_waitid
280     common  tee                     sys_tee
281     common  add_key                 sys_add_key
282     common  request_key             sys_request_key
283     common  keyctl                  sys_keyctl                      compat_sys_keyctl
284     common  openat                  sys_openat                      compat_sys_openat
285     common  mkdirat                 sys_mkdirat
286     common  mknodat                 sys_mknodat
287     common  fchownat                sys_fchownat
288     32      futimesat               sys_futimesat_time32
288     64      futimesat               sys_futimesat
289     common  fstatat64               sys_fstatat64                   compat_sys_fstatat64
290     common  unlinkat                sys_unlinkat
291     common  renameat                sys_renameat
292     common  linkat                  sys_linkat
293     common  symlinkat               sys_symlinkat
294     common  readlinkat              sys_readlinkat
295     common  fchmodat                sys_fchmodat
296     common  faccessat               sys_faccessat
297     32      pselect6                sys_pselect6_time32             compat_sys_pselect6_time32
297     64      pselect6                sys_pselect6
298     32      ppoll                   sys_ppoll_time32                compat_sys_ppoll_time32
298     64      ppoll                   sys_ppoll
299     common  unshare                 sys_unshare
300     common  set_robust_list         sys_set_robust_list             compat_sys_set_robust_list
301     common  get_robust_list         sys_get_robust_list             compat_sys_get_robust_list
302     common  migrate_pages           sys_migrate_pages
303     common  mbind                   sys_mbind
304     common  get_mempolicy           sys_get_mempolicy
305     common  set_mempolicy           sys_set_mempolicy
306     common  kexec_load              sys_kexec_load                  compat_sys_kexec_load
307     common  move_pages              sys_move_pages
308     common  getcpu                  sys_getcpu
309     common  epoll_pwait             sys_epoll_pwait                 compat_sys_epoll_pwait
310     32      utimensat               sys_utimensat_time32
310     64      utimensat               sys_utimensat
311     common  signalfd                sys_signalfd                    compat_sys_signalfd
312     common  timerfd_create          sys_timerfd_create
313     common  eventfd                 sys_eventfd
314     common  fallocate               sys_fallocate                   compat_sys_fallocate
315     32      timerfd_settime         sys_timerfd_settime32
315     64      timerfd_settime         sys_timerfd_settime
316     32      timerfd_gettime         sys_timerfd_gettime32
316     64      timerfd_gettime         sys_timerfd_gettime
317     common  signalfd4               sys_signalfd4                   compat_sys_signalfd4
318     common  eventfd2                sys_eventfd2
319     common  epoll_create1           sys_epoll_create1
320     common  dup3                    sys_dup3
321     common  pipe2                   sys_pipe2
322     common  inotify_init1           sys_inotify_init1
323     common  accept4                 sys_accept4
324     common  preadv                  sys_preadv                      compat_sys_preadv
325     common  pwritev                 sys_pwritev                     compat_sys_pwritev
326     common  rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo           compat_sys_rt_tgsigqueueinfo
327     common  perf_event_open         sys_perf_event_open
328     32      recvmmsg                sys_recvmmsg_time32             compat_sys_recvmmsg_time32
328     64      recvmmsg                sys_recvmmsg
329     common  fanotify_init           sys_fanotify_init
330     common  fanotify_mark           sys_fanotify_mark               compat_sys_fanotify_mark
331     common  prlimit64               sys_prlimit64
332     common  name_to_handle_at       sys_name_to_handle_at
333     common  open_by_handle_at       sys_open_by_handle_at           compat_sys_open_by_handle_at
334     32      clock_adjtime           sys_clock_adjtime32
334     64      clock_adjtime           sys_sparc_clock_adjtime
335     common  syncfs                  sys_syncfs
336     common  sendmmsg                sys_sendmmsg                    compat_sys_sendmmsg
337     common  setns                   sys_setns
338     common  process_vm_readv        sys_process_vm_readv
339     common  process_vm_writev       sys_process_vm_writev
340     32      kern_features           sys_ni_syscall                  sys_kern_features
340     64      kern_features           sys_kern_features
341     common  kcmp                    sys_kcmp
342     common  finit_module            sys_finit_module
343     common  sched_setattr           sys_sched_setattr
344     common  sched_getattr           sys_sched_getattr
345     common  renameat2               sys_renameat2
346     common  seccomp                 sys_seccomp
347     common  getrandom               sys_getrandom
348     common  memfd_create            sys_memfd_create
349     common  bpf                     sys_bpf
350     32      execveat                sys_execveat                    sys32_execveat
350     64      execveat                sys64_execveat
351     common  membarrier              sys_membarrier
352     common  userfaultfd             sys_userfaultfd
353     common  bind                    sys_bind
354     common  listen                  sys_listen
355     common  setsockopt              sys_setsockopt                  sys_setsockopt
356     common  mlock2                  sys_mlock2
357     common  copy_file_range         sys_copy_file_range
358     common  preadv2                 sys_preadv2                     compat_sys_preadv2
359     common  pwritev2                sys_pwritev2                    compat_sys_pwritev2
360     common  statx                   sys_statx
361     32      io_pgetevents           sys_io_pgetevents_time32        compat_sys_io_pgetevents
361     64      io_pgetevents           sys_io_pgetevents
362     common  pkey_mprotect           sys_pkey_mprotect
363     common  pkey_alloc              sys_pkey_alloc
364     common  pkey_free               sys_pkey_free
365     common  rseq                    sys_rseq
# room for arch specific syscalls
392     64      semtimedop                      sys_semtimedop
393     common  semget                  sys_semget
394     common  semctl                  sys_semctl                      compat_sys_semctl
395     common  shmget                  sys_shmget
396     common  shmctl                  sys_shmctl                      compat_sys_shmctl
397     common  shmat                   sys_shmat                       compat_sys_shmat
398     common  shmdt                   sys_shmdt
399     common  msgget                  sys_msgget
400     common  msgsnd                  sys_msgsnd                      compat_sys_msgsnd
401     common  msgrcv                  sys_msgrcv                      compat_sys_msgrcv
402     common  msgctl                  sys_msgctl                      compat_sys_msgctl
403     32      clock_gettime64                 sys_clock_gettime               sys_clock_gettime
404     32      clock_settime64                 sys_clock_settime               sys_clock_settime
405     32      clock_adjtime64                 sys_clock_adjtime               sys_clock_adjtime
406     32      clock_getres_time64             sys_clock_getres                sys_clock_getres
407     32      clock_nanosleep_time64          sys_clock_nanosleep             sys_clock_nanosleep
408     32      timer_gettime64                 sys_timer_gettime               sys_timer_gettime
409     32      timer_settime64                 sys_timer_settime               sys_timer_settime
410     32      timerfd_gettime64               sys_timerfd_gettime             sys_timerfd_gettime
411     32      timerfd_settime64               sys_timerfd_settime             sys_timerfd_settime
412     32      utimensat_time64                sys_utimensat                   sys_utimensat
413     32      pselect6_time64                 sys_pselect6                    compat_sys_pselect6_time64
414     32      ppoll_time64                    sys_ppoll                       compat_sys_ppoll_time64
416     32      io_pgetevents_time64            sys_io_pgetevents               compat_sys_io_pgetevents_time64
417     32      recvmmsg_time64                 sys_recvmmsg                    compat_sys_recvmmsg_time64
418     32      mq_timedsend_time64             sys_mq_timedsend                sys_mq_timedsend
419     32      mq_timedreceive_time64          sys_mq_timedreceive             sys_mq_timedreceive
420     32      semtimedop_time64               sys_semtimedop                  sys_semtimedop
421     32      rt_sigtimedwait_time64          sys_rt_sigtimedwait             compat_sys_rt_sigtimedwait_time64
422     32      futex_time64                    sys_futex                       sys_futex
423     32      sched_rr_get_interval_time64    sys_sched_rr_get_interval       sys_sched_rr_get_interval
424     common  pidfd_send_signal               sys_pidfd_send_signal
425     common  io_uring_setup                  sys_io_uring_setup
426     common  io_uring_enter                  sys_io_uring_enter
427     common  io_uring_register               sys_io_uring_register
428     common  open_tree                       sys_open_tree
429     common  move_mount                      sys_move_mount
430     common  fsopen                          sys_fsopen
431     common  fsconfig                        sys_fsconfig
432     common  fsmount                         sys_fsmount
433     common  fspick                          sys_fspick
434     common  pidfd_open                      sys_pidfd_open
# 435 reserved for clone3
436     common  close_range                     sys_close_range
437     common  openat2                 sys_openat2
438     common  pidfd_getfd                     sys_pidfd_getfd
439     common  faccessat2                      sys_faccessat2
440     common  process_madvise                 sys_process_madvise
441     common  epoll_pwait2                    sys_epoll_pwait2                compat_sys_epoll_pwait2
442     common  mount_setattr                   sys_mount_setattr
443     common  quotactl_fd                     sys_quotactl_fd
444     common  landlock_create_ruleset         sys_landlock_create_ruleset
445     common  landlock_add_rule               sys_landlock_add_rule
446     common  landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     common  process_mrelease                sys_process_mrelease
449     common  futex_waitv                     sys_futex_waitv
450     common  set_mempolicy_home_node         sys_set_mempolicy_home_node
451     common  cachestat                       sys_cachestat
452     common  fchmodat2                       sys_fchmodat2
453     common  map_shadow_stack                sys_map_shadow_stack
454     common  futex_wake                      sys_futex_wake
455     common  futex_wait                      sys_futex_wait
456     common  futex_requeue                   sys_futex_requeue
457     common  statmount                       sys_statmount
458     common  listmount                       sys_listmount
459     common  lsm_get_self_attr               sys_lsm_get_self_attr
460     common  lsm_set_self_attr               sys_lsm_set_self_attr
461     common  lsm_list_modules                sys_lsm_list_modules
462     common  mseal                           sys_mseal
"""


# RISCV64
#
# [How to make]
# gcc -I `pwd`/include/uapi/ -E -D__SYSCALL=SYSCALL arch/riscv/include/uapi/asm/unistd.h \
# | grep ^SYSCALL | sed -e 's/SYSCALL(//;s/[,)]//g;/+/d' > /tmp/a
# grep -oP "__NR\S+\s+\d+$" include/uapi/asm-generic/unistd.h | grep -v __NR_sync_file_range2 > /tmp/b
# join -2 2 -o 1.1,1.10,2.1,1.2 -e riscv64 /tmp/a /tmp/b | sed -e 's/\(__NR_\|__NR3264_\)//g' | column -t
#
riscv64_syscall_tbl = """
0    riscv64  io_setup                 sys_io_setup
1    riscv64  io_destroy               sys_io_destroy
2    riscv64  io_submit                sys_io_submit
3    riscv64  io_cancel                sys_io_cancel
4    riscv64  io_getevents             sys_io_getevents
5    riscv64  setxattr                 sys_setxattr
6    riscv64  lsetxattr                sys_lsetxattr
7    riscv64  fsetxattr                sys_fsetxattr
8    riscv64  getxattr                 sys_getxattr
9    riscv64  lgetxattr                sys_lgetxattr
10   riscv64  fgetxattr                sys_fgetxattr
11   riscv64  listxattr                sys_listxattr
12   riscv64  llistxattr               sys_llistxattr
13   riscv64  flistxattr               sys_flistxattr
14   riscv64  removexattr              sys_removexattr
15   riscv64  lremovexattr             sys_lremovexattr
16   riscv64  fremovexattr             sys_fremovexattr
17   riscv64  getcwd                   sys_getcwd
18   riscv64  lookup_dcookie           sys_ni_syscall
19   riscv64  eventfd2                 sys_eventfd2
20   riscv64  epoll_create1            sys_epoll_create1
21   riscv64  epoll_ctl                sys_epoll_ctl
22   riscv64  epoll_pwait              sys_epoll_pwait
23   riscv64  dup                      sys_dup
24   riscv64  dup3                     sys_dup3
25   riscv64  fcntl                    sys_fcntl
26   riscv64  inotify_init1            sys_inotify_init1
27   riscv64  inotify_add_watch        sys_inotify_add_watch
28   riscv64  inotify_rm_watch         sys_inotify_rm_watch
29   riscv64  ioctl                    sys_ioctl
30   riscv64  ioprio_set               sys_ioprio_set
31   riscv64  ioprio_get               sys_ioprio_get
32   riscv64  flock                    sys_flock
33   riscv64  mknodat                  sys_mknodat
34   riscv64  mkdirat                  sys_mkdirat
35   riscv64  unlinkat                 sys_unlinkat
36   riscv64  symlinkat                sys_symlinkat
37   riscv64  linkat                   sys_linkat
39   riscv64  umount2                  sys_umount
40   riscv64  mount                    sys_mount
41   riscv64  pivot_root               sys_pivot_root
42   riscv64  nfsservctl               sys_ni_syscall
43   riscv64  statfs                   sys_statfs
44   riscv64  fstatfs                  sys_fstatfs
45   riscv64  truncate                 sys_truncate
46   riscv64  ftruncate                sys_ftruncate
47   riscv64  fallocate                sys_fallocate
48   riscv64  faccessat                sys_faccessat
49   riscv64  chdir                    sys_chdir
50   riscv64  fchdir                   sys_fchdir
51   riscv64  chroot                   sys_chroot
52   riscv64  fchmod                   sys_fchmod
53   riscv64  fchmodat                 sys_fchmodat
54   riscv64  fchownat                 sys_fchownat
55   riscv64  fchown                   sys_fchown
56   riscv64  openat                   sys_openat
57   riscv64  close                    sys_close
58   riscv64  vhangup                  sys_vhangup
59   riscv64  pipe2                    sys_pipe2
60   riscv64  quotactl                 sys_quotactl
61   riscv64  getdents64               sys_getdents64
62   riscv64  lseek                    sys_lseek
63   riscv64  read                     sys_read
64   riscv64  write                    sys_write
65   riscv64  readv                    sys_readv
66   riscv64  writev                   sys_writev
67   riscv64  pread64                  sys_pread64
68   riscv64  pwrite64                 sys_pwrite64
69   riscv64  preadv                   sys_preadv
70   riscv64  pwritev                  sys_pwritev
71   riscv64  sendfile                 sys_sendfile64
72   riscv64  pselect6                 sys_pselect6
73   riscv64  ppoll                    sys_ppoll
74   riscv64  signalfd4                sys_signalfd4
75   riscv64  vmsplice                 sys_vmsplice
76   riscv64  splice                   sys_splice
77   riscv64  tee                      sys_tee
78   riscv64  readlinkat               sys_readlinkat
79   riscv64  fstatat                  sys_newfstatat
80   riscv64  fstat                    sys_newfstat
81   riscv64  sync                     sys_sync
82   riscv64  fsync                    sys_fsync
83   riscv64  fdatasync                sys_fdatasync
84   riscv64  sync_file_range          sys_sync_file_range
85   riscv64  timerfd_create           sys_timerfd_create
86   riscv64  timerfd_settime          sys_timerfd_settime
87   riscv64  timerfd_gettime          sys_timerfd_gettime
88   riscv64  utimensat                sys_utimensat
89   riscv64  acct                     sys_acct
90   riscv64  capget                   sys_capget
91   riscv64  capset                   sys_capset
92   riscv64  personality              sys_personality
93   riscv64  exit                     sys_exit
94   riscv64  exit_group               sys_exit_group
95   riscv64  waitid                   sys_waitid
96   riscv64  set_tid_address          sys_set_tid_address
97   riscv64  unshare                  sys_unshare
98   riscv64  futex                    sys_futex
99   riscv64  set_robust_list          sys_set_robust_list
100  riscv64  get_robust_list          sys_get_robust_list
101  riscv64  nanosleep                sys_nanosleep
102  riscv64  getitimer                sys_getitimer
103  riscv64  setitimer                sys_setitimer
104  riscv64  kexec_load               sys_kexec_load
105  riscv64  init_module              sys_init_module
106  riscv64  delete_module            sys_delete_module
107  riscv64  timer_create             sys_timer_create
108  riscv64  timer_gettime            sys_timer_gettime
109  riscv64  timer_getoverrun         sys_timer_getoverrun
110  riscv64  timer_settime            sys_timer_settime
111  riscv64  timer_delete             sys_timer_delete
112  riscv64  clock_settime            sys_clock_settime
113  riscv64  clock_gettime            sys_clock_gettime
114  riscv64  clock_getres             sys_clock_getres
115  riscv64  clock_nanosleep          sys_clock_nanosleep
116  riscv64  syslog                   sys_syslog
117  riscv64  ptrace                   sys_ptrace
118  riscv64  sched_setparam           sys_sched_setparam
119  riscv64  sched_setscheduler       sys_sched_setscheduler
120  riscv64  sched_getscheduler       sys_sched_getscheduler
121  riscv64  sched_getparam           sys_sched_getparam
122  riscv64  sched_setaffinity        sys_sched_setaffinity
123  riscv64  sched_getaffinity        sys_sched_getaffinity
124  riscv64  sched_yield              sys_sched_yield
125  riscv64  sched_get_priority_max   sys_sched_get_priority_max
126  riscv64  sched_get_priority_min   sys_sched_get_priority_min
127  riscv64  sched_rr_get_interval    sys_sched_rr_get_interval
128  riscv64  restart_syscall          sys_restart_syscall
129  riscv64  kill                     sys_kill
130  riscv64  tkill                    sys_tkill
131  riscv64  tgkill                   sys_tgkill
132  riscv64  sigaltstack              sys_sigaltstack
133  riscv64  rt_sigsuspend            sys_rt_sigsuspend
134  riscv64  rt_sigaction             sys_rt_sigaction
135  riscv64  rt_sigprocmask           sys_rt_sigprocmask
136  riscv64  rt_sigpending            sys_rt_sigpending
137  riscv64  rt_sigtimedwait          sys_rt_sigtimedwait
138  riscv64  rt_sigqueueinfo          sys_rt_sigqueueinfo
139  riscv64  rt_sigreturn             sys_rt_sigreturn
140  riscv64  setpriority              sys_setpriority
141  riscv64  getpriority              sys_getpriority
142  riscv64  reboot                   sys_reboot
143  riscv64  setregid                 sys_setregid
144  riscv64  setgid                   sys_setgid
145  riscv64  setreuid                 sys_setreuid
146  riscv64  setuid                   sys_setuid
147  riscv64  setresuid                sys_setresuid
148  riscv64  getresuid                sys_getresuid
149  riscv64  setresgid                sys_setresgid
150  riscv64  getresgid                sys_getresgid
151  riscv64  setfsuid                 sys_setfsuid
152  riscv64  setfsgid                 sys_setfsgid
153  riscv64  times                    sys_times
154  riscv64  setpgid                  sys_setpgid
155  riscv64  getpgid                  sys_getpgid
156  riscv64  getsid                   sys_getsid
157  riscv64  setsid                   sys_setsid
158  riscv64  getgroups                sys_getgroups
159  riscv64  setgroups                sys_setgroups
160  riscv64  uname                    sys_newuname
161  riscv64  sethostname              sys_sethostname
162  riscv64  setdomainname            sys_setdomainname
163  riscv64  getrlimit                sys_getrlimit
164  riscv64  setrlimit                sys_setrlimit
165  riscv64  getrusage                sys_getrusage
166  riscv64  umask                    sys_umask
167  riscv64  prctl                    sys_prctl
168  riscv64  getcpu                   sys_getcpu
169  riscv64  gettimeofday             sys_gettimeofday
170  riscv64  settimeofday             sys_settimeofday
171  riscv64  adjtimex                 sys_adjtimex
172  riscv64  getpid                   sys_getpid
173  riscv64  getppid                  sys_getppid
174  riscv64  getuid                   sys_getuid
175  riscv64  geteuid                  sys_geteuid
176  riscv64  getgid                   sys_getgid
177  riscv64  getegid                  sys_getegid
178  riscv64  gettid                   sys_gettid
179  riscv64  sysinfo                  sys_sysinfo
180  riscv64  mq_open                  sys_mq_open
181  riscv64  mq_unlink                sys_mq_unlink
182  riscv64  mq_timedsend             sys_mq_timedsend
183  riscv64  mq_timedreceive          sys_mq_timedreceive
184  riscv64  mq_notify                sys_mq_notify
185  riscv64  mq_getsetattr            sys_mq_getsetattr
186  riscv64  msgget                   sys_msgget
187  riscv64  msgctl                   sys_msgctl
188  riscv64  msgrcv                   sys_msgrcv
189  riscv64  msgsnd                   sys_msgsnd
190  riscv64  semget                   sys_semget
191  riscv64  semctl                   sys_semctl
192  riscv64  semtimedop               sys_semtimedop
193  riscv64  semop                    sys_semop
194  riscv64  shmget                   sys_shmget
195  riscv64  shmctl                   sys_shmctl
196  riscv64  shmat                    sys_shmat
197  riscv64  shmdt                    sys_shmdt
198  riscv64  socket                   sys_socket
199  riscv64  socketpair               sys_socketpair
200  riscv64  bind                     sys_bind
201  riscv64  listen                   sys_listen
202  riscv64  accept                   sys_accept
203  riscv64  connect                  sys_connect
204  riscv64  getsockname              sys_getsockname
205  riscv64  getpeername              sys_getpeername
206  riscv64  sendto                   sys_sendto
207  riscv64  recvfrom                 sys_recvfrom
208  riscv64  setsockopt               sys_setsockopt
209  riscv64  getsockopt               sys_getsockopt
210  riscv64  shutdown                 sys_shutdown
211  riscv64  sendmsg                  sys_sendmsg
212  riscv64  recvmsg                  sys_recvmsg
213  riscv64  readahead                sys_readahead
214  riscv64  brk                      sys_brk
215  riscv64  munmap                   sys_munmap
216  riscv64  mremap                   sys_mremap
217  riscv64  add_key                  sys_add_key
218  riscv64  request_key              sys_request_key
219  riscv64  keyctl                   sys_keyctl
220  riscv64  clone                    sys_clone
221  riscv64  execve                   sys_execve
222  riscv64  mmap                     sys_mmap
223  riscv64  fadvise64                sys_fadvise64_64
224  riscv64  swapon                   sys_swapon
225  riscv64  swapoff                  sys_swapoff
226  riscv64  mprotect                 sys_mprotect
227  riscv64  msync                    sys_msync
228  riscv64  mlock                    sys_mlock
229  riscv64  munlock                  sys_munlock
230  riscv64  mlockall                 sys_mlockall
231  riscv64  munlockall               sys_munlockall
232  riscv64  mincore                  sys_mincore
233  riscv64  madvise                  sys_madvise
234  riscv64  remap_file_pages         sys_remap_file_pages
235  riscv64  mbind                    sys_mbind
236  riscv64  get_mempolicy            sys_get_mempolicy
237  riscv64  set_mempolicy            sys_set_mempolicy
238  riscv64  migrate_pages            sys_migrate_pages
239  riscv64  move_pages               sys_move_pages
240  riscv64  rt_tgsigqueueinfo        sys_rt_tgsigqueueinfo
241  riscv64  perf_event_open          sys_perf_event_open
242  riscv64  accept4                  sys_accept4
243  riscv64  recvmmsg                 sys_recvmmsg
260  riscv64  wait4                    sys_wait4
261  riscv64  prlimit64                sys_prlimit64
262  riscv64  fanotify_init            sys_fanotify_init
263  riscv64  fanotify_mark            sys_fanotify_mark
264  riscv64  name_to_handle_at        sys_name_to_handle_at
265  riscv64  open_by_handle_at        sys_open_by_handle_at
266  riscv64  clock_adjtime            sys_clock_adjtime
267  riscv64  syncfs                   sys_syncfs
268  riscv64  setns                    sys_setns
269  riscv64  sendmmsg                 sys_sendmmsg
270  riscv64  process_vm_readv         sys_process_vm_readv
271  riscv64  process_vm_writev        sys_process_vm_writev
272  riscv64  kcmp                     sys_kcmp
273  riscv64  finit_module             sys_finit_module
274  riscv64  sched_setattr            sys_sched_setattr
275  riscv64  sched_getattr            sys_sched_getattr
276  riscv64  renameat2                sys_renameat2
277  riscv64  seccomp                  sys_seccomp
278  riscv64  getrandom                sys_getrandom
279  riscv64  memfd_create             sys_memfd_create
280  riscv64  bpf                      sys_bpf
281  riscv64  execveat                 sys_execveat
282  riscv64  userfaultfd              sys_userfaultfd
283  riscv64  membarrier               sys_membarrier
284  riscv64  mlock2                   sys_mlock2
285  riscv64  copy_file_range          sys_copy_file_range
286  riscv64  preadv2                  sys_preadv2
287  riscv64  pwritev2                 sys_pwritev2
288  riscv64  pkey_mprotect            sys_pkey_mprotect
289  riscv64  pkey_alloc               sys_pkey_alloc
290  riscv64  pkey_free                sys_pkey_free
291  riscv64  statx                    sys_statx
292  riscv64  io_pgetevents            sys_io_pgetevents
293  riscv64  rseq                     sys_rseq
294  riscv64  kexec_file_load          sys_kexec_file_load
424  riscv64  pidfd_send_signal        sys_pidfd_send_signal
425  riscv64  io_uring_setup           sys_io_uring_setup
426  riscv64  io_uring_enter           sys_io_uring_enter
427  riscv64  io_uring_register        sys_io_uring_register
428  riscv64  open_tree                sys_open_tree
429  riscv64  move_mount               sys_move_mount
430  riscv64  fsopen                   sys_fsopen
431  riscv64  fsconfig                 sys_fsconfig
432  riscv64  fsmount                  sys_fsmount
433  riscv64  fspick                   sys_fspick
434  riscv64  pidfd_open               sys_pidfd_open
435  riscv64  clone3                   sys_clone3
436  riscv64  close_range              sys_close_range
437  riscv64  openat2                  sys_openat2
438  riscv64  pidfd_getfd              sys_pidfd_getfd
439  riscv64  faccessat2               sys_faccessat2
440  riscv64  process_madvise          sys_process_madvise
441  riscv64  epoll_pwait2             sys_epoll_pwait2
442  riscv64  mount_setattr            sys_mount_setattr
443  riscv64  quotactl_fd              sys_quotactl_fd
444  riscv64  landlock_create_ruleset  sys_landlock_create_ruleset
445  riscv64  landlock_add_rule        sys_landlock_add_rule
446  riscv64  landlock_restrict_self   sys_landlock_restrict_self
447  riscv64  memfd_secret             sys_memfd_secret
448  riscv64  process_mrelease         sys_process_mrelease
449  riscv64  futex_waitv              sys_futex_waitv
450  riscv64  set_mempolicy_home_node  sys_set_mempolicy_home_node
451  riscv64  cachestat                sys_cachestat
452  riscv64  fchmodat2                sys_fchmodat2
453  riscv64  map_shadow_stack         sys_map_shadow_stack
454  riscv64  futex_wake               sys_futex_wake
455  riscv64  futex_wait               sys_futex_wait
456  riscv64  futex_requeue            sys_futex_requeue
457  riscv64  statmount                sys_statmount
458  riscv64  listmount                sys_listmount
459  riscv64  lsm_get_self_attr        sys_lsm_get_self_attr
460  riscv64  lsm_set_self_attr        sys_lsm_set_self_attr
461  riscv64  lsm_list_modules         sys_lsm_list_modules
462  riscv64  mseal                    sys_mseal
"""


# RISCV32
#
# [How to make]
# gcc -I `pwd`/include/uapi/ -E -D__SYSCALL=SYSCALL -D__BITS_PER_LONG=32 -D__ILP32__=1 arch/riscv/include/uapi/asm/unistd.h \
# | grep ^SYSCALL | sed -e 's/SYSCALL(//;s/[,)]//g;/+/d' > /tmp/a
# grep -oP "__NR\S+\s+\d+$" include/uapi/asm-generic/unistd.h | grep -v __NR_sync_file_range2 > /tmp/b
# join -2 2 -o 1.1,1.10,2.1,1.2 -e riscv32 /tmp/a /tmp/b | sed -e 's/\(__NR_\|__NR3264_\)//g' | column -t
#
riscv32_syscall_tbl = """
0    riscv32  io_setup                      sys_io_setup
1    riscv32  io_destroy                    sys_io_destroy
2    riscv32  io_submit                     sys_io_submit
3    riscv32  io_cancel                     sys_io_cancel
5    riscv32  setxattr                      sys_setxattr
6    riscv32  lsetxattr                     sys_lsetxattr
7    riscv32  fsetxattr                     sys_fsetxattr
8    riscv32  getxattr                      sys_getxattr
9    riscv32  lgetxattr                     sys_lgetxattr
10   riscv32  fgetxattr                     sys_fgetxattr
11   riscv32  listxattr                     sys_listxattr
12   riscv32  llistxattr                    sys_llistxattr
13   riscv32  flistxattr                    sys_flistxattr
14   riscv32  removexattr                   sys_removexattr
15   riscv32  lremovexattr                  sys_lremovexattr
16   riscv32  fremovexattr                  sys_fremovexattr
17   riscv32  getcwd                        sys_getcwd
18   riscv32  lookup_dcookie                sys_ni_syscall
19   riscv32  eventfd2                      sys_eventfd2
20   riscv32  epoll_create1                 sys_epoll_create1
21   riscv32  epoll_ctl                     sys_epoll_ctl
22   riscv32  epoll_pwait                   sys_epoll_pwait
23   riscv32  dup                           sys_dup
24   riscv32  dup3                          sys_dup3
25   riscv32  fcntl                         sys_fcntl64
26   riscv32  inotify_init1                 sys_inotify_init1
27   riscv32  inotify_add_watch             sys_inotify_add_watch
28   riscv32  inotify_rm_watch              sys_inotify_rm_watch
29   riscv32  ioctl                         sys_ioctl
30   riscv32  ioprio_set                    sys_ioprio_set
31   riscv32  ioprio_get                    sys_ioprio_get
32   riscv32  flock                         sys_flock
33   riscv32  mknodat                       sys_mknodat
34   riscv32  mkdirat                       sys_mkdirat
35   riscv32  unlinkat                      sys_unlinkat
36   riscv32  symlinkat                     sys_symlinkat
37   riscv32  linkat                        sys_linkat
39   riscv32  umount2                       sys_umount
40   riscv32  mount                         sys_mount
41   riscv32  pivot_root                    sys_pivot_root
42   riscv32  nfsservctl                    sys_ni_syscall
43   riscv32  statfs                        sys_statfs64
44   riscv32  fstatfs                       sys_fstatfs64
45   riscv32  truncate                      sys_truncate64
46   riscv32  ftruncate                     sys_ftruncate64
47   riscv32  fallocate                     sys_fallocate
48   riscv32  faccessat                     sys_faccessat
49   riscv32  chdir                         sys_chdir
50   riscv32  fchdir                        sys_fchdir
51   riscv32  chroot                        sys_chroot
52   riscv32  fchmod                        sys_fchmod
53   riscv32  fchmodat                      sys_fchmodat
54   riscv32  fchownat                      sys_fchownat
55   riscv32  fchown                        sys_fchown
56   riscv32  openat                        sys_openat
57   riscv32  close                         sys_close
58   riscv32  vhangup                       sys_vhangup
59   riscv32  pipe2                         sys_pipe2
60   riscv32  quotactl                      sys_quotactl
61   riscv32  getdents64                    sys_getdents64
62   riscv32  lseek                         sys_llseek
63   riscv32  read                          sys_read
64   riscv32  write                         sys_write
65   riscv32  readv                         sys_readv
66   riscv32  writev                        sys_writev
67   riscv32  pread64                       sys_pread64
68   riscv32  pwrite64                      sys_pwrite64
69   riscv32  preadv                        sys_preadv
70   riscv32  pwritev                       sys_pwritev
71   riscv32  sendfile                      sys_sendfile64
74   riscv32  signalfd4                     sys_signalfd4
75   riscv32  vmsplice                      sys_vmsplice
76   riscv32  splice                        sys_splice
77   riscv32  tee                           sys_tee
78   riscv32  readlinkat                    sys_readlinkat
79   riscv32  fstatat                       sys_fstatat64
80   riscv32  fstat                         sys_fstat64
81   riscv32  sync                          sys_sync
82   riscv32  fsync                         sys_fsync
83   riscv32  fdatasync                     sys_fdatasync
84   riscv32  sync_file_range               sys_sync_file_range
85   riscv32  timerfd_create                sys_timerfd_create
89   riscv32  acct                          sys_acct
90   riscv32  capget                        sys_capget
91   riscv32  capset                        sys_capset
92   riscv32  personality                   sys_personality
93   riscv32  exit                          sys_exit
94   riscv32  exit_group                    sys_exit_group
95   riscv32  waitid                        sys_waitid
96   riscv32  set_tid_address               sys_set_tid_address
97   riscv32  unshare                       sys_unshare
99   riscv32  set_robust_list               sys_set_robust_list
100  riscv32  get_robust_list               sys_get_robust_list
102  riscv32  getitimer                     sys_getitimer
103  riscv32  setitimer                     sys_setitimer
104  riscv32  kexec_load                    sys_kexec_load
105  riscv32  init_module                   sys_init_module
106  riscv32  delete_module                 sys_delete_module
107  riscv32  timer_create                  sys_timer_create
109  riscv32  timer_getoverrun              sys_timer_getoverrun
111  riscv32  timer_delete                  sys_timer_delete
116  riscv32  syslog                        sys_syslog
117  riscv32  ptrace                        sys_ptrace
118  riscv32  sched_setparam                sys_sched_setparam
119  riscv32  sched_setscheduler            sys_sched_setscheduler
120  riscv32  sched_getscheduler            sys_sched_getscheduler
121  riscv32  sched_getparam                sys_sched_getparam
122  riscv32  sched_setaffinity             sys_sched_setaffinity
123  riscv32  sched_getaffinity             sys_sched_getaffinity
124  riscv32  sched_yield                   sys_sched_yield
125  riscv32  sched_get_priority_max        sys_sched_get_priority_max
126  riscv32  sched_get_priority_min        sys_sched_get_priority_min
128  riscv32  restart_syscall               sys_restart_syscall
129  riscv32  kill                          sys_kill
130  riscv32  tkill                         sys_tkill
131  riscv32  tgkill                        sys_tgkill
132  riscv32  sigaltstack                   sys_sigaltstack
133  riscv32  rt_sigsuspend                 sys_rt_sigsuspend
134  riscv32  rt_sigaction                  sys_rt_sigaction
135  riscv32  rt_sigprocmask                sys_rt_sigprocmask
136  riscv32  rt_sigpending                 sys_rt_sigpending
138  riscv32  rt_sigqueueinfo               sys_rt_sigqueueinfo
139  riscv32  rt_sigreturn                  sys_rt_sigreturn
140  riscv32  setpriority                   sys_setpriority
141  riscv32  getpriority                   sys_getpriority
142  riscv32  reboot                        sys_reboot
143  riscv32  setregid                      sys_setregid
144  riscv32  setgid                        sys_setgid
145  riscv32  setreuid                      sys_setreuid
146  riscv32  setuid                        sys_setuid
147  riscv32  setresuid                     sys_setresuid
148  riscv32  getresuid                     sys_getresuid
149  riscv32  setresgid                     sys_setresgid
150  riscv32  getresgid                     sys_getresgid
151  riscv32  setfsuid                      sys_setfsuid
152  riscv32  setfsgid                      sys_setfsgid
153  riscv32  times                         sys_times
154  riscv32  setpgid                       sys_setpgid
155  riscv32  getpgid                       sys_getpgid
156  riscv32  getsid                        sys_getsid
157  riscv32  setsid                        sys_setsid
158  riscv32  getgroups                     sys_getgroups
159  riscv32  setgroups                     sys_setgroups
160  riscv32  uname                         sys_newuname
161  riscv32  sethostname                   sys_sethostname
162  riscv32  setdomainname                 sys_setdomainname
163  riscv32  getrlimit                     sys_getrlimit
164  riscv32  setrlimit                     sys_setrlimit
165  riscv32  getrusage                     sys_getrusage
166  riscv32  umask                         sys_umask
167  riscv32  prctl                         sys_prctl
168  riscv32  getcpu                        sys_getcpu
172  riscv32  getpid                        sys_getpid
173  riscv32  getppid                       sys_getppid
174  riscv32  getuid                        sys_getuid
175  riscv32  geteuid                       sys_geteuid
176  riscv32  getgid                        sys_getgid
177  riscv32  getegid                       sys_getegid
178  riscv32  gettid                        sys_gettid
179  riscv32  sysinfo                       sys_sysinfo
180  riscv32  mq_open                       sys_mq_open
181  riscv32  mq_unlink                     sys_mq_unlink
184  riscv32  mq_notify                     sys_mq_notify
185  riscv32  mq_getsetattr                 sys_mq_getsetattr
186  riscv32  msgget                        sys_msgget
187  riscv32  msgctl                        sys_msgctl
188  riscv32  msgrcv                        sys_msgrcv
189  riscv32  msgsnd                        sys_msgsnd
190  riscv32  semget                        sys_semget
191  riscv32  semctl                        sys_semctl
193  riscv32  semop                         sys_semop
194  riscv32  shmget                        sys_shmget
195  riscv32  shmctl                        sys_shmctl
196  riscv32  shmat                         sys_shmat
197  riscv32  shmdt                         sys_shmdt
198  riscv32  socket                        sys_socket
199  riscv32  socketpair                    sys_socketpair
200  riscv32  bind                          sys_bind
201  riscv32  listen                        sys_listen
202  riscv32  accept                        sys_accept
203  riscv32  connect                       sys_connect
204  riscv32  getsockname                   sys_getsockname
205  riscv32  getpeername                   sys_getpeername
206  riscv32  sendto                        sys_sendto
207  riscv32  recvfrom                      sys_recvfrom
208  riscv32  setsockopt                    sys_setsockopt
209  riscv32  getsockopt                    sys_getsockopt
210  riscv32  shutdown                      sys_shutdown
211  riscv32  sendmsg                       sys_sendmsg
212  riscv32  recvmsg                       sys_recvmsg
213  riscv32  readahead                     sys_readahead
214  riscv32  brk                           sys_brk
215  riscv32  munmap                        sys_munmap
216  riscv32  mremap                        sys_mremap
217  riscv32  add_key                       sys_add_key
218  riscv32  request_key                   sys_request_key
219  riscv32  keyctl                        sys_keyctl
220  riscv32  clone                         sys_clone
221  riscv32  execve                        sys_execve
222  riscv32  mmap                          sys_mmap2
223  riscv32  fadvise64                     sys_fadvise64_64
224  riscv32  swapon                        sys_swapon
225  riscv32  swapoff                       sys_swapoff
226  riscv32  mprotect                      sys_mprotect
227  riscv32  msync                         sys_msync
228  riscv32  mlock                         sys_mlock
229  riscv32  munlock                       sys_munlock
230  riscv32  mlockall                      sys_mlockall
231  riscv32  munlockall                    sys_munlockall
232  riscv32  mincore                       sys_mincore
233  riscv32  madvise                       sys_madvise
234  riscv32  remap_file_pages              sys_remap_file_pages
235  riscv32  mbind                         sys_mbind
236  riscv32  get_mempolicy                 sys_get_mempolicy
237  riscv32  set_mempolicy                 sys_set_mempolicy
238  riscv32  migrate_pages                 sys_migrate_pages
239  riscv32  move_pages                    sys_move_pages
240  riscv32  rt_tgsigqueueinfo             sys_rt_tgsigqueueinfo
241  riscv32  perf_event_open               sys_perf_event_open
242  riscv32  accept4                       sys_accept4
261  riscv32  prlimit64                     sys_prlimit64
262  riscv32  fanotify_init                 sys_fanotify_init
263  riscv32  fanotify_mark                 sys_fanotify_mark
264  riscv32  name_to_handle_at             sys_name_to_handle_at
265  riscv32  open_by_handle_at             sys_open_by_handle_at
267  riscv32  syncfs                        sys_syncfs
268  riscv32  setns                         sys_setns
269  riscv32  sendmmsg                      sys_sendmmsg
270  riscv32  process_vm_readv              sys_process_vm_readv
271  riscv32  process_vm_writev             sys_process_vm_writev
272  riscv32  kcmp                          sys_kcmp
273  riscv32  finit_module                  sys_finit_module
274  riscv32  sched_setattr                 sys_sched_setattr
275  riscv32  sched_getattr                 sys_sched_getattr
276  riscv32  renameat2                     sys_renameat2
277  riscv32  seccomp                       sys_seccomp
278  riscv32  getrandom                     sys_getrandom
279  riscv32  memfd_create                  sys_memfd_create
280  riscv32  bpf                           sys_bpf
281  riscv32  execveat                      sys_execveat
282  riscv32  userfaultfd                   sys_userfaultfd
283  riscv32  membarrier                    sys_membarrier
284  riscv32  mlock2                        sys_mlock2
285  riscv32  copy_file_range               sys_copy_file_range
286  riscv32  preadv2                       sys_preadv2
287  riscv32  pwritev2                      sys_pwritev2
288  riscv32  pkey_mprotect                 sys_pkey_mprotect
289  riscv32  pkey_alloc                    sys_pkey_alloc
290  riscv32  pkey_free                     sys_pkey_free
291  riscv32  statx                         sys_statx
293  riscv32  rseq                          sys_rseq
294  riscv32  kexec_file_load               sys_kexec_file_load
403  riscv32  clock_gettime64               sys_clock_gettime
404  riscv32  clock_settime64               sys_clock_settime
405  riscv32  clock_adjtime64               sys_clock_adjtime
406  riscv32  clock_getres_time64           sys_clock_getres
407  riscv32  clock_nanosleep_time64        sys_clock_nanosleep
408  riscv32  timer_gettime64               sys_timer_gettime
409  riscv32  timer_settime64               sys_timer_settime
410  riscv32  timerfd_gettime64             sys_timerfd_gettime
411  riscv32  timerfd_settime64             sys_timerfd_settime
412  riscv32  utimensat_time64              sys_utimensat
413  riscv32  pselect6_time64               sys_pselect6
414  riscv32  ppoll_time64                  sys_ppoll
416  riscv32  io_pgetevents_time64          sys_io_pgetevents
417  riscv32  recvmmsg_time64               sys_recvmmsg
418  riscv32  mq_timedsend_time64           sys_mq_timedsend
419  riscv32  mq_timedreceive_time64        sys_mq_timedreceive
420  riscv32  semtimedop_time64             sys_semtimedop
421  riscv32  rt_sigtimedwait_time64        sys_rt_sigtimedwait
422  riscv32  futex_time64                  sys_futex
423  riscv32  sched_rr_get_interval_time64  sys_sched_rr_get_interval
424  riscv32  pidfd_send_signal             sys_pidfd_send_signal
425  riscv32  io_uring_setup                sys_io_uring_setup
426  riscv32  io_uring_enter                sys_io_uring_enter
427  riscv32  io_uring_register             sys_io_uring_register
428  riscv32  open_tree                     sys_open_tree
429  riscv32  move_mount                    sys_move_mount
430  riscv32  fsopen                        sys_fsopen
431  riscv32  fsconfig                      sys_fsconfig
432  riscv32  fsmount                       sys_fsmount
433  riscv32  fspick                        sys_fspick
434  riscv32  pidfd_open                    sys_pidfd_open
435  riscv32  clone3                        sys_clone3
436  riscv32  close_range                   sys_close_range
437  riscv32  openat2                       sys_openat2
438  riscv32  pidfd_getfd                   sys_pidfd_getfd
439  riscv32  faccessat2                    sys_faccessat2
440  riscv32  process_madvise               sys_process_madvise
441  riscv32  epoll_pwait2                  sys_epoll_pwait2
442  riscv32  mount_setattr                 sys_mount_setattr
443  riscv32  quotactl_fd                   sys_quotactl_fd
444  riscv32  landlock_create_ruleset       sys_landlock_create_ruleset
445  riscv32  landlock_add_rule             sys_landlock_add_rule
446  riscv32  landlock_restrict_self        sys_landlock_restrict_self
447  riscv32  memfd_secret                  sys_memfd_secret
448  riscv32  process_mrelease              sys_process_mrelease
449  riscv32  futex_waitv                   sys_futex_waitv
450  riscv32  set_mempolicy_home_node       sys_set_mempolicy_home_node
451  riscv32  cachestat                     sys_cachestat
452  riscv32  fchmodat2                     sys_fchmodat2
453  riscv32  map_shadow_stack              sys_map_shadow_stack
454  riscv32  futex_wake                    sys_futex_wake
455  riscv32  futex_wait                    sys_futex_wait
456  riscv32  futex_requeue                 sys_futex_requeue
457  riscv32  statmount                     sys_statmount
458  riscv32  listmount                     sys_listmount
459  riscv32  lsm_get_self_attr             sys_lsm_get_self_attr
460  riscv32  lsm_set_self_attr             sys_lsm_set_self_attr
461  riscv32  lsm_list_modules              sys_lsm_list_modules
462  riscv32  mseal                         sys_mseal
"""


# S390X
# - arch/s390/kernel/syscalls/syscall.tbl
s390x_syscall_tbl = """
# System call table for s390
#
# Format:
#
# <nr> <abi> <syscall> <entry-64bit> <compat-entry>
#
# where <abi> can be common, 64, or 32

1    common     exit                    sys_exit                        sys_exit
2    common     fork                    sys_fork                        sys_fork
3    common     read                    sys_read                        compat_sys_s390_read
4    common     write                   sys_write                       compat_sys_s390_write
5    common     open                    sys_open                        compat_sys_open
6    common     close                   sys_close                       sys_close
7    common     restart_syscall         sys_restart_syscall             sys_restart_syscall
8    common     creat                   sys_creat                       sys_creat
9    common     link                    sys_link                        sys_link
10   common     unlink                  sys_unlink                      sys_unlink
11   common     execve                  sys_execve                      compat_sys_execve
12   common     chdir                   sys_chdir                       sys_chdir
13   32         time                    -                               sys_time32
14   common     mknod                   sys_mknod                       sys_mknod
15   common     chmod                   sys_chmod                       sys_chmod
16   32         lchown                  -                               sys_lchown16
19   common     lseek                   sys_lseek                       compat_sys_lseek
20   common     getpid                  sys_getpid                      sys_getpid
21   common     mount                   sys_mount                       sys_mount
22   common     umount                  sys_oldumount                   sys_oldumount
23   32         setuid                  -                               sys_setuid16
24   32         getuid                  -                               sys_getuid16
25   32         stime                   -                               sys_stime32
26   common     ptrace                  sys_ptrace                      compat_sys_ptrace
27   common     alarm                   sys_alarm                       sys_alarm
29   common     pause                   sys_pause                       sys_pause
30   common     utime                   sys_utime                       sys_utime32
33   common     access                  sys_access                      sys_access
34   common     nice                    sys_nice                        sys_nice
36   common     sync                    sys_sync                        sys_sync
37   common     kill                    sys_kill                        sys_kill
38   common     rename                  sys_rename                      sys_rename
39   common     mkdir                   sys_mkdir                       sys_mkdir
40   common     rmdir                   sys_rmdir                       sys_rmdir
41   common     dup                     sys_dup                         sys_dup
42   common     pipe                    sys_pipe                        sys_pipe
43   common     times                   sys_times                       compat_sys_times
45   common     brk                     sys_brk                         sys_brk
46   32         setgid                  -                               sys_setgid16
47   32         getgid                  -                               sys_getgid16
48   common     signal                  sys_signal                      sys_signal
49   32         geteuid                 -                               sys_geteuid16
50   32         getegid                 -                               sys_getegid16
51   common     acct                    sys_acct                        sys_acct
52   common     umount2                 sys_umount                      sys_umount
54   common     ioctl                   sys_ioctl                       compat_sys_ioctl
55   common     fcntl                   sys_fcntl                       compat_sys_fcntl
57   common     setpgid                 sys_setpgid                     sys_setpgid
60   common     umask                   sys_umask                       sys_umask
61   common     chroot                  sys_chroot                      sys_chroot
62   common     ustat                   sys_ustat                       compat_sys_ustat
63   common     dup2                    sys_dup2                        sys_dup2
64   common     getppid                 sys_getppid                     sys_getppid
65   common     getpgrp                 sys_getpgrp                     sys_getpgrp
66   common     setsid                  sys_setsid                      sys_setsid
67   common     sigaction               sys_sigaction                   compat_sys_sigaction
70   32         setreuid                -                               sys_setreuid16
71   32         setregid                -                               sys_setregid16
72   common     sigsuspend              sys_sigsuspend                  sys_sigsuspend
73   common     sigpending              sys_sigpending                  compat_sys_sigpending
74   common     sethostname             sys_sethostname                 sys_sethostname
75   common     setrlimit               sys_setrlimit                   compat_sys_setrlimit
76   32         getrlimit               -                               compat_sys_old_getrlimit
77   common     getrusage               sys_getrusage                   compat_sys_getrusage
78   common     gettimeofday            sys_gettimeofday                compat_sys_gettimeofday
79   common     settimeofday            sys_settimeofday                compat_sys_settimeofday
80   32         getgroups               -                               sys_getgroups16
81   32         setgroups               -                               sys_setgroups16
83   common     symlink                 sys_symlink                     sys_symlink
85   common     readlink                sys_readlink                    sys_readlink
86   common     uselib                  sys_uselib                      sys_uselib
87   common     swapon                  sys_swapon                      sys_swapon
88   common     reboot                  sys_reboot                      sys_reboot
89   common     readdir                 -                               compat_sys_old_readdir
90   common     mmap                    sys_old_mmap                    compat_sys_s390_old_mmap
91   common     munmap                  sys_munmap                      sys_munmap
92   common     truncate                sys_truncate                    compat_sys_truncate
93   common     ftruncate               sys_ftruncate                   compat_sys_ftruncate
94   common     fchmod                  sys_fchmod                      sys_fchmod
95   32         fchown                  -                               sys_fchown16
96   common     getpriority             sys_getpriority                 sys_getpriority
97   common     setpriority             sys_setpriority                 sys_setpriority
99   common     statfs                  sys_statfs                      compat_sys_statfs
100  common     fstatfs                 sys_fstatfs                     compat_sys_fstatfs
101  32         ioperm                  -                               -
102  common     socketcall              sys_socketcall                  compat_sys_socketcall
103  common     syslog                  sys_syslog                      sys_syslog
104  common     setitimer               sys_setitimer                   compat_sys_setitimer
105  common     getitimer               sys_getitimer                   compat_sys_getitimer
106  common     stat                    sys_newstat                     compat_sys_newstat
107  common     lstat                   sys_newlstat                    compat_sys_newlstat
108  common     fstat                   sys_newfstat                    compat_sys_newfstat
110  common     lookup_dcookie          -                               -
111  common     vhangup                 sys_vhangup                     sys_vhangup
112  common     idle                    -                               -
114  common     wait4                   sys_wait4                       compat_sys_wait4
115  common     swapoff                 sys_swapoff                     sys_swapoff
116  common     sysinfo                 sys_sysinfo                     compat_sys_sysinfo
117  common     ipc                     sys_s390_ipc                    compat_sys_s390_ipc
118  common     fsync                   sys_fsync                       sys_fsync
119  common     sigreturn               sys_sigreturn                   compat_sys_sigreturn
120  common     clone                   sys_clone                       sys_clone
121  common     setdomainname           sys_setdomainname               sys_setdomainname
122  common     uname                   sys_newuname                    sys_newuname
124  common     adjtimex                sys_adjtimex                    sys_adjtimex_time32
125  common     mprotect                sys_mprotect                    sys_mprotect
126  common     sigprocmask             sys_sigprocmask                 compat_sys_sigprocmask
127  common     create_module           -                               -
128  common     init_module             sys_init_module                 sys_init_module
129  common     delete_module           sys_delete_module               sys_delete_module
130  common     get_kernel_syms         -                               -
131  common     quotactl                sys_quotactl                    sys_quotactl
132  common     getpgid                 sys_getpgid                     sys_getpgid
133  common     fchdir                  sys_fchdir                      sys_fchdir
134  common     bdflush                 sys_ni_syscall                  sys_ni_syscall
135  common     sysfs                   sys_sysfs                       sys_sysfs
136  common     personality             sys_s390_personality            sys_s390_personality
137  common     afs_syscall             -                               -
138  32         setfsuid                -                               sys_setfsuid16
139  32         setfsgid                -                               sys_setfsgid16
140  32         _llseek                 -                               sys_llseek
141  common     getdents                sys_getdents                    compat_sys_getdents
142  32         _newselect              -                               compat_sys_select
142  64         select                  sys_select                      -
143  common     flock                   sys_flock                       sys_flock
144  common     msync                   sys_msync                       sys_msync
145  common     readv                   sys_readv                       sys_readv
146  common     writev                  sys_writev                      sys_writev
147  common     getsid                  sys_getsid                      sys_getsid
148  common     fdatasync               sys_fdatasync                   sys_fdatasync
149  common     _sysctl                 -                               -
150  common     mlock                   sys_mlock                       sys_mlock
151  common     munlock                 sys_munlock                     sys_munlock
152  common     mlockall                sys_mlockall                    sys_mlockall
153  common     munlockall              sys_munlockall                  sys_munlockall
154  common     sched_setparam          sys_sched_setparam              sys_sched_setparam
155  common     sched_getparam          sys_sched_getparam              sys_sched_getparam
156  common     sched_setscheduler      sys_sched_setscheduler          sys_sched_setscheduler
157  common     sched_getscheduler      sys_sched_getscheduler          sys_sched_getscheduler
158  common     sched_yield             sys_sched_yield                 sys_sched_yield
159  common     sched_get_priority_max  sys_sched_get_priority_max      sys_sched_get_priority_max
160  common     sched_get_priority_min  sys_sched_get_priority_min      sys_sched_get_priority_min
161  common     sched_rr_get_interval   sys_sched_rr_get_interval       sys_sched_rr_get_interval_time32
162  common     nanosleep               sys_nanosleep                   sys_nanosleep_time32
163  common     mremap                  sys_mremap                      sys_mremap
164  32         setresuid               -                               sys_setresuid16
165  32         getresuid               -                               sys_getresuid16
167  common     query_module            -                               -
168  common     poll                    sys_poll                        sys_poll
169  common     nfsservctl              -                               -
170  32         setresgid               -                               sys_setresgid16
171  32         getresgid               -                               sys_getresgid16
172  common     prctl                   sys_prctl                       sys_prctl
173  common     rt_sigreturn            sys_rt_sigreturn                compat_sys_rt_sigreturn
174  common     rt_sigaction            sys_rt_sigaction                compat_sys_rt_sigaction
175  common     rt_sigprocmask          sys_rt_sigprocmask              compat_sys_rt_sigprocmask
176  common     rt_sigpending           sys_rt_sigpending               compat_sys_rt_sigpending
177  common     rt_sigtimedwait         sys_rt_sigtimedwait             compat_sys_rt_sigtimedwait_time32
178  common     rt_sigqueueinfo         sys_rt_sigqueueinfo             compat_sys_rt_sigqueueinfo
179  common     rt_sigsuspend           sys_rt_sigsuspend               compat_sys_rt_sigsuspend
180  common     pread64                 sys_pread64                     compat_sys_s390_pread64
181  common     pwrite64                sys_pwrite64                    compat_sys_s390_pwrite64
182  32         chown                   -                               sys_chown16
183  common     getcwd                  sys_getcwd                      sys_getcwd
184  common     capget                  sys_capget                      sys_capget
185  common     capset                  sys_capset                      sys_capset
186  common     sigaltstack             sys_sigaltstack                 compat_sys_sigaltstack
187  common     sendfile                sys_sendfile64                  compat_sys_sendfile
188  common     getpmsg                 -                               -
189  common     putpmsg                 -                               -
190  common     vfork                   sys_vfork                       sys_vfork
191  32         ugetrlimit              -                               compat_sys_getrlimit
191  64         getrlimit               sys_getrlimit                   -
192  32         mmap2                   -                               compat_sys_s390_mmap2
193  32         truncate64              -                               compat_sys_s390_truncate64
194  32         ftruncate64             -                               compat_sys_s390_ftruncate64
195  32         stat64                  -                               compat_sys_s390_stat64
196  32         lstat64                 -                               compat_sys_s390_lstat64
197  32         fstat64                 -                               compat_sys_s390_fstat64
198  32         lchown32                -                               sys_lchown
198  64         lchown                  sys_lchown                      -
199  32         getuid32                -                               sys_getuid
199  64         getuid                  sys_getuid                      -
200  32         getgid32                -                               sys_getgid
200  64         getgid                  sys_getgid                      -
201  32         geteuid32               -                               sys_geteuid
201  64         geteuid                 sys_geteuid                     -
202  32         getegid32               -                               sys_getegid
202  64         getegid                 sys_getegid                     -
203  32         setreuid32              -                               sys_setreuid
203  64         setreuid                sys_setreuid                    -
204  32         setregid32              -                               sys_setregid
204  64         setregid                sys_setregid                    -
205  32         getgroups32             -                               sys_getgroups
205  64         getgroups               sys_getgroups                   -
206  32         setgroups32             -                               sys_setgroups
206  64         setgroups               sys_setgroups                   -
207  32         fchown32                -                               sys_fchown
207  64         fchown                  sys_fchown                      -
208  32         setresuid32             -                               sys_setresuid
208  64         setresuid               sys_setresuid                   -
209  32         getresuid32             -                               sys_getresuid
209  64         getresuid               sys_getresuid                   -
210  32         setresgid32             -                               sys_setresgid
210  64         setresgid               sys_setresgid                   -
211  32         getresgid32             -                               sys_getresgid
211  64         getresgid               sys_getresgid                   -
212  32         chown32                 -                               sys_chown
212  64         chown                   sys_chown                       -
213  32         setuid32                -                               sys_setuid
213  64         setuid                  sys_setuid                      -
214  32         setgid32                -                               sys_setgid
214  64         setgid                  sys_setgid                      -
215  32         setfsuid32              -                               sys_setfsuid
215  64         setfsuid                sys_setfsuid                    -
216  32         setfsgid32              -                               sys_setfsgid
216  64         setfsgid                sys_setfsgid                    -
217  common     pivot_root              sys_pivot_root                  sys_pivot_root
218  common     mincore                 sys_mincore                     sys_mincore
219  common     madvise                 sys_madvise                     sys_madvise
220  common     getdents64              sys_getdents64                  sys_getdents64
221  32         fcntl64                 -                               compat_sys_fcntl64
222  common     readahead               sys_readahead                   compat_sys_s390_readahead
223  32         sendfile64              -                               compat_sys_sendfile64
224  common     setxattr                sys_setxattr                    sys_setxattr
225  common     lsetxattr               sys_lsetxattr                   sys_lsetxattr
226  common     fsetxattr               sys_fsetxattr                   sys_fsetxattr
227  common     getxattr                sys_getxattr                    sys_getxattr
228  common     lgetxattr               sys_lgetxattr                   sys_lgetxattr
229  common     fgetxattr               sys_fgetxattr                   sys_fgetxattr
230  common     listxattr               sys_listxattr                   sys_listxattr
231  common     llistxattr              sys_llistxattr                  sys_llistxattr
232  common     flistxattr              sys_flistxattr                  sys_flistxattr
233  common     removexattr             sys_removexattr                 sys_removexattr
234  common     lremovexattr            sys_lremovexattr                sys_lremovexattr
235  common     fremovexattr            sys_fremovexattr                sys_fremovexattr
236  common     gettid                  sys_gettid                      sys_gettid
237  common     tkill                   sys_tkill                       sys_tkill
238  common     futex                   sys_futex                       sys_futex_time32
239  common     sched_setaffinity       sys_sched_setaffinity           compat_sys_sched_setaffinity
240  common     sched_getaffinity       sys_sched_getaffinity           compat_sys_sched_getaffinity
241  common     tgkill                  sys_tgkill                      sys_tgkill
243  common     io_setup                sys_io_setup                    compat_sys_io_setup
244  common     io_destroy              sys_io_destroy                  sys_io_destroy
245  common     io_getevents            sys_io_getevents                sys_io_getevents_time32
246  common     io_submit               sys_io_submit                   compat_sys_io_submit
247  common     io_cancel               sys_io_cancel                   sys_io_cancel
248  common     exit_group              sys_exit_group                  sys_exit_group
249  common     epoll_create            sys_epoll_create                sys_epoll_create
250  common     epoll_ctl               sys_epoll_ctl                   sys_epoll_ctl
251  common     epoll_wait              sys_epoll_wait                  sys_epoll_wait
252  common     set_tid_address         sys_set_tid_address             sys_set_tid_address
253  common     fadvise64               sys_fadvise64_64                compat_sys_s390_fadvise64
254  common     timer_create            sys_timer_create                compat_sys_timer_create
255  common     timer_settime           sys_timer_settime               sys_timer_settime32
256  common     timer_gettime           sys_timer_gettime               sys_timer_gettime32
257  common     timer_getoverrun        sys_timer_getoverrun            sys_timer_getoverrun
258  common     timer_delete            sys_timer_delete                sys_timer_delete
259  common     clock_settime           sys_clock_settime               sys_clock_settime32
260  common     clock_gettime           sys_clock_gettime               sys_clock_gettime32
261  common     clock_getres            sys_clock_getres                sys_clock_getres_time32
262  common     clock_nanosleep         sys_clock_nanosleep             sys_clock_nanosleep_time32
264  32         fadvise64_64            -                               compat_sys_s390_fadvise64_64
265  common     statfs64                sys_statfs64                    compat_sys_statfs64
266  common     fstatfs64               sys_fstatfs64                   compat_sys_fstatfs64
267  common     remap_file_pages        sys_remap_file_pages            sys_remap_file_pages
268  common     mbind                   sys_mbind                       sys_mbind
269  common     get_mempolicy           sys_get_mempolicy               sys_get_mempolicy
270  common     set_mempolicy           sys_set_mempolicy               sys_set_mempolicy
271  common     mq_open                 sys_mq_open                     compat_sys_mq_open
272  common     mq_unlink               sys_mq_unlink                   sys_mq_unlink
273  common     mq_timedsend            sys_mq_timedsend                sys_mq_timedsend_time32
274  common     mq_timedreceive         sys_mq_timedreceive             sys_mq_timedreceive_time32
275  common     mq_notify               sys_mq_notify                   compat_sys_mq_notify
276  common     mq_getsetattr           sys_mq_getsetattr               compat_sys_mq_getsetattr
277  common     kexec_load              sys_kexec_load                  compat_sys_kexec_load
278  common     add_key                 sys_add_key                     sys_add_key
279  common     request_key             sys_request_key                 sys_request_key
280  common     keyctl                  sys_keyctl                      compat_sys_keyctl
281  common     waitid                  sys_waitid                      compat_sys_waitid
282  common     ioprio_set              sys_ioprio_set                  sys_ioprio_set
283  common     ioprio_get              sys_ioprio_get                  sys_ioprio_get
284  common     inotify_init            sys_inotify_init                sys_inotify_init
285  common     inotify_add_watch       sys_inotify_add_watch           sys_inotify_add_watch
286  common     inotify_rm_watch        sys_inotify_rm_watch            sys_inotify_rm_watch
287  common     migrate_pages           sys_migrate_pages               sys_migrate_pages
288  common     openat                  sys_openat                      compat_sys_openat
289  common     mkdirat                 sys_mkdirat                     sys_mkdirat
290  common     mknodat                 sys_mknodat                     sys_mknodat
291  common     fchownat                sys_fchownat                    sys_fchownat
292  common     futimesat               sys_futimesat                   sys_futimesat_time32
293  32         fstatat64               -                               compat_sys_s390_fstatat64
293  64         newfstatat              sys_newfstatat                  -
294  common     unlinkat                sys_unlinkat                    sys_unlinkat
295  common     renameat                sys_renameat                    sys_renameat
296  common     linkat                  sys_linkat                      sys_linkat
297  common     symlinkat               sys_symlinkat                   sys_symlinkat
298  common     readlinkat              sys_readlinkat                  sys_readlinkat
299  common     fchmodat                sys_fchmodat                    sys_fchmodat
300  common     faccessat               sys_faccessat                   sys_faccessat
301  common     pselect6                sys_pselect6                    compat_sys_pselect6_time32
302  common     ppoll                   sys_ppoll                       compat_sys_ppoll_time32
303  common     unshare                 sys_unshare                     sys_unshare
304  common     set_robust_list         sys_set_robust_list             compat_sys_set_robust_list
305  common     get_robust_list         sys_get_robust_list             compat_sys_get_robust_list
306  common     splice                  sys_splice                      sys_splice
307  common     sync_file_range         sys_sync_file_range             compat_sys_s390_sync_file_range
308  common     tee                     sys_tee                         sys_tee
309  common     vmsplice                sys_vmsplice                    sys_vmsplice
310  common     move_pages              sys_move_pages                  sys_move_pages
311  common     getcpu                  sys_getcpu                      sys_getcpu
312  common     epoll_pwait             sys_epoll_pwait                 compat_sys_epoll_pwait
313  common     utimes                  sys_utimes                      sys_utimes_time32
314  common     fallocate               sys_fallocate                   compat_sys_s390_fallocate
315  common     utimensat               sys_utimensat                   sys_utimensat_time32
316  common     signalfd                sys_signalfd                    compat_sys_signalfd
317  common     timerfd                 -                               -
318  common     eventfd                 sys_eventfd                     sys_eventfd
319  common     timerfd_create          sys_timerfd_create              sys_timerfd_create
320  common     timerfd_settime         sys_timerfd_settime             sys_timerfd_settime32
321  common     timerfd_gettime         sys_timerfd_gettime             sys_timerfd_gettime32
322  common     signalfd4               sys_signalfd4                   compat_sys_signalfd4
323  common     eventfd2                sys_eventfd2                    sys_eventfd2
324  common     inotify_init1           sys_inotify_init1               sys_inotify_init1
325  common     pipe2                   sys_pipe2                       sys_pipe2
326  common     dup3                    sys_dup3                        sys_dup3
327  common     epoll_create1           sys_epoll_create1               sys_epoll_create1
328  common     preadv                  sys_preadv                      compat_sys_preadv
329  common     pwritev                 sys_pwritev                     compat_sys_pwritev
330  common     rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo           compat_sys_rt_tgsigqueueinfo
331  common     perf_event_open         sys_perf_event_open             sys_perf_event_open
332  common     fanotify_init           sys_fanotify_init               sys_fanotify_init
333  common     fanotify_mark           sys_fanotify_mark               compat_sys_fanotify_mark
334  common     prlimit64               sys_prlimit64                   sys_prlimit64
335  common     name_to_handle_at       sys_name_to_handle_at           sys_name_to_handle_at
336  common     open_by_handle_at       sys_open_by_handle_at           compat_sys_open_by_handle_at
337  common     clock_adjtime           sys_clock_adjtime               sys_clock_adjtime32
338  common     syncfs                  sys_syncfs                      sys_syncfs
339  common     setns                   sys_setns                       sys_setns
340  common     process_vm_readv        sys_process_vm_readv            sys_process_vm_readv
341  common     process_vm_writev       sys_process_vm_writev           sys_process_vm_writev
342  common     s390_runtime_instr      sys_s390_runtime_instr          sys_s390_runtime_instr
343  common     kcmp                    sys_kcmp                        sys_kcmp
344  common     finit_module            sys_finit_module                sys_finit_module
345  common     sched_setattr           sys_sched_setattr               sys_sched_setattr
346  common     sched_getattr           sys_sched_getattr               sys_sched_getattr
347  common     renameat2               sys_renameat2                   sys_renameat2
348  common     seccomp                 sys_seccomp                     sys_seccomp
349  common     getrandom               sys_getrandom                   sys_getrandom
350  common     memfd_create            sys_memfd_create                sys_memfd_create
351  common     bpf                     sys_bpf                         sys_bpf
352  common     s390_pci_mmio_write     sys_s390_pci_mmio_write         sys_s390_pci_mmio_write
353  common     s390_pci_mmio_read      sys_s390_pci_mmio_read          sys_s390_pci_mmio_read
354  common     execveat                sys_execveat                    compat_sys_execveat
355  common     userfaultfd             sys_userfaultfd                 sys_userfaultfd
356  common     membarrier              sys_membarrier                  sys_membarrier
357  common     recvmmsg                sys_recvmmsg                    compat_sys_recvmmsg_time32
358  common     sendmmsg                sys_sendmmsg                    compat_sys_sendmmsg
359  common     socket                  sys_socket                      sys_socket
360  common     socketpair              sys_socketpair                  sys_socketpair
361  common     bind                    sys_bind                        sys_bind
362  common     connect                 sys_connect                     sys_connect
363  common     listen                  sys_listen                      sys_listen
364  common     accept4                 sys_accept4                     sys_accept4
365  common     getsockopt              sys_getsockopt                  sys_getsockopt
366  common     setsockopt              sys_setsockopt                  sys_setsockopt
367  common     getsockname             sys_getsockname                 sys_getsockname
368  common     getpeername             sys_getpeername                 sys_getpeername
369  common     sendto                  sys_sendto                      sys_sendto
370  common     sendmsg                 sys_sendmsg                     compat_sys_sendmsg
371  common     recvfrom                sys_recvfrom                    compat_sys_recvfrom
372  common     recvmsg                 sys_recvmsg                     compat_sys_recvmsg
373  common     shutdown                sys_shutdown                    sys_shutdown
374  common     mlock2                  sys_mlock2                      sys_mlock2
375  common     copy_file_range         sys_copy_file_range             sys_copy_file_range
376  common     preadv2                 sys_preadv2                     compat_sys_preadv2
377  common     pwritev2                sys_pwritev2                    compat_sys_pwritev2
378  common     s390_guarded_storage    sys_s390_guarded_storage        sys_s390_guarded_storage
379  common     statx                   sys_statx                       sys_statx
380  common     s390_sthyi              sys_s390_sthyi                  sys_s390_sthyi
381  common     kexec_file_load         sys_kexec_file_load             sys_kexec_file_load
382  common     io_pgetevents           sys_io_pgetevents               compat_sys_io_pgetevents
383  common     rseq                    sys_rseq                        sys_rseq
384  common     pkey_mprotect           sys_pkey_mprotect               sys_pkey_mprotect
385  common     pkey_alloc              sys_pkey_alloc                  sys_pkey_alloc
386  common     pkey_free               sys_pkey_free                   sys_pkey_free
# room for arch specific syscalls
392     64      semtimedop              sys_semtimedop                  -
393  common     semget                  sys_semget                      sys_semget
394  common     semctl                  sys_semctl                      compat_sys_semctl
395  common     shmget                  sys_shmget                      sys_shmget
396  common     shmctl                  sys_shmctl                      compat_sys_shmctl
397  common     shmat                   sys_shmat                       compat_sys_shmat
398  common     shmdt                   sys_shmdt                       sys_shmdt
399  common     msgget                  sys_msgget                      sys_msgget
400  common     msgsnd                  sys_msgsnd                      compat_sys_msgsnd
401  common     msgrcv                  sys_msgrcv                      compat_sys_msgrcv
402  common     msgctl                  sys_msgctl                      compat_sys_msgctl
403     32      clock_gettime64         -                               sys_clock_gettime
404     32      clock_settime64         -                               sys_clock_settime
405     32      clock_adjtime64         -                               sys_clock_adjtime
406     32      clock_getres_time64     -                               sys_clock_getres
407     32      clock_nanosleep_time64  -                               sys_clock_nanosleep
408     32      timer_gettime64         -                               sys_timer_gettime
409     32      timer_settime64         -                               sys_timer_settime
410     32      timerfd_gettime64       -                               sys_timerfd_gettime
411     32      timerfd_settime64       -                               sys_timerfd_settime
412     32      utimensat_time64        -                               sys_utimensat
413     32      pselect6_time64         -                               compat_sys_pselect6_time64
414     32      ppoll_time64            -                               compat_sys_ppoll_time64
416     32      io_pgetevents_time64    -                               compat_sys_io_pgetevents_time64
417     32      recvmmsg_time64         -                               compat_sys_recvmmsg_time64
418     32      mq_timedsend_time64     -                               sys_mq_timedsend
419     32      mq_timedreceive_time64  -                               sys_mq_timedreceive
420     32      semtimedop_time64       -                               sys_semtimedop
421     32      rt_sigtimedwait_time64  -                               compat_sys_rt_sigtimedwait_time64
422     32      futex_time64            -                               sys_futex
423     32      sched_rr_get_interval_time64    -                       sys_sched_rr_get_interval
424  common     pidfd_send_signal       sys_pidfd_send_signal           sys_pidfd_send_signal
425  common     io_uring_setup          sys_io_uring_setup              sys_io_uring_setup
426  common     io_uring_enter          sys_io_uring_enter              sys_io_uring_enter
427  common     io_uring_register       sys_io_uring_register           sys_io_uring_register
428  common     open_tree               sys_open_tree                   sys_open_tree
429  common     move_mount              sys_move_mount                  sys_move_mount
430  common     fsopen                  sys_fsopen                      sys_fsopen
431  common     fsconfig                sys_fsconfig                    sys_fsconfig
432  common     fsmount                 sys_fsmount                     sys_fsmount
433  common     fspick                  sys_fspick                      sys_fspick
434  common     pidfd_open              sys_pidfd_open                  sys_pidfd_open
435  common     clone3                  sys_clone3                      sys_clone3
436  common     close_range             sys_close_range                 sys_close_range
437  common     openat2                 sys_openat2                     sys_openat2
438  common     pidfd_getfd             sys_pidfd_getfd                 sys_pidfd_getfd
439  common     faccessat2              sys_faccessat2                  sys_faccessat2
440  common     process_madvise         sys_process_madvise             sys_process_madvise
441  common     epoll_pwait2            sys_epoll_pwait2                compat_sys_epoll_pwait2
442  common     mount_setattr           sys_mount_setattr               sys_mount_setattr
443  common     quotactl_fd             sys_quotactl_fd                 sys_quotactl_fd
444  common     landlock_create_ruleset sys_landlock_create_ruleset     sys_landlock_create_ruleset
445  common     landlock_add_rule       sys_landlock_add_rule           sys_landlock_add_rule
446  common     landlock_restrict_self  sys_landlock_restrict_self      sys_landlock_restrict_self
447  common     memfd_secret            sys_memfd_secret                sys_memfd_secret
448  common     process_mrelease        sys_process_mrelease            sys_process_mrelease
449  common     futex_waitv             sys_futex_waitv                 sys_futex_waitv
450  common     set_mempolicy_home_node sys_set_mempolicy_home_node     sys_set_mempolicy_home_node
451  common     cachestat               sys_cachestat                   sys_cachestat
452  common     fchmodat2               sys_fchmodat2                   sys_fchmodat2
453  common     map_shadow_stack        sys_map_shadow_stack            sys_map_shadow_stack
454  common     futex_wake              sys_futex_wake                  sys_futex_wake
455  common     futex_wait              sys_futex_wait                  sys_futex_wait
456  common     futex_requeue           sys_futex_requeue               sys_futex_requeue
457  common     statmount               sys_statmount                   sys_statmount
458  common     listmount               sys_listmount                   sys_listmount
459  common     lsm_get_self_attr       sys_lsm_get_self_attr           sys_lsm_get_self_attr
460  common     lsm_set_self_attr       sys_lsm_set_self_attr           sys_lsm_set_self_attr
461  common     lsm_list_modules        sys_lsm_list_modules            sys_lsm_list_modules
462  common     mseal                   sys_mseal                       sys_mseal
"""


# SH4
# - arch/sh/kernel/syscalls/syscall.tbl
sh4_syscall_tbl = """
# system call numbers and entry vectors for sh
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The <abi> is always "common" for this file
#
0       common  restart_syscall                 sys_restart_syscall
1       common  exit                            sys_exit
2       common  fork                            sys_fork
3       common  read                            sys_read
4       common  write                           sys_write
5       common  open                            sys_open
6       common  close                           sys_close
7       common  waitpid                         sys_waitpid
8       common  creat                           sys_creat
9       common  link                            sys_link
10      common  unlink                          sys_unlink
11      common  execve                          sys_execve
12      common  chdir                           sys_chdir
13      common  time                            sys_time32
14      common  mknod                           sys_mknod
15      common  chmod                           sys_chmod
16      common  lchown                          sys_lchown16
# 17 was break
18      common  oldstat                         sys_stat
19      common  lseek                           sys_lseek
20      common  getpid                          sys_getpid
21      common  mount                           sys_mount
22      common  umount                          sys_oldumount
23      common  setuid                          sys_setuid16
24      common  getuid                          sys_getuid16
25      common  stime                           sys_stime32
26      common  ptrace                          sys_ptrace
27      common  alarm                           sys_alarm
28      common  oldfstat                        sys_fstat
29      common  pause                           sys_pause
30      common  utime                           sys_utime32
# 31 was stty
# 32 was gtty
33      common  access                          sys_access
34      common  nice                            sys_nice
# 35 was ftime
36      common  sync                            sys_sync
37      common  kill                            sys_kill
38      common  rename                          sys_rename
39      common  mkdir                           sys_mkdir
40      common  rmdir                           sys_rmdir
41      common  dup                             sys_dup
42      common  pipe                            sys_sh_pipe
43      common  times                           sys_times
# 44 was prof
45      common  brk                             sys_brk
46      common  setgid                          sys_setgid16
47      common  getgid                          sys_getgid16
48      common  signal                          sys_signal
49      common  geteuid                         sys_geteuid16
50      common  getegid                         sys_getegid16
51      common  acct                            sys_acct
52      common  umount2                         sys_umount
# 53 was lock
54      common  ioctl                           sys_ioctl
55      common  fcntl                           sys_fcntl
# 56 was mpx
57      common  setpgid                         sys_setpgid
# 58 was ulimit
# 59 was olduname
60      common  umask                           sys_umask
61      common  chroot                          sys_chroot
62      common  ustat                           sys_ustat
63      common  dup2                            sys_dup2
64      common  getppid                         sys_getppid
65      common  getpgrp                         sys_getpgrp
66      common  setsid                          sys_setsid
67      common  sigaction                       sys_sigaction
68      common  sgetmask                        sys_sgetmask
69      common  ssetmask                        sys_ssetmask
70      common  setreuid                        sys_setreuid16
71      common  setregid                        sys_setregid16
72      common  sigsuspend                      sys_sigsuspend
73      common  sigpending                      sys_sigpending
74      common  sethostname                     sys_sethostname
75      common  setrlimit                       sys_setrlimit
76      common  getrlimit                       sys_old_getrlimit
77      common  getrusage                       sys_getrusage
78      common  gettimeofday                    sys_gettimeofday
79      common  settimeofday                    sys_settimeofday
80      common  getgroups                       sys_getgroups16
81      common  setgroups                       sys_setgroups16
# 82 was select
83      common  symlink                         sys_symlink
84      common  oldlstat                        sys_lstat
85      common  readlink                        sys_readlink
86      common  uselib                          sys_uselib
87      common  swapon                          sys_swapon
88      common  reboot                          sys_reboot
89      common  readdir                         sys_old_readdir
90      common  mmap                            old_mmap
91      common  munmap                          sys_munmap
92      common  truncate                        sys_truncate
93      common  ftruncate                       sys_ftruncate
94      common  fchmod                          sys_fchmod
95      common  fchown                          sys_fchown16
96      common  getpriority                     sys_getpriority
97      common  setpriority                     sys_setpriority
# 98 was profil
99      common  statfs                          sys_statfs
100     common  fstatfs                         sys_fstatfs
# 101 was ioperm
102     common  socketcall                      sys_socketcall
103     common  syslog                          sys_syslog
104     common  setitimer                       sys_setitimer
105     common  getitimer                       sys_getitimer
106     common  stat                            sys_newstat
107     common  lstat                           sys_newlstat
108     common  fstat                           sys_newfstat
109     common  olduname                        sys_uname
# 110 was iopl
111     common  vhangup                         sys_vhangup
# 112 was idle
# 113 was vm86old
114     common  wait4                           sys_wait4
115     common  swapoff                         sys_swapoff
116     common  sysinfo                         sys_sysinfo
117     common  ipc                             sys_ipc
118     common  fsync                           sys_fsync
119     common  sigreturn                       sys_sigreturn
120     common  clone                           sys_clone
121     common  setdomainname                   sys_setdomainname
122     common  uname                           sys_newuname
123     common  cacheflush                      sys_cacheflush
124     common  adjtimex                        sys_adjtimex_time32
125     common  mprotect                        sys_mprotect
126     common  sigprocmask                     sys_sigprocmask
# 127 was create_module
128     common  init_module                     sys_init_module
129     common  delete_module                   sys_delete_module
# 130 was get_kernel_syms
131     common  quotactl                        sys_quotactl
132     common  getpgid                         sys_getpgid
133     common  fchdir                          sys_fchdir
134     common  bdflush                         sys_ni_syscall
135     common  sysfs                           sys_sysfs
136     common  personality                     sys_personality
# 137 was afs_syscall
138     common  setfsuid                        sys_setfsuid16
139     common  setfsgid                        sys_setfsgid16
140     common  _llseek                         sys_llseek
141     common  getdents                        sys_getdents
142     common  _newselect                      sys_select
143     common  flock                           sys_flock
144     common  msync                           sys_msync
145     common  readv                           sys_readv
146     common  writev                          sys_writev
147     common  getsid                          sys_getsid
148     common  fdatasync                       sys_fdatasync
149     common  _sysctl                         sys_ni_syscall
150     common  mlock                           sys_mlock
151     common  munlock                         sys_munlock
152     common  mlockall                        sys_mlockall
153     common  munlockall                      sys_munlockall
154     common  sched_setparam                  sys_sched_setparam
155     common  sched_getparam                  sys_sched_getparam
156     common  sched_setscheduler              sys_sched_setscheduler
157     common  sched_getscheduler              sys_sched_getscheduler
158     common  sched_yield                     sys_sched_yield
159     common  sched_get_priority_max          sys_sched_get_priority_max
160     common  sched_get_priority_min          sys_sched_get_priority_min
161     common  sched_rr_get_interval           sys_sched_rr_get_interval_time32
162     common  nanosleep                       sys_nanosleep_time32
163     common  mremap                          sys_mremap
164     common  setresuid                       sys_setresuid16
165     common  getresuid                       sys_getresuid16
# 166 was vm86
# 167 was query_module
168     common  poll                            sys_poll
169     common  nfsservctl                      sys_ni_syscall
170     common  setresgid                       sys_setresgid16
171     common  getresgid                       sys_getresgid16
172     common  prctl                           sys_prctl
173     common  rt_sigreturn                    sys_rt_sigreturn
174     common  rt_sigaction                    sys_rt_sigaction
175     common  rt_sigprocmask                  sys_rt_sigprocmask
176     common  rt_sigpending                   sys_rt_sigpending
177     common  rt_sigtimedwait                 sys_rt_sigtimedwait_time32
178     common  rt_sigqueueinfo                 sys_rt_sigqueueinfo
179     common  rt_sigsuspend                   sys_rt_sigsuspend
180     common  pread64                         sys_pread_wrapper
181     common  pwrite64                        sys_pwrite_wrapper
182     common  chown                           sys_chown16
183     common  getcwd                          sys_getcwd
184     common  capget                          sys_capget
185     common  capset                          sys_capset
186     common  sigaltstack                     sys_sigaltstack
187     common  sendfile                        sys_sendfile
# 188 is reserved for getpmsg
# 189 is reserved for putpmsg
190     common  vfork                           sys_vfork
191     common  ugetrlimit                      sys_getrlimit
192     common  mmap2                           sys_mmap2
193     common  truncate64                      sys_truncate64
194     common  ftruncate64                     sys_ftruncate64
195     common  stat64                          sys_stat64
196     common  lstat64                         sys_lstat64
197     common  fstat64                         sys_fstat64
198     common  lchown32                        sys_lchown
199     common  getuid32                        sys_getuid
200     common  getgid32                        sys_getgid
201     common  geteuid32                       sys_geteuid
202     common  getegid32                       sys_getegid
203     common  setreuid32                      sys_setreuid
204     common  setregid32                      sys_setregid
205     common  getgroups32                     sys_getgroups
206     common  setgroups32                     sys_setgroups
207     common  fchown32                        sys_fchown
208     common  setresuid32                     sys_setresuid
209     common  getresuid32                     sys_getresuid
210     common  setresgid32                     sys_setresgid
211     common  getresgid32                     sys_getresgid
212     common  chown32                         sys_chown
213     common  setuid32                        sys_setuid
214     common  setgid32                        sys_setgid
215     common  setfsuid32                      sys_setfsuid
216     common  setfsgid32                      sys_setfsgid
217     common  pivot_root                      sys_pivot_root
218     common  mincore                         sys_mincore
219     common  madvise                         sys_madvise
220     common  getdents64                      sys_getdents64
221     common  fcntl64                         sys_fcntl64
# 222 is reserved for tux
# 223 is unused
224     common  gettid                          sys_gettid
225     common  readahead                       sys_readahead
226     common  setxattr                        sys_setxattr
227     common  lsetxattr                       sys_lsetxattr
228     common  fsetxattr                       sys_fsetxattr
229     common  getxattr                        sys_getxattr
230     common  lgetxattr                       sys_lgetxattr
231     common  fgetxattr                       sys_fgetxattr
232     common  listxattr                       sys_listxattr
233     common  llistxattr                      sys_llistxattr
234     common  flistxattr                      sys_flistxattr
235     common  removexattr                     sys_removexattr
236     common  lremovexattr                    sys_lremovexattr
237     common  fremovexattr                    sys_fremovexattr
238     common  tkill                           sys_tkill
239     common  sendfile64                      sys_sendfile64
240     common  futex                           sys_futex_time32
241     common  sched_setaffinity               sys_sched_setaffinity
242     common  sched_getaffinity               sys_sched_getaffinity
# 243 is reserved for set_thread_area
# 244 is reserved for get_thread_area
245     common  io_setup                        sys_io_setup
246     common  io_destroy                      sys_io_destroy
247     common  io_getevents                    sys_io_getevents_time32
248     common  io_submit                       sys_io_submit
249     common  io_cancel                       sys_io_cancel
250     common  fadvise64                       sys_fadvise64
# 251 is unused
252     common  exit_group                      sys_exit_group
253     common  lookup_dcookie                  sys_ni_syscall
254     common  epoll_create                    sys_epoll_create
255     common  epoll_ctl                       sys_epoll_ctl
256     common  epoll_wait                      sys_epoll_wait
257     common  remap_file_pages                sys_remap_file_pages
258     common  set_tid_address                 sys_set_tid_address
259     common  timer_create                    sys_timer_create
260     common  timer_settime                   sys_timer_settime32
261     common  timer_gettime                   sys_timer_gettime32
262     common  timer_getoverrun                sys_timer_getoverrun
263     common  timer_delete                    sys_timer_delete
264     common  clock_settime                   sys_clock_settime32
265     common  clock_gettime                   sys_clock_gettime32
266     common  clock_getres                    sys_clock_getres_time32
267     common  clock_nanosleep                 sys_clock_nanosleep_time32
268     common  statfs64                        sys_statfs64
269     common  fstatfs64                       sys_fstatfs64
270     common  tgkill                          sys_tgkill
271     common  utimes                          sys_utimes_time32
272     common  fadvise64_64                    sys_fadvise64_64_wrapper
# 273 is reserved for vserver
274     common  mbind                           sys_mbind
275     common  get_mempolicy                   sys_get_mempolicy
276     common  set_mempolicy                   sys_set_mempolicy
277     common  mq_open                         sys_mq_open
278     common  mq_unlink                       sys_mq_unlink
279     common  mq_timedsend                    sys_mq_timedsend_time32
280     common  mq_timedreceive                 sys_mq_timedreceive_time32
281     common  mq_notify                       sys_mq_notify
282     common  mq_getsetattr                   sys_mq_getsetattr
283     common  kexec_load                      sys_kexec_load
284     common  waitid                          sys_waitid
285     common  add_key                         sys_add_key
286     common  request_key                     sys_request_key
287     common  keyctl                          sys_keyctl
288     common  ioprio_set                      sys_ioprio_set
289     common  ioprio_get                      sys_ioprio_get
290     common  inotify_init                    sys_inotify_init
291     common  inotify_add_watch               sys_inotify_add_watch
292     common  inotify_rm_watch                sys_inotify_rm_watch
# 293 is unused
294     common  migrate_pages                   sys_migrate_pages
295     common  openat                          sys_openat
296     common  mkdirat                         sys_mkdirat
297     common  mknodat                         sys_mknodat
298     common  fchownat                        sys_fchownat
299     common  futimesat                       sys_futimesat_time32
300     common  fstatat64                       sys_fstatat64
301     common  unlinkat                        sys_unlinkat
302     common  renameat                        sys_renameat
303     common  linkat                          sys_linkat
304     common  symlinkat                       sys_symlinkat
305     common  readlinkat                      sys_readlinkat
306     common  fchmodat                        sys_fchmodat
307     common  faccessat                       sys_faccessat
308     common  pselect6                        sys_pselect6_time32
309     common  ppoll                           sys_ppoll_time32
310     common  unshare                         sys_unshare
311     common  set_robust_list                 sys_set_robust_list
312     common  get_robust_list                 sys_get_robust_list
313     common  splice                          sys_splice
314     common  sync_file_range                 sys_sh_sync_file_range6
315     common  tee                             sys_tee
316     common  vmsplice                        sys_vmsplice
317     common  move_pages                      sys_move_pages
318     common  getcpu                          sys_getcpu
319     common  epoll_pwait                     sys_epoll_pwait
320     common  utimensat                       sys_utimensat_time32
321     common  signalfd                        sys_signalfd
322     common  timerfd_create                  sys_timerfd_create
323     common  eventfd                         sys_eventfd
324     common  fallocate                       sys_fallocate
325     common  timerfd_settime                 sys_timerfd_settime32
326     common  timerfd_gettime                 sys_timerfd_gettime32
327     common  signalfd4                       sys_signalfd4
328     common  eventfd2                        sys_eventfd2
329     common  epoll_create1                   sys_epoll_create1
330     common  dup3                            sys_dup3
331     common  pipe2                           sys_pipe2
332     common  inotify_init1                   sys_inotify_init1
333     common  preadv                          sys_preadv
334     common  pwritev                         sys_pwritev
335     common  rt_tgsigqueueinfo               sys_rt_tgsigqueueinfo
336     common  perf_event_open                 sys_perf_event_open
337     common  fanotify_init                   sys_fanotify_init
338     common  fanotify_mark                   sys_fanotify_mark
339     common  prlimit64                       sys_prlimit64
340     common  socket                          sys_socket
341     common  bind                            sys_bind
342     common  connect                         sys_connect
343     common  listen                          sys_listen
344     common  accept                          sys_accept
345     common  getsockname                     sys_getsockname
346     common  getpeername                     sys_getpeername
347     common  socketpair                      sys_socketpair
348     common  send                            sys_send
349     common  sendto                          sys_sendto
350     common  recv                            sys_recv
351     common  recvfrom                        sys_recvfrom
352     common  shutdown                        sys_shutdown
353     common  setsockopt                      sys_setsockopt
354     common  getsockopt                      sys_getsockopt
355     common  sendmsg                         sys_sendmsg
356     common  recvmsg                         sys_recvmsg
357     common  recvmmsg                        sys_recvmmsg_time32
358     common  accept4                         sys_accept4
359     common  name_to_handle_at               sys_name_to_handle_at
360     common  open_by_handle_at               sys_open_by_handle_at
361     common  clock_adjtime                   sys_clock_adjtime32
362     common  syncfs                          sys_syncfs
363     common  sendmmsg                        sys_sendmmsg
364     common  setns                           sys_setns
365     common  process_vm_readv                sys_process_vm_readv
366     common  process_vm_writev               sys_process_vm_writev
367     common  kcmp                            sys_kcmp
368     common  finit_module                    sys_finit_module
369     common  sched_getattr                   sys_sched_getattr
370     common  sched_setattr                   sys_sched_setattr
371     common  renameat2                       sys_renameat2
372     common  seccomp                         sys_seccomp
373     common  getrandom                       sys_getrandom
374     common  memfd_create                    sys_memfd_create
375     common  bpf                             sys_bpf
376     common  execveat                        sys_execveat
377     common  userfaultfd                     sys_userfaultfd
378     common  membarrier                      sys_membarrier
379     common  mlock2                          sys_mlock2
380     common  copy_file_range                 sys_copy_file_range
381     common  preadv2                         sys_preadv2
382     common  pwritev2                        sys_pwritev2
383     common  statx                           sys_statx
384     common  pkey_mprotect                   sys_pkey_mprotect
385     common  pkey_alloc                      sys_pkey_alloc
386     common  pkey_free                       sys_pkey_free
387     common  rseq                            sys_rseq
388     common  sync_file_range2                sys_sync_file_range2
# room for arch specific syscalls
393     common  semget                          sys_semget
394     common  semctl                          sys_semctl
395     common  shmget                          sys_shmget
396     common  shmctl                          sys_shmctl
397     common  shmat                           sys_shmat
398     common  shmdt                           sys_shmdt
399     common  msgget                          sys_msgget
400     common  msgsnd                          sys_msgsnd
401     common  msgrcv                          sys_msgrcv
402     common  msgctl                          sys_msgctl
403     common  clock_gettime64                 sys_clock_gettime
404     common  clock_settime64                 sys_clock_settime
405     common  clock_adjtime64                 sys_clock_adjtime
406     common  clock_getres_time64             sys_clock_getres
407     common  clock_nanosleep_time64          sys_clock_nanosleep
408     common  timer_gettime64                 sys_timer_gettime
409     common  timer_settime64                 sys_timer_settime
410     common  timerfd_gettime64               sys_timerfd_gettime
411     common  timerfd_settime64               sys_timerfd_settime
412     common  utimensat_time64                sys_utimensat
413     common  pselect6_time64                 sys_pselect6
414     common  ppoll_time64                    sys_ppoll
416     common  io_pgetevents_time64            sys_io_pgetevents
417     common  recvmmsg_time64                 sys_recvmmsg
418     common  mq_timedsend_time64             sys_mq_timedsend
419     common  mq_timedreceive_time64          sys_mq_timedreceive
420     common  semtimedop_time64               sys_semtimedop
421     common  rt_sigtimedwait_time64          sys_rt_sigtimedwait
422     common  futex_time64                    sys_futex
423     common  sched_rr_get_interval_time64    sys_sched_rr_get_interval
424     common  pidfd_send_signal               sys_pidfd_send_signal
425     common  io_uring_setup                  sys_io_uring_setup
426     common  io_uring_enter                  sys_io_uring_enter
427     common  io_uring_register               sys_io_uring_register
428     common  open_tree                       sys_open_tree
429     common  move_mount                      sys_move_mount
430     common  fsopen                          sys_fsopen
431     common  fsconfig                        sys_fsconfig
432     common  fsmount                         sys_fsmount
433     common  fspick                          sys_fspick
434     common  pidfd_open                      sys_pidfd_open
# 435 reserved for clone3
436     common  close_range                     sys_close_range
437     common  openat2                         sys_openat2
438     common  pidfd_getfd                     sys_pidfd_getfd
439     common  faccessat2                      sys_faccessat2
440     common  process_madvise                 sys_process_madvise
441     common  epoll_pwait2                    sys_epoll_pwait2
442     common  mount_setattr                   sys_mount_setattr
443     common  quotactl_fd                     sys_quotactl_fd
444     common  landlock_create_ruleset         sys_landlock_create_ruleset
445     common  landlock_add_rule               sys_landlock_add_rule
446     common  landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     common  process_mrelease                sys_process_mrelease
449     common  futex_waitv                     sys_futex_waitv
450     common  set_mempolicy_home_node         sys_set_mempolicy_home_node
451     common  cachestat                       sys_cachestat
452     common  fchmodat2                       sys_fchmodat2
453     common  map_shadow_stack                sys_map_shadow_stack
454     common  futex_wake                      sys_futex_wake
455     common  futex_wait                      sys_futex_wait
456     common  futex_requeue                   sys_futex_requeue
457     common  statmount                       sys_statmount
458     common  listmount                       sys_listmount
459     common  lsm_get_self_attr               sys_lsm_get_self_attr
460     common  lsm_set_self_attr               sys_lsm_set_self_attr
461     common  lsm_list_modules                sys_lsm_list_modules
462     common  mseal                           sys_mseal
"""


# m68k
# - arch/m68k/kernel/syscalls/syscall.tbl
m68k_syscall_tbl = """
# system call numbers and entry vectors for m68k
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The <abi> is always "common" for this file
#
0       common  restart_syscall                 sys_restart_syscall
1       common  exit                            sys_exit
2       common  fork                            __sys_fork
3       common  read                            sys_read
4       common  write                           sys_write
5       common  open                            sys_open
6       common  close                           sys_close
7       common  waitpid                         sys_waitpid
8       common  creat                           sys_creat
9       common  link                            sys_link
10      common  unlink                          sys_unlink
11      common  execve                          sys_execve
12      common  chdir                           sys_chdir
13      common  time                            sys_time32
14      common  mknod                           sys_mknod
15      common  chmod                           sys_chmod
16      common  chown                           sys_chown16
# 17 was break
18      common  oldstat                         sys_stat
19      common  lseek                           sys_lseek
20      common  getpid                          sys_getpid
21      common  mount                           sys_mount
22      common  umount                          sys_oldumount
23      common  setuid                          sys_setuid16
24      common  getuid                          sys_getuid16
25      common  stime                           sys_stime32
26      common  ptrace                          sys_ptrace
27      common  alarm                           sys_alarm
28      common  oldfstat                        sys_fstat
29      common  pause                           sys_pause
30      common  utime                           sys_utime32
# 31 was stty
# 32 was gtty
33      common  access                          sys_access
34      common  nice                            sys_nice
# 35 was ftime
36      common  sync                            sys_sync
37      common  kill                            sys_kill
38      common  rename                          sys_rename
39      common  mkdir                           sys_mkdir
40      common  rmdir                           sys_rmdir
41      common  dup                             sys_dup
42      common  pipe                            sys_pipe
43      common  times                           sys_times
# 44 was prof
45      common  brk                             sys_brk
46      common  setgid                          sys_setgid16
47      common  getgid                          sys_getgid16
48      common  signal                          sys_signal
49      common  geteuid                         sys_geteuid16
50      common  getegid                         sys_getegid16
51      common  acct                            sys_acct
52      common  umount2                         sys_umount
# 53 was lock
54      common  ioctl                           sys_ioctl
55      common  fcntl                           sys_fcntl
# 56 was mpx
57      common  setpgid                         sys_setpgid
# 58 was ulimit
# 59 was oldolduname
60      common  umask                           sys_umask
61      common  chroot                          sys_chroot
62      common  ustat                           sys_ustat
63      common  dup2                            sys_dup2
64      common  getppid                         sys_getppid
65      common  getpgrp                         sys_getpgrp
66      common  setsid                          sys_setsid
67      common  sigaction                       sys_sigaction
68      common  sgetmask                        sys_sgetmask
69      common  ssetmask                        sys_ssetmask
70      common  setreuid                        sys_setreuid16
71      common  setregid                        sys_setregid16
72      common  sigsuspend                      sys_sigsuspend
73      common  sigpending                      sys_sigpending
74      common  sethostname                     sys_sethostname
75      common  setrlimit                       sys_setrlimit
76      common  getrlimit                       sys_old_getrlimit
77      common  getrusage                       sys_getrusage
78      common  gettimeofday                    sys_gettimeofday
79      common  settimeofday                    sys_settimeofday
80      common  getgroups                       sys_getgroups16
81      common  setgroups                       sys_setgroups16
82      common  select                          sys_old_select
83      common  symlink                         sys_symlink
84      common  oldlstat                        sys_lstat
85      common  readlink                        sys_readlink
86      common  uselib                          sys_uselib
87      common  swapon                          sys_swapon
88      common  reboot                          sys_reboot
89      common  readdir                         sys_old_readdir
90      common  mmap                            sys_old_mmap
91      common  munmap                          sys_munmap
92      common  truncate                        sys_truncate
93      common  ftruncate                       sys_ftruncate
94      common  fchmod                          sys_fchmod
95      common  fchown                          sys_fchown16
96      common  getpriority                     sys_getpriority
97      common  setpriority                     sys_setpriority
# 98 was profil
99      common  statfs                          sys_statfs
100     common  fstatfs                         sys_fstatfs
# 101 was ioperm
102     common  socketcall                      sys_socketcall
103     common  syslog                          sys_syslog
104     common  setitimer                       sys_setitimer
105     common  getitimer                       sys_getitimer
106     common  stat                            sys_newstat
107     common  lstat                           sys_newlstat
108     common  fstat                           sys_newfstat
# 109 was olduname
# 110 was iopl
111     common  vhangup                         sys_vhangup
# 112 was idle
# 113 was vm86
114     common  wait4                           sys_wait4
115     common  swapoff                         sys_swapoff
116     common  sysinfo                         sys_sysinfo
117     common  ipc                             sys_ipc
118     common  fsync                           sys_fsync
119     common  sigreturn                       sys_sigreturn
120     common  clone                           __sys_clone
121     common  setdomainname                   sys_setdomainname
122     common  uname                           sys_newuname
123     common  cacheflush                      sys_cacheflush
124     common  adjtimex                        sys_adjtimex_time32
125     common  mprotect                        sys_mprotect
126     common  sigprocmask                     sys_sigprocmask
127     common  create_module                   sys_ni_syscall
128     common  init_module                     sys_init_module
129     common  delete_module                   sys_delete_module
130     common  get_kernel_syms                 sys_ni_syscall
131     common  quotactl                        sys_quotactl
132     common  getpgid                         sys_getpgid
133     common  fchdir                          sys_fchdir
134     common  bdflush                         sys_ni_syscall
135     common  sysfs                           sys_sysfs
136     common  personality                     sys_personality
# 137 was afs_syscall
138     common  setfsuid                        sys_setfsuid16
139     common  setfsgid                        sys_setfsgid16
140     common  _llseek                         sys_llseek
141     common  getdents                        sys_getdents
142     common  _newselect                      sys_select
143     common  flock                           sys_flock
144     common  msync                           sys_msync
145     common  readv                           sys_readv
146     common  writev                          sys_writev
147     common  getsid                          sys_getsid
148     common  fdatasync                       sys_fdatasync
149     common  _sysctl                         sys_ni_syscall
150     common  mlock                           sys_mlock
151     common  munlock                         sys_munlock
152     common  mlockall                        sys_mlockall
153     common  munlockall                      sys_munlockall
154     common  sched_setparam                  sys_sched_setparam
155     common  sched_getparam                  sys_sched_getparam
156     common  sched_setscheduler              sys_sched_setscheduler
157     common  sched_getscheduler              sys_sched_getscheduler
158     common  sched_yield                     sys_sched_yield
159     common  sched_get_priority_max          sys_sched_get_priority_max
160     common  sched_get_priority_min          sys_sched_get_priority_min
161     common  sched_rr_get_interval           sys_sched_rr_get_interval_time32
162     common  nanosleep                       sys_nanosleep_time32
163     common  mremap                          sys_mremap
164     common  setresuid                       sys_setresuid16
165     common  getresuid                       sys_getresuid16
166     common  getpagesize                     sys_getpagesize
167     common  query_module                    sys_ni_syscall
168     common  poll                            sys_poll
169     common  nfsservctl                      sys_ni_syscall
170     common  setresgid                       sys_setresgid16
171     common  getresgid                       sys_getresgid16
172     common  prctl                           sys_prctl
173     common  rt_sigreturn                    sys_rt_sigreturn
174     common  rt_sigaction                    sys_rt_sigaction
175     common  rt_sigprocmask                  sys_rt_sigprocmask
176     common  rt_sigpending                   sys_rt_sigpending
177     common  rt_sigtimedwait                 sys_rt_sigtimedwait_time32
178     common  rt_sigqueueinfo                 sys_rt_sigqueueinfo
179     common  rt_sigsuspend                   sys_rt_sigsuspend
180     common  pread64                         sys_pread64
181     common  pwrite64                        sys_pwrite64
182     common  lchown                          sys_lchown16
183     common  getcwd                          sys_getcwd
184     common  capget                          sys_capget
185     common  capset                          sys_capset
186     common  sigaltstack                     sys_sigaltstack
187     common  sendfile                        sys_sendfile
188     common  getpmsg                         sys_ni_syscall
189     common  putpmsg                         sys_ni_syscall
190     common  vfork                           __sys_vfork
191     common  ugetrlimit                      sys_getrlimit
192     common  mmap2                           sys_mmap2
193     common  truncate64                      sys_truncate64
194     common  ftruncate64                     sys_ftruncate64
195     common  stat64                          sys_stat64
196     common  lstat64                         sys_lstat64
197     common  fstat64                         sys_fstat64
198     common  chown32                         sys_chown
199     common  getuid32                        sys_getuid
200     common  getgid32                        sys_getgid
201     common  geteuid32                       sys_geteuid
202     common  getegid32                       sys_getegid
203     common  setreuid32                      sys_setreuid
204     common  setregid32                      sys_setregid
205     common  getgroups32                     sys_getgroups
206     common  setgroups32                     sys_setgroups
207     common  fchown32                        sys_fchown
208     common  setresuid32                     sys_setresuid
209     common  getresuid32                     sys_getresuid
210     common  setresgid32                     sys_setresgid
211     common  getresgid32                     sys_getresgid
212     common  lchown32                        sys_lchown
213     common  setuid32                        sys_setuid
214     common  setgid32                        sys_setgid
215     common  setfsuid32                      sys_setfsuid
216     common  setfsgid32                      sys_setfsgid
217     common  pivot_root                      sys_pivot_root
# 218 is reserved
# 219 is reserved
220     common  getdents64                      sys_getdents64
221     common  gettid                          sys_gettid
222     common  tkill                           sys_tkill
223     common  setxattr                        sys_setxattr
224     common  lsetxattr                       sys_lsetxattr
225     common  fsetxattr                       sys_fsetxattr
226     common  getxattr                        sys_getxattr
227     common  lgetxattr                       sys_lgetxattr
228     common  fgetxattr                       sys_fgetxattr
229     common  listxattr                       sys_listxattr
230     common  llistxattr                      sys_llistxattr
231     common  flistxattr                      sys_flistxattr
232     common  removexattr                     sys_removexattr
233     common  lremovexattr                    sys_lremovexattr
234     common  fremovexattr                    sys_fremovexattr
235     common  futex                           sys_futex_time32
236     common  sendfile64                      sys_sendfile64
237     common  mincore                         sys_mincore
238     common  madvise                         sys_madvise
239     common  fcntl64                         sys_fcntl64
240     common  readahead                       sys_readahead
241     common  io_setup                        sys_io_setup
242     common  io_destroy                      sys_io_destroy
243     common  io_getevents                    sys_io_getevents_time32
244     common  io_submit                       sys_io_submit
245     common  io_cancel                       sys_io_cancel
246     common  fadvise64                       sys_fadvise64
247     common  exit_group                      sys_exit_group
248     common  lookup_dcookie                  sys_ni_syscall
249     common  epoll_create                    sys_epoll_create
250     common  epoll_ctl                       sys_epoll_ctl
251     common  epoll_wait                      sys_epoll_wait
252     common  remap_file_pages                sys_remap_file_pages
253     common  set_tid_address                 sys_set_tid_address
254     common  timer_create                    sys_timer_create
255     common  timer_settime                   sys_timer_settime32
256     common  timer_gettime                   sys_timer_gettime32
257     common  timer_getoverrun                sys_timer_getoverrun
258     common  timer_delete                    sys_timer_delete
259     common  clock_settime                   sys_clock_settime32
260     common  clock_gettime                   sys_clock_gettime32
261     common  clock_getres                    sys_clock_getres_time32
262     common  clock_nanosleep                 sys_clock_nanosleep_time32
263     common  statfs64                        sys_statfs64
264     common  fstatfs64                       sys_fstatfs64
265     common  tgkill                          sys_tgkill
266     common  utimes                          sys_utimes_time32
267     common  fadvise64_64                    sys_fadvise64_64
268     common  mbind                           sys_mbind
269     common  get_mempolicy                   sys_get_mempolicy
270     common  set_mempolicy                   sys_set_mempolicy
271     common  mq_open                         sys_mq_open
272     common  mq_unlink                       sys_mq_unlink
273     common  mq_timedsend                    sys_mq_timedsend_time32
274     common  mq_timedreceive                 sys_mq_timedreceive_time32
275     common  mq_notify                       sys_mq_notify
276     common  mq_getsetattr                   sys_mq_getsetattr
277     common  waitid                          sys_waitid
# 278 was vserver
279     common  add_key                         sys_add_key
280     common  request_key                     sys_request_key
281     common  keyctl                          sys_keyctl
282     common  ioprio_set                      sys_ioprio_set
283     common  ioprio_get                      sys_ioprio_get
284     common  inotify_init                    sys_inotify_init
285     common  inotify_add_watch               sys_inotify_add_watch
286     common  inotify_rm_watch                sys_inotify_rm_watch
287     common  migrate_pages                   sys_migrate_pages
288     common  openat                          sys_openat
289     common  mkdirat                         sys_mkdirat
290     common  mknodat                         sys_mknodat
291     common  fchownat                        sys_fchownat
292     common  futimesat                       sys_futimesat_time32
293     common  fstatat64                       sys_fstatat64
294     common  unlinkat                        sys_unlinkat
295     common  renameat                        sys_renameat
296     common  linkat                          sys_linkat
297     common  symlinkat                       sys_symlinkat
298     common  readlinkat                      sys_readlinkat
299     common  fchmodat                        sys_fchmodat
300     common  faccessat                       sys_faccessat
301     common  pselect6                        sys_pselect6_time32
302     common  ppoll                           sys_ppoll_time32
303     common  unshare                         sys_unshare
304     common  set_robust_list                 sys_set_robust_list
305     common  get_robust_list                 sys_get_robust_list
306     common  splice                          sys_splice
307     common  sync_file_range                 sys_sync_file_range
308     common  tee                             sys_tee
309     common  vmsplice                        sys_vmsplice
310     common  move_pages                      sys_move_pages
311     common  sched_setaffinity               sys_sched_setaffinity
312     common  sched_getaffinity               sys_sched_getaffinity
313     common  kexec_load                      sys_kexec_load
314     common  getcpu                          sys_getcpu
315     common  epoll_pwait                     sys_epoll_pwait
316     common  utimensat                       sys_utimensat_time32
317     common  signalfd                        sys_signalfd
318     common  timerfd_create                  sys_timerfd_create
319     common  eventfd                         sys_eventfd
320     common  fallocate                       sys_fallocate
321     common  timerfd_settime                 sys_timerfd_settime32
322     common  timerfd_gettime                 sys_timerfd_gettime32
323     common  signalfd4                       sys_signalfd4
324     common  eventfd2                        sys_eventfd2
325     common  epoll_create1                   sys_epoll_create1
326     common  dup3                            sys_dup3
327     common  pipe2                           sys_pipe2
328     common  inotify_init1                   sys_inotify_init1
329     common  preadv                          sys_preadv
330     common  pwritev                         sys_pwritev
331     common  rt_tgsigqueueinfo               sys_rt_tgsigqueueinfo
332     common  perf_event_open                 sys_perf_event_open
333     common  get_thread_area                 sys_get_thread_area
334     common  set_thread_area                 sys_set_thread_area
335     common  atomic_cmpxchg_32               sys_atomic_cmpxchg_32
336     common  atomic_barrier                  sys_atomic_barrier
337     common  fanotify_init                   sys_fanotify_init
338     common  fanotify_mark                   sys_fanotify_mark
339     common  prlimit64                       sys_prlimit64
340     common  name_to_handle_at               sys_name_to_handle_at
341     common  open_by_handle_at               sys_open_by_handle_at
342     common  clock_adjtime                   sys_clock_adjtime32
343     common  syncfs                          sys_syncfs
344     common  setns                           sys_setns
345     common  process_vm_readv                sys_process_vm_readv
346     common  process_vm_writev               sys_process_vm_writev
347     common  kcmp                            sys_kcmp
348     common  finit_module                    sys_finit_module
349     common  sched_setattr                   sys_sched_setattr
350     common  sched_getattr                   sys_sched_getattr
351     common  renameat2                       sys_renameat2
352     common  getrandom                       sys_getrandom
353     common  memfd_create                    sys_memfd_create
354     common  bpf                             sys_bpf
355     common  execveat                        sys_execveat
356     common  socket                          sys_socket
357     common  socketpair                      sys_socketpair
358     common  bind                            sys_bind
359     common  connect                         sys_connect
360     common  listen                          sys_listen
361     common  accept4                         sys_accept4
362     common  getsockopt                      sys_getsockopt
363     common  setsockopt                      sys_setsockopt
364     common  getsockname                     sys_getsockname
365     common  getpeername                     sys_getpeername
366     common  sendto                          sys_sendto
367     common  sendmsg                         sys_sendmsg
368     common  recvfrom                        sys_recvfrom
369     common  recvmsg                         sys_recvmsg
370     common  shutdown                        sys_shutdown
371     common  recvmmsg                        sys_recvmmsg_time32
372     common  sendmmsg                        sys_sendmmsg
373     common  userfaultfd                     sys_userfaultfd
374     common  membarrier                      sys_membarrier
375     common  mlock2                          sys_mlock2
376     common  copy_file_range                 sys_copy_file_range
377     common  preadv2                         sys_preadv2
378     common  pwritev2                        sys_pwritev2
379     common  statx                           sys_statx
380     common  seccomp                         sys_seccomp
381     common  pkey_mprotect                   sys_pkey_mprotect
382     common  pkey_alloc                      sys_pkey_alloc
383     common  pkey_free                       sys_pkey_free
384     common  rseq                            sys_rseq
# room for arch specific calls
393     common  semget                          sys_semget
394     common  semctl                          sys_semctl
395     common  shmget                          sys_shmget
396     common  shmctl                          sys_shmctl
397     common  shmat                           sys_shmat
398     common  shmdt                           sys_shmdt
399     common  msgget                          sys_msgget
400     common  msgsnd                          sys_msgsnd
401     common  msgrcv                          sys_msgrcv
402     common  msgctl                          sys_msgctl
403     common  clock_gettime64                 sys_clock_gettime
404     common  clock_settime64                 sys_clock_settime
405     common  clock_adjtime64                 sys_clock_adjtime
406     common  clock_getres_time64             sys_clock_getres
407     common  clock_nanosleep_time64          sys_clock_nanosleep
408     common  timer_gettime64                 sys_timer_gettime
409     common  timer_settime64                 sys_timer_settime
410     common  timerfd_gettime64               sys_timerfd_gettime
411     common  timerfd_settime64               sys_timerfd_settime
412     common  utimensat_time64                sys_utimensat
413     common  pselect6_time64                 sys_pselect6
414     common  ppoll_time64                    sys_ppoll
416     common  io_pgetevents_time64            sys_io_pgetevents
417     common  recvmmsg_time64                 sys_recvmmsg
418     common  mq_timedsend_time64             sys_mq_timedsend
419     common  mq_timedreceive_time64          sys_mq_timedreceive
420     common  semtimedop_time64               sys_semtimedop
421     common  rt_sigtimedwait_time64          sys_rt_sigtimedwait
422     common  futex_time64                    sys_futex
423     common  sched_rr_get_interval_time64    sys_sched_rr_get_interval
424     common  pidfd_send_signal               sys_pidfd_send_signal
425     common  io_uring_setup                  sys_io_uring_setup
426     common  io_uring_enter                  sys_io_uring_enter
427     common  io_uring_register               sys_io_uring_register
428     common  open_tree                       sys_open_tree
429     common  move_mount                      sys_move_mount
430     common  fsopen                          sys_fsopen
431     common  fsconfig                        sys_fsconfig
432     common  fsmount                         sys_fsmount
433     common  fspick                          sys_fspick
434     common  pidfd_open                      sys_pidfd_open
435     common  clone3                          __sys_clone3
436     common  close_range                     sys_close_range
437     common  openat2                         sys_openat2
438     common  pidfd_getfd                     sys_pidfd_getfd
439     common  faccessat2                      sys_faccessat2
440     common  process_madvise                 sys_process_madvise
441     common  epoll_pwait2                    sys_epoll_pwait2
442     common  mount_setattr                   sys_mount_setattr
443     common  quotactl_fd                     sys_quotactl_fd
444     common  landlock_create_ruleset         sys_landlock_create_ruleset
445     common  landlock_add_rule               sys_landlock_add_rule
446     common  landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     common  process_mrelease                sys_process_mrelease
449     common  futex_waitv                     sys_futex_waitv
450     common  set_mempolicy_home_node         sys_set_mempolicy_home_node
451     common  cachestat                       sys_cachestat
452     common  fchmodat2                       sys_fchmodat2
453     common  map_shadow_stack                sys_map_shadow_stack
454     common  futex_wake                      sys_futex_wake
455     common  futex_wait                      sys_futex_wait
456     common  futex_requeue                   sys_futex_requeue
457     common  statmount                       sys_statmount
458     common  listmount                       sys_listmount
459     common  lsm_get_self_attr               sys_lsm_get_self_attr
460     common  lsm_set_self_attr               sys_lsm_set_self_attr
461     common  lsm_list_modules                sys_lsm_list_modules
462     common  mseal                           sys_mseal
"""


# alpha
# - arch/alpha/kernel/syscalls/syscall.tbl
alpha_syscall_tbl = """
# system call numbers and entry vectors for alpha
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The <abi> is always "common" for this file
#
0       common  osf_syscall                     alpha_syscall_zero
1       common  exit                            sys_exit
2       common  fork                            alpha_fork
3       common  read                            sys_read
4       common  write                           sys_write
5       common  osf_old_open                    sys_ni_syscall
6       common  close                           sys_close
7       common  osf_wait4                       sys_osf_wait4
8       common  osf_old_creat                   sys_ni_syscall
9       common  link                            sys_link
10      common  unlink                          sys_unlink
11      common  osf_execve                      sys_ni_syscall
12      common  chdir                           sys_chdir
13      common  fchdir                          sys_fchdir
14      common  mknod                           sys_mknod
15      common  chmod                           sys_chmod
16      common  chown                           sys_chown
17      common  brk                             sys_osf_brk
18      common  osf_getfsstat                   sys_ni_syscall
19      common  lseek                           sys_lseek
20      common  getxpid                         sys_getxpid
21      common  osf_mount                       sys_osf_mount
22      common  umount2                         sys_umount
23      common  setuid                          sys_setuid
24      common  getxuid                         sys_getxuid
25      common  exec_with_loader                sys_ni_syscall
26      common  ptrace                          sys_ptrace
27      common  osf_nrecvmsg                    sys_ni_syscall
28      common  osf_nsendmsg                    sys_ni_syscall
29      common  osf_nrecvfrom                   sys_ni_syscall
30      common  osf_naccept                     sys_ni_syscall
31      common  osf_ngetpeername                sys_ni_syscall
32      common  osf_ngetsockname                sys_ni_syscall
33      common  access                          sys_access
34      common  osf_chflags                     sys_ni_syscall
35      common  osf_fchflags                    sys_ni_syscall
36      common  sync                            sys_sync
37      common  kill                            sys_kill
38      common  osf_old_stat                    sys_ni_syscall
39      common  setpgid                         sys_setpgid
40      common  osf_old_lstat                   sys_ni_syscall
41      common  dup                             sys_dup
42      common  pipe                            sys_alpha_pipe
43      common  osf_set_program_attributes      sys_osf_set_program_attributes
44      common  osf_profil                      sys_ni_syscall
45      common  open                            sys_open
46      common  osf_old_sigaction               sys_ni_syscall
47      common  getxgid                         sys_getxgid
48      common  osf_sigprocmask                 sys_osf_sigprocmask
49      common  osf_getlogin                    sys_ni_syscall
50      common  osf_setlogin                    sys_ni_syscall
51      common  acct                            sys_acct
52      common  sigpending                      sys_sigpending
54      common  ioctl                           sys_ioctl
55      common  osf_reboot                      sys_ni_syscall
56      common  osf_revoke                      sys_ni_syscall
57      common  symlink                         sys_symlink
58      common  readlink                        sys_readlink
59      common  execve                          sys_execve
60      common  umask                           sys_umask
61      common  chroot                          sys_chroot
62      common  osf_old_fstat                   sys_ni_syscall
63      common  getpgrp                         sys_getpgrp
64      common  getpagesize                     sys_getpagesize
65      common  osf_mremap                      sys_ni_syscall
66      common  vfork                           alpha_vfork
67      common  stat                            sys_newstat
68      common  lstat                           sys_newlstat
69      common  osf_sbrk                        sys_ni_syscall
70      common  osf_sstk                        sys_ni_syscall
71      common  mmap                            sys_osf_mmap
72      common  osf_old_vadvise                 sys_ni_syscall
73      common  munmap                          sys_munmap
74      common  mprotect                        sys_mprotect
75      common  madvise                         sys_madvise
76      common  vhangup                         sys_vhangup
77      common  osf_kmodcall                    sys_ni_syscall
78      common  osf_mincore                     sys_ni_syscall
79      common  getgroups                       sys_getgroups
80      common  setgroups                       sys_setgroups
81      common  osf_old_getpgrp                 sys_ni_syscall
82      common  setpgrp                         sys_setpgid
83      common  osf_setitimer                   compat_sys_setitimer
84      common  osf_old_wait                    sys_ni_syscall
85      common  osf_table                       sys_ni_syscall
86      common  osf_getitimer                   compat_sys_getitimer
87      common  gethostname                     sys_gethostname
88      common  sethostname                     sys_sethostname
89      common  getdtablesize                   sys_getdtablesize
90      common  dup2                            sys_dup2
91      common  fstat                           sys_newfstat
92      common  fcntl                           sys_fcntl
93      common  osf_select                      sys_osf_select
94      common  poll                            sys_poll
95      common  fsync                           sys_fsync
96      common  setpriority                     sys_setpriority
97      common  socket                          sys_socket
98      common  connect                         sys_connect
99      common  accept                          sys_accept
100     common  getpriority                     sys_osf_getpriority
101     common  send                            sys_send
102     common  recv                            sys_recv
103     common  sigreturn                       sys_sigreturn
104     common  bind                            sys_bind
105     common  setsockopt                      sys_setsockopt
106     common  listen                          sys_listen
107     common  osf_plock                       sys_ni_syscall
108     common  osf_old_sigvec                  sys_ni_syscall
109     common  osf_old_sigblock                sys_ni_syscall
110     common  osf_old_sigsetmask              sys_ni_syscall
111     common  sigsuspend                      sys_sigsuspend
112     common  osf_sigstack                    sys_osf_sigstack
113     common  recvmsg                         sys_recvmsg
114     common  sendmsg                         sys_sendmsg
115     common  osf_old_vtrace                  sys_ni_syscall
116     common  osf_gettimeofday                sys_osf_gettimeofday
117     common  osf_getrusage                   sys_osf_getrusage
118     common  getsockopt                      sys_getsockopt
120     common  readv                           sys_readv
121     common  writev                          sys_writev
122     common  osf_settimeofday                sys_osf_settimeofday
123     common  fchown                          sys_fchown
124     common  fchmod                          sys_fchmod
125     common  recvfrom                        sys_recvfrom
126     common  setreuid                        sys_setreuid
127     common  setregid                        sys_setregid
128     common  rename                          sys_rename
129     common  truncate                        sys_truncate
130     common  ftruncate                       sys_ftruncate
131     common  flock                           sys_flock
132     common  setgid                          sys_setgid
133     common  sendto                          sys_sendto
134     common  shutdown                        sys_shutdown
135     common  socketpair                      sys_socketpair
136     common  mkdir                           sys_mkdir
137     common  rmdir                           sys_rmdir
138     common  osf_utimes                      sys_osf_utimes
139     common  osf_old_sigreturn               sys_ni_syscall
140     common  osf_adjtime                     sys_ni_syscall
141     common  getpeername                     sys_getpeername
142     common  osf_gethostid                   sys_ni_syscall
143     common  osf_sethostid                   sys_ni_syscall
144     common  getrlimit                       sys_getrlimit
145     common  setrlimit                       sys_setrlimit
146     common  osf_old_killpg                  sys_ni_syscall
147     common  setsid                          sys_setsid
148     common  quotactl                        sys_quotactl
149     common  osf_oldquota                    sys_ni_syscall
150     common  getsockname                     sys_getsockname
153     common  osf_pid_block                   sys_ni_syscall
154     common  osf_pid_unblock                 sys_ni_syscall
156     common  sigaction                       sys_osf_sigaction
157     common  osf_sigwaitprim                 sys_ni_syscall
158     common  osf_nfssvc                      sys_ni_syscall
159     common  osf_getdirentries               sys_osf_getdirentries
160     common  osf_statfs                      sys_osf_statfs
161     common  osf_fstatfs                     sys_osf_fstatfs
163     common  osf_asynch_daemon               sys_ni_syscall
164     common  osf_getfh                       sys_ni_syscall
165     common  osf_getdomainname               sys_osf_getdomainname
166     common  setdomainname                   sys_setdomainname
169     common  osf_exportfs                    sys_ni_syscall
181     common  osf_alt_plock                   sys_ni_syscall
184     common  osf_getmnt                      sys_ni_syscall
187     common  osf_alt_sigpending              sys_ni_syscall
188     common  osf_alt_setsid                  sys_ni_syscall
199     common  osf_swapon                      sys_swapon
200     common  msgctl                          sys_old_msgctl
201     common  msgget                          sys_msgget
202     common  msgrcv                          sys_msgrcv
203     common  msgsnd                          sys_msgsnd
204     common  semctl                          sys_old_semctl
205     common  semget                          sys_semget
206     common  semop                           sys_semop
207     common  osf_utsname                     sys_osf_utsname
208     common  lchown                          sys_lchown
209     common  shmat                           sys_shmat
210     common  shmctl                          sys_old_shmctl
211     common  shmdt                           sys_shmdt
212     common  shmget                          sys_shmget
213     common  osf_mvalid                      sys_ni_syscall
214     common  osf_getaddressconf              sys_ni_syscall
215     common  osf_msleep                      sys_ni_syscall
216     common  osf_mwakeup                     sys_ni_syscall
217     common  msync                           sys_msync
218     common  osf_signal                      sys_ni_syscall
219     common  osf_utc_gettime                 sys_ni_syscall
220     common  osf_utc_adjtime                 sys_ni_syscall
222     common  osf_security                    sys_ni_syscall
223     common  osf_kloadcall                   sys_ni_syscall
224     common  osf_stat                        sys_osf_stat
225     common  osf_lstat                       sys_osf_lstat
226     common  osf_fstat                       sys_osf_fstat
227     common  osf_statfs64                    sys_osf_statfs64
228     common  osf_fstatfs64                   sys_osf_fstatfs64
233     common  getpgid                         sys_getpgid
234     common  getsid                          sys_getsid
235     common  sigaltstack                     sys_sigaltstack
236     common  osf_waitid                      sys_ni_syscall
237     common  osf_priocntlset                 sys_ni_syscall
238     common  osf_sigsendset                  sys_ni_syscall
239     common  osf_set_speculative             sys_ni_syscall
240     common  osf_msfs_syscall                sys_ni_syscall
241     common  osf_sysinfo                     sys_osf_sysinfo
242     common  osf_uadmin                      sys_ni_syscall
243     common  osf_fuser                       sys_ni_syscall
244     common  osf_proplist_syscall            sys_osf_proplist_syscall
245     common  osf_ntp_adjtime                 sys_ni_syscall
246     common  osf_ntp_gettime                 sys_ni_syscall
247     common  osf_pathconf                    sys_ni_syscall
248     common  osf_fpathconf                   sys_ni_syscall
250     common  osf_uswitch                     sys_ni_syscall
251     common  osf_usleep_thread               sys_osf_usleep_thread
252     common  osf_audcntl                     sys_ni_syscall
253     common  osf_audgen                      sys_ni_syscall
254     common  sysfs                           sys_sysfs
255     common  osf_subsys_info                 sys_ni_syscall
256     common  osf_getsysinfo                  sys_osf_getsysinfo
257     common  osf_setsysinfo                  sys_osf_setsysinfo
258     common  osf_afs_syscall                 sys_ni_syscall
259     common  osf_swapctl                     sys_ni_syscall
260     common  osf_memcntl                     sys_ni_syscall
261     common  osf_fdatasync                   sys_ni_syscall
300     common  bdflush                         sys_ni_syscall
301     common  sethae                          sys_sethae
302     common  mount                           sys_mount
303     common  old_adjtimex                    sys_old_adjtimex
304     common  swapoff                         sys_swapoff
305     common  getdents                        sys_getdents
306     common  create_module                   sys_ni_syscall
307     common  init_module                     sys_init_module
308     common  delete_module                   sys_delete_module
309     common  get_kernel_syms                 sys_ni_syscall
310     common  syslog                          sys_syslog
311     common  reboot                          sys_reboot
312     common  clone                           alpha_clone
313     common  uselib                          sys_uselib
314     common  mlock                           sys_mlock
315     common  munlock                         sys_munlock
316     common  mlockall                        sys_mlockall
317     common  munlockall                      sys_munlockall
318     common  sysinfo                         sys_sysinfo
319     common  _sysctl                         sys_ni_syscall
# 320 was sys_idle
321     common  oldumount                       sys_oldumount
322     common  swapon                          sys_swapon
323     common  times                           sys_times
324     common  personality                     sys_personality
325     common  setfsuid                        sys_setfsuid
326     common  setfsgid                        sys_setfsgid
327     common  ustat                           sys_ustat
328     common  statfs                          sys_statfs
329     common  fstatfs                         sys_fstatfs
330     common  sched_setparam                  sys_sched_setparam
331     common  sched_getparam                  sys_sched_getparam
332     common  sched_setscheduler              sys_sched_setscheduler
333     common  sched_getscheduler              sys_sched_getscheduler
334     common  sched_yield                     sys_sched_yield
335     common  sched_get_priority_max          sys_sched_get_priority_max
336     common  sched_get_priority_min          sys_sched_get_priority_min
337     common  sched_rr_get_interval           sys_sched_rr_get_interval
338     common  afs_syscall                     sys_ni_syscall
339     common  uname                           sys_newuname
340     common  nanosleep                       sys_nanosleep
341     common  mremap                          sys_mremap
342     common  nfsservctl                      sys_ni_syscall
343     common  setresuid                       sys_setresuid
344     common  getresuid                       sys_getresuid
345     common  pciconfig_read                  sys_pciconfig_read
346     common  pciconfig_write                 sys_pciconfig_write
347     common  query_module                    sys_ni_syscall
348     common  prctl                           sys_prctl
349     common  pread64                         sys_pread64
350     common  pwrite64                        sys_pwrite64
351     common  rt_sigreturn                    sys_rt_sigreturn
352     common  rt_sigaction                    sys_rt_sigaction
353     common  rt_sigprocmask                  sys_rt_sigprocmask
354     common  rt_sigpending                   sys_rt_sigpending
355     common  rt_sigtimedwait                 sys_rt_sigtimedwait
356     common  rt_sigqueueinfo                 sys_rt_sigqueueinfo
357     common  rt_sigsuspend                   sys_rt_sigsuspend
358     common  select                          sys_select
359     common  gettimeofday                    sys_gettimeofday
360     common  settimeofday                    sys_settimeofday
361     common  getitimer                       sys_getitimer
362     common  setitimer                       sys_setitimer
363     common  utimes                          sys_utimes
364     common  getrusage                       sys_getrusage
365     common  wait4                           sys_wait4
366     common  adjtimex                        sys_adjtimex
367     common  getcwd                          sys_getcwd
368     common  capget                          sys_capget
369     common  capset                          sys_capset
370     common  sendfile                        sys_sendfile64
371     common  setresgid                       sys_setresgid
372     common  getresgid                       sys_getresgid
373     common  dipc                            sys_ni_syscall
374     common  pivot_root                      sys_pivot_root
375     common  mincore                         sys_mincore
376     common  pciconfig_iobase                sys_pciconfig_iobase
377     common  getdents64                      sys_getdents64
378     common  gettid                          sys_gettid
379     common  readahead                       sys_readahead
# 380 is unused
381     common  tkill                           sys_tkill
382     common  setxattr                        sys_setxattr
383     common  lsetxattr                       sys_lsetxattr
384     common  fsetxattr                       sys_fsetxattr
385     common  getxattr                        sys_getxattr
386     common  lgetxattr                       sys_lgetxattr
387     common  fgetxattr                       sys_fgetxattr
388     common  listxattr                       sys_listxattr
389     common  llistxattr                      sys_llistxattr
390     common  flistxattr                      sys_flistxattr
391     common  removexattr                     sys_removexattr
392     common  lremovexattr                    sys_lremovexattr
393     common  fremovexattr                    sys_fremovexattr
394     common  futex                           sys_futex
395     common  sched_setaffinity               sys_sched_setaffinity
396     common  sched_getaffinity               sys_sched_getaffinity
397     common  tuxcall                         sys_ni_syscall
398     common  io_setup                        sys_io_setup
399     common  io_destroy                      sys_io_destroy
400     common  io_getevents                    sys_io_getevents
401     common  io_submit                       sys_io_submit
402     common  io_cancel                       sys_io_cancel
405     common  exit_group                      sys_exit_group
406     common  lookup_dcookie                  sys_ni_syscall
407     common  epoll_create                    sys_epoll_create
408     common  epoll_ctl                       sys_epoll_ctl
409     common  epoll_wait                      sys_epoll_wait
410     common  remap_file_pages                sys_remap_file_pages
411     common  set_tid_address                 sys_set_tid_address
412     common  restart_syscall                 sys_restart_syscall
413     common  fadvise64                       sys_fadvise64
414     common  timer_create                    sys_timer_create
415     common  timer_settime                   sys_timer_settime
416     common  timer_gettime                   sys_timer_gettime
417     common  timer_getoverrun                sys_timer_getoverrun
418     common  timer_delete                    sys_timer_delete
419     common  clock_settime                   sys_clock_settime
420     common  clock_gettime                   sys_clock_gettime
421     common  clock_getres                    sys_clock_getres
422     common  clock_nanosleep                 sys_clock_nanosleep
423     common  semtimedop                      sys_semtimedop
424     common  tgkill                          sys_tgkill
425     common  stat64                          sys_stat64
426     common  lstat64                         sys_lstat64
427     common  fstat64                         sys_fstat64
428     common  vserver                         sys_ni_syscall
429     common  mbind                           sys_ni_syscall
430     common  get_mempolicy                   sys_ni_syscall
431     common  set_mempolicy                   sys_ni_syscall
432     common  mq_open                         sys_mq_open
433     common  mq_unlink                       sys_mq_unlink
434     common  mq_timedsend                    sys_mq_timedsend
435     common  mq_timedreceive                 sys_mq_timedreceive
436     common  mq_notify                       sys_mq_notify
437     common  mq_getsetattr                   sys_mq_getsetattr
438     common  waitid                          sys_waitid
439     common  add_key                         sys_add_key
440     common  request_key                     sys_request_key
441     common  keyctl                          sys_keyctl
442     common  ioprio_set                      sys_ioprio_set
443     common  ioprio_get                      sys_ioprio_get
444     common  inotify_init                    sys_inotify_init
445     common  inotify_add_watch               sys_inotify_add_watch
446     common  inotify_rm_watch                sys_inotify_rm_watch
447     common  fdatasync                       sys_fdatasync
448     common  kexec_load                      sys_kexec_load
449     common  migrate_pages                   sys_migrate_pages
450     common  openat                          sys_openat
451     common  mkdirat                         sys_mkdirat
452     common  mknodat                         sys_mknodat
453     common  fchownat                        sys_fchownat
454     common  futimesat                       sys_futimesat
455     common  fstatat64                       sys_fstatat64
456     common  unlinkat                        sys_unlinkat
457     common  renameat                        sys_renameat
458     common  linkat                          sys_linkat
459     common  symlinkat                       sys_symlinkat
460     common  readlinkat                      sys_readlinkat
461     common  fchmodat                        sys_fchmodat
462     common  faccessat                       sys_faccessat
463     common  pselect6                        sys_pselect6
464     common  ppoll                           sys_ppoll
465     common  unshare                         sys_unshare
466     common  set_robust_list                 sys_set_robust_list
467     common  get_robust_list                 sys_get_robust_list
468     common  splice                          sys_splice
469     common  sync_file_range                 sys_sync_file_range
470     common  tee                             sys_tee
471     common  vmsplice                        sys_vmsplice
472     common  move_pages                      sys_move_pages
473     common  getcpu                          sys_getcpu
474     common  epoll_pwait                     sys_epoll_pwait
475     common  utimensat                       sys_utimensat
476     common  signalfd                        sys_signalfd
477     common  timerfd                         sys_ni_syscall
478     common  eventfd                         sys_eventfd
479     common  recvmmsg                        sys_recvmmsg
480     common  fallocate                       sys_fallocate
481     common  timerfd_create                  sys_timerfd_create
482     common  timerfd_settime                 sys_timerfd_settime
483     common  timerfd_gettime                 sys_timerfd_gettime
484     common  signalfd4                       sys_signalfd4
485     common  eventfd2                        sys_eventfd2
486     common  epoll_create1                   sys_epoll_create1
487     common  dup3                            sys_dup3
488     common  pipe2                           sys_pipe2
489     common  inotify_init1                   sys_inotify_init1
490     common  preadv                          sys_preadv
491     common  pwritev                         sys_pwritev
492     common  rt_tgsigqueueinfo               sys_rt_tgsigqueueinfo
493     common  perf_event_open                 sys_perf_event_open
494     common  fanotify_init                   sys_fanotify_init
495     common  fanotify_mark                   sys_fanotify_mark
496     common  prlimit64                       sys_prlimit64
497     common  name_to_handle_at               sys_name_to_handle_at
498     common  open_by_handle_at               sys_open_by_handle_at
499     common  clock_adjtime                   sys_clock_adjtime
500     common  syncfs                          sys_syncfs
501     common  setns                           sys_setns
502     common  accept4                         sys_accept4
503     common  sendmmsg                        sys_sendmmsg
504     common  process_vm_readv                sys_process_vm_readv
505     common  process_vm_writev               sys_process_vm_writev
506     common  kcmp                            sys_kcmp
507     common  finit_module                    sys_finit_module
508     common  sched_setattr                   sys_sched_setattr
509     common  sched_getattr                   sys_sched_getattr
510     common  renameat2                       sys_renameat2
511     common  getrandom                       sys_getrandom
512     common  memfd_create                    sys_memfd_create
513     common  execveat                        sys_execveat
514     common  seccomp                         sys_seccomp
515     common  bpf                             sys_bpf
516     common  userfaultfd                     sys_userfaultfd
517     common  membarrier                      sys_membarrier
518     common  mlock2                          sys_mlock2
519     common  copy_file_range                 sys_copy_file_range
520     common  preadv2                         sys_preadv2
521     common  pwritev2                        sys_pwritev2
522     common  statx                           sys_statx
523     common  io_pgetevents                   sys_io_pgetevents
524     common  pkey_mprotect                   sys_pkey_mprotect
525     common  pkey_alloc                      sys_pkey_alloc
526     common  pkey_free                       sys_pkey_free
527     common  rseq                            sys_rseq
528     common  statfs64                        sys_statfs64
529     common  fstatfs64                       sys_fstatfs64
530     common  getegid                         sys_getegid
531     common  geteuid                         sys_geteuid
532     common  getppid                         sys_getppid
# all other architectures have common numbers for new syscall, alpha
# is the exception.
534     common  pidfd_send_signal               sys_pidfd_send_signal
535     common  io_uring_setup                  sys_io_uring_setup
536     common  io_uring_enter                  sys_io_uring_enter
537     common  io_uring_register               sys_io_uring_register
538     common  open_tree                       sys_open_tree
539     common  move_mount                      sys_move_mount
540     common  fsopen                          sys_fsopen
541     common  fsconfig                        sys_fsconfig
542     common  fsmount                         sys_fsmount
543     common  fspick                          sys_fspick
544     common  pidfd_open                      sys_pidfd_open
545     common  clone3                          alpha_clone3
546     common  close_range                     sys_close_range
547     common  openat2                         sys_openat2
548     common  pidfd_getfd                     sys_pidfd_getfd
549     common  faccessat2                      sys_faccessat2
550     common  process_madvise                 sys_process_madvise
551     common  epoll_pwait2                    sys_epoll_pwait2
552     common  mount_setattr                   sys_mount_setattr
553     common  quotactl_fd                     sys_quotactl_fd
554     common  landlock_create_ruleset         sys_landlock_create_ruleset
555     common  landlock_add_rule               sys_landlock_add_rule
556     common  landlock_restrict_self          sys_landlock_restrict_self
# 557 reserved for memfd_secret
558     common  process_mrelease                sys_process_mrelease
559     common  futex_waitv                     sys_futex_waitv
560     common  set_mempolicy_home_node         sys_ni_syscall
561     common  cachestat                       sys_cachestat
562     common  fchmodat2                       sys_fchmodat2
563     common  map_shadow_stack                sys_map_shadow_stack
564     common  futex_wake                      sys_futex_wake
565     common  futex_wait                      sys_futex_wait
566     common  futex_requeue                   sys_futex_requeue
567     common  statmount                       sys_statmount
568     common  listmount                       sys_listmount
569     common  lsm_get_self_attr               sys_lsm_get_self_attr
570     common  lsm_set_self_attr               sys_lsm_set_self_attr
571     common  lsm_list_modules                sys_lsm_list_modules
572     common  mseal                           sys_mseal
"""


# HPPA
# - arch/parisc/kernel/syscalls/syscall.tbl
hppa_syscall_tbl = """
# system call numbers and entry vectors for parisc
#
# The format is:
# <number> <abi> <name> <entry point> <compat entry point>
#
# The <abi> can be common, 64, or 32 for this file.
#
0       common  restart_syscall         sys_restart_syscall
1       common  exit                    sys_exit
2       common  fork                    sys_fork_wrapper
3       common  read                    sys_read
4       common  write                   sys_write
5       common  open                    sys_open                        compat_sys_open
6       common  close                   sys_close
7       common  waitpid                 sys_waitpid
8       common  creat                   sys_creat
9       common  link                    sys_link
10      common  unlink                  sys_unlink
11      common  execve                  sys_execve                      compat_sys_execve
12      common  chdir                   sys_chdir
13      32      time                    sys_time32
13      64      time                    sys_time
14      common  mknod                   sys_mknod
15      common  chmod                   sys_chmod
16      common  lchown                  sys_lchown
17      common  socket                  sys_socket
18      common  stat                    sys_newstat                     compat_sys_newstat
19      common  lseek                   sys_lseek                       compat_sys_lseek
20      common  getpid                  sys_getpid
21      common  mount                   sys_mount
22      common  bind                    sys_bind
23      common  setuid                  sys_setuid
24      common  getuid                  sys_getuid
25      32      stime                   sys_stime32
25      64      stime                   sys_stime
26      common  ptrace                  sys_ptrace                      compat_sys_ptrace
27      common  alarm                   sys_alarm
28      common  fstat                   sys_newfstat                    compat_sys_newfstat
29      common  pause                   sys_pause
30      32      utime                   sys_utime32
30      64      utime                   sys_utime
31      common  connect                 sys_connect
32      common  listen                  sys_listen
33      common  access                  sys_access
34      common  nice                    sys_nice
35      common  accept                  sys_accept
36      common  sync                    sys_sync
37      common  kill                    sys_kill
38      common  rename                  sys_rename
39      common  mkdir                   sys_mkdir
40      common  rmdir                   sys_rmdir
41      common  dup                     sys_dup
42      common  pipe                    sys_pipe
43      common  times                   sys_times                       compat_sys_times
44      common  getsockname             sys_getsockname
45      common  brk                     sys_brk
46      common  setgid                  sys_setgid
47      common  getgid                  sys_getgid
48      common  signal                  sys_signal
49      common  geteuid                 sys_geteuid
50      common  getegid                 sys_getegid
51      common  acct                    sys_acct
52      common  umount2                 sys_umount
53      common  getpeername             sys_getpeername
54      common  ioctl                   sys_ioctl                       compat_sys_ioctl
55      common  fcntl                   sys_fcntl                       compat_sys_fcntl
56      common  socketpair              sys_socketpair
57      common  setpgid                 sys_setpgid
58      common  send                    sys_send
59      common  uname                   sys_newuname
60      common  umask                   sys_umask
61      common  chroot                  sys_chroot
62      common  ustat                   sys_ustat                       compat_sys_ustat
63      common  dup2                    sys_dup2
64      common  getppid                 sys_getppid
65      common  getpgrp                 sys_getpgrp
66      common  setsid                  sys_setsid
67      common  pivot_root              sys_pivot_root
68      common  sgetmask                sys_sgetmask                    sys32_unimplemented
69      common  ssetmask                sys_ssetmask                    sys32_unimplemented
70      common  setreuid                sys_setreuid
71      common  setregid                sys_setregid
72      common  mincore                 sys_mincore
73      common  sigpending              sys_sigpending                  compat_sys_sigpending
74      common  sethostname             sys_sethostname
75      common  setrlimit               sys_setrlimit                   compat_sys_setrlimit
76      common  getrlimit               sys_getrlimit                   compat_sys_getrlimit
77      common  getrusage               sys_getrusage                   compat_sys_getrusage
78      common  gettimeofday            sys_gettimeofday                compat_sys_gettimeofday
79      common  settimeofday            sys_settimeofday                compat_sys_settimeofday
80      common  getgroups               sys_getgroups
81      common  setgroups               sys_setgroups
82      common  sendto                  sys_sendto
83      common  symlink                 sys_symlink
84      common  lstat                   sys_newlstat                    compat_sys_newlstat
85      common  readlink                sys_readlink
86      common  uselib                  sys_ni_syscall
87      common  swapon                  sys_swapon
88      common  reboot                  sys_reboot
89      common  mmap2                   sys_mmap2
90      common  mmap                    sys_mmap
91      common  munmap                  sys_munmap
92      common  truncate                sys_truncate                    compat_sys_truncate
93      common  ftruncate               sys_ftruncate                   compat_sys_ftruncate
94      common  fchmod                  sys_fchmod
95      common  fchown                  sys_fchown
96      common  getpriority             sys_getpriority
97      common  setpriority             sys_setpriority
98      common  recv                    sys_recv                        compat_sys_recv
99      common  statfs                  sys_statfs                      compat_sys_statfs
100     common  fstatfs                 sys_fstatfs                     compat_sys_fstatfs
101     common  stat64                  sys_stat64
# 102 was socketcall
103     common  syslog                  sys_syslog
104     common  setitimer               sys_setitimer                   compat_sys_setitimer
105     common  getitimer               sys_getitimer                   compat_sys_getitimer
106     common  capget                  sys_capget
107     common  capset                  sys_capset
108     32      pread64                 parisc_pread64
108     64      pread64                 sys_pread64
109     32      pwrite64                parisc_pwrite64
109     64      pwrite64                sys_pwrite64
110     common  getcwd                  sys_getcwd
111     common  vhangup                 sys_vhangup
112     common  fstat64                 sys_fstat64
113     common  vfork                   sys_vfork_wrapper
114     common  wait4                   sys_wait4                       compat_sys_wait4
115     common  swapoff                 sys_swapoff
116     common  sysinfo                 sys_sysinfo                     compat_sys_sysinfo
117     common  shutdown                sys_shutdown
118     common  fsync                   sys_fsync
119     common  madvise                 parisc_madvise
120     common  clone                   sys_clone_wrapper
121     common  setdomainname           sys_setdomainname
122     common  sendfile                sys_sendfile                    compat_sys_sendfile
123     common  recvfrom                sys_recvfrom                    compat_sys_recvfrom
124     32      adjtimex                sys_adjtimex_time32
124     64      adjtimex                sys_adjtimex
125     common  mprotect                sys_mprotect
126     common  sigprocmask             sys_sigprocmask                 compat_sys_sigprocmask
# 127 was create_module
128     common  init_module             sys_init_module
129     common  delete_module           sys_delete_module
# 130 was get_kernel_syms
131     common  quotactl                sys_quotactl
132     common  getpgid                 sys_getpgid
133     common  fchdir                  sys_fchdir
134     common  bdflush                 sys_ni_syscall
135     common  sysfs                   sys_sysfs
136     32      personality             parisc_personality
136     64      personality             sys_personality
# 137 was afs_syscall
138     common  setfsuid                sys_setfsuid
139     common  setfsgid                sys_setfsgid
140     common  _llseek                 sys_llseek
141     common  getdents                sys_getdents                    compat_sys_getdents
142     common  _newselect              sys_select                      compat_sys_select
143     common  flock                   sys_flock
144     common  msync                   sys_msync
145     common  readv                   sys_readv
146     common  writev                  sys_writev
147     common  getsid                  sys_getsid
148     common  fdatasync               sys_fdatasync
149     common  _sysctl                 sys_ni_syscall
150     common  mlock                   sys_mlock
151     common  munlock                 sys_munlock
152     common  mlockall                sys_mlockall
153     common  munlockall              sys_munlockall
154     common  sched_setparam          sys_sched_setparam
155     common  sched_getparam          sys_sched_getparam
156     common  sched_setscheduler      sys_sched_setscheduler
157     common  sched_getscheduler      sys_sched_getscheduler
158     common  sched_yield             sys_sched_yield
159     common  sched_get_priority_max  sys_sched_get_priority_max
160     common  sched_get_priority_min  sys_sched_get_priority_min
161     32      sched_rr_get_interval   sys_sched_rr_get_interval_time32
161     64      sched_rr_get_interval   sys_sched_rr_get_interval
162     32      nanosleep               sys_nanosleep_time32
162     64      nanosleep               sys_nanosleep
163     common  mremap                  sys_mremap
164     common  setresuid               sys_setresuid
165     common  getresuid               sys_getresuid
166     common  sigaltstack             sys_sigaltstack                 compat_sys_sigaltstack
# 167 was query_module
168     common  poll                    sys_poll
# 169 was nfsservctl
170     common  setresgid               sys_setresgid
171     common  getresgid               sys_getresgid
172     common  prctl                   sys_prctl
173     common  rt_sigreturn            sys_rt_sigreturn_wrapper
174     common  rt_sigaction            sys_rt_sigaction                compat_sys_rt_sigaction
175     common  rt_sigprocmask          sys_rt_sigprocmask              compat_sys_rt_sigprocmask
176     common  rt_sigpending           sys_rt_sigpending               compat_sys_rt_sigpending
177     32      rt_sigtimedwait         sys_rt_sigtimedwait_time32      compat_sys_rt_sigtimedwait_time32
177     64      rt_sigtimedwait         sys_rt_sigtimedwait
178     common  rt_sigqueueinfo         sys_rt_sigqueueinfo             compat_sys_rt_sigqueueinfo
179     common  rt_sigsuspend           sys_rt_sigsuspend               compat_sys_rt_sigsuspend
180     common  chown                   sys_chown
181     common  setsockopt              sys_setsockopt                  sys_setsockopt
182     common  getsockopt              sys_getsockopt                  sys_getsockopt
183     common  sendmsg                 sys_sendmsg                     compat_sys_sendmsg
184     common  recvmsg                 sys_recvmsg                     compat_sys_recvmsg
185     common  semop                   sys_semop
186     common  semget                  sys_semget
187     common  semctl                  sys_semctl                      compat_sys_semctl
188     common  msgsnd                  sys_msgsnd                      compat_sys_msgsnd
189     common  msgrcv                  sys_msgrcv                      compat_sys_msgrcv
190     common  msgget                  sys_msgget
191     common  msgctl                  sys_msgctl                      compat_sys_msgctl
192     common  shmat                   sys_shmat                       compat_sys_shmat
193     common  shmdt                   sys_shmdt
194     common  shmget                  sys_shmget
195     common  shmctl                  sys_shmctl                      compat_sys_shmctl
# 196 was getpmsg
# 197 was putpmsg
198     common  lstat64                 sys_lstat64
199     32      truncate64              parisc_truncate64
199     64      truncate64              sys_truncate64
200     32      ftruncate64             parisc_ftruncate64
200     64      ftruncate64             sys_ftruncate64
201     common  getdents64              sys_getdents64
202     common  fcntl64                 sys_fcntl64                     compat_sys_fcntl64
# 203 was attrctl
# 204 was acl_get
# 205 was acl_set
206     common  gettid                  sys_gettid
207     32      readahead               parisc_readahead
207     64      readahead               sys_readahead
208     common  tkill                   sys_tkill
209     common  sendfile64              sys_sendfile64                  compat_sys_sendfile64
210     32      futex                   sys_futex_time32
210     64      futex                   sys_futex
211     common  sched_setaffinity       sys_sched_setaffinity           compat_sys_sched_setaffinity
212     common  sched_getaffinity       sys_sched_getaffinity           compat_sys_sched_getaffinity
# 213 was set_thread_area
# 214 was get_thread_area
215     common  io_setup                sys_io_setup                    compat_sys_io_setup
216     common  io_destroy              sys_io_destroy
217     32      io_getevents            sys_io_getevents_time32
217     64      io_getevents            sys_io_getevents
218     common  io_submit               sys_io_submit                   compat_sys_io_submit
219     common  io_cancel               sys_io_cancel
# 220 was alloc_hugepages
# 221 was free_hugepages
222     common  exit_group              sys_exit_group
223     common  lookup_dcookie          sys_ni_syscall
224     common  epoll_create            sys_epoll_create
225     common  epoll_ctl               sys_epoll_ctl
226     common  epoll_wait              sys_epoll_wait
227     common  remap_file_pages        sys_remap_file_pages
228     32      semtimedop              sys_semtimedop_time32
228     64      semtimedop              sys_semtimedop
229     common  mq_open                 sys_mq_open                     compat_sys_mq_open
230     common  mq_unlink               sys_mq_unlink
231     32      mq_timedsend            sys_mq_timedsend_time32
231     64      mq_timedsend            sys_mq_timedsend
232     32      mq_timedreceive         sys_mq_timedreceive_time32
232     64      mq_timedreceive         sys_mq_timedreceive
233     common  mq_notify               sys_mq_notify                   compat_sys_mq_notify
234     common  mq_getsetattr           sys_mq_getsetattr               compat_sys_mq_getsetattr
235     common  waitid                  sys_waitid                      compat_sys_waitid
236     32      fadvise64_64            parisc_fadvise64_64
236     64      fadvise64_64            sys_fadvise64_64
237     common  set_tid_address         sys_set_tid_address
238     common  setxattr                sys_setxattr
239     common  lsetxattr               sys_lsetxattr
240     common  fsetxattr               sys_fsetxattr
241     common  getxattr                sys_getxattr
242     common  lgetxattr               sys_lgetxattr
243     common  fgetxattr               sys_fgetxattr
244     common  listxattr               sys_listxattr
245     common  llistxattr              sys_llistxattr
246     common  flistxattr              sys_flistxattr
247     common  removexattr             sys_removexattr
248     common  lremovexattr            sys_lremovexattr
249     common  fremovexattr            sys_fremovexattr
250     common  timer_create            sys_timer_create                compat_sys_timer_create
251     32      timer_settime           sys_timer_settime32
251     64      timer_settime           sys_timer_settime
252     32      timer_gettime           sys_timer_gettime32
252     64      timer_gettime           sys_timer_gettime
253     common  timer_getoverrun        sys_timer_getoverrun
254     common  timer_delete            sys_timer_delete
255     32      clock_settime           sys_clock_settime32
255     64      clock_settime           sys_clock_settime
256     32      clock_gettime           sys_clock_gettime32
256     64      clock_gettime           sys_clock_gettime
257     32      clock_getres            sys_clock_getres_time32
257     64      clock_getres            sys_clock_getres
258     32      clock_nanosleep         sys_clock_nanosleep_time32
258     64      clock_nanosleep         sys_clock_nanosleep
259     common  tgkill                  sys_tgkill
260     common  mbind                   sys_mbind
261     common  get_mempolicy           sys_get_mempolicy
262     common  set_mempolicy           sys_set_mempolicy
# 263 was vserver
264     common  add_key                 sys_add_key
265     common  request_key             sys_request_key
266     common  keyctl                  sys_keyctl                      compat_sys_keyctl
267     common  ioprio_set              sys_ioprio_set
268     common  ioprio_get              sys_ioprio_get
269     common  inotify_init            sys_inotify_init
270     common  inotify_add_watch       sys_inotify_add_watch
271     common  inotify_rm_watch        sys_inotify_rm_watch
272     common  migrate_pages           sys_migrate_pages
273     32      pselect6                sys_pselect6_time32             compat_sys_pselect6_time32
273     64      pselect6                sys_pselect6
274     32      ppoll                   sys_ppoll_time32                compat_sys_ppoll_time32
274     64      ppoll                   sys_ppoll
275     common  openat                  sys_openat                      compat_sys_openat
276     common  mkdirat                 sys_mkdirat
277     common  mknodat                 sys_mknodat
278     common  fchownat                sys_fchownat
279     32      futimesat               sys_futimesat_time32
279     64      futimesat               sys_futimesat
280     common  fstatat64               sys_fstatat64
281     common  unlinkat                sys_unlinkat
282     common  renameat                sys_renameat
283     common  linkat                  sys_linkat
284     common  symlinkat               sys_symlinkat
285     common  readlinkat              sys_readlinkat
286     common  fchmodat                sys_fchmodat
287     common  faccessat               sys_faccessat
288     common  unshare                 sys_unshare
289     common  set_robust_list         sys_set_robust_list             compat_sys_set_robust_list
290     common  get_robust_list         sys_get_robust_list             compat_sys_get_robust_list
291     common  splice                  sys_splice
292     32      sync_file_range         parisc_sync_file_range
292     64      sync_file_range         sys_sync_file_range
293     common  tee                     sys_tee
294     common  vmsplice                sys_vmsplice
295     common  move_pages              sys_move_pages
296     common  getcpu                  sys_getcpu
297     common  epoll_pwait             sys_epoll_pwait                 compat_sys_epoll_pwait
298     common  statfs64                sys_statfs64                    compat_sys_statfs64
299     common  fstatfs64               sys_fstatfs64                   compat_sys_fstatfs64
300     common  kexec_load              sys_kexec_load                  compat_sys_kexec_load
301     32      utimensat               sys_utimensat_time32
301     64      utimensat               sys_utimensat
302     common  signalfd                sys_signalfd                    compat_sys_signalfd
# 303 was timerfd
304     common  eventfd                 sys_eventfd
305     32      fallocate               parisc_fallocate
305     64      fallocate               sys_fallocate
306     common  timerfd_create          parisc_timerfd_create
307     32      timerfd_settime         sys_timerfd_settime32
307     64      timerfd_settime         sys_timerfd_settime
308     32      timerfd_gettime         sys_timerfd_gettime32
308     64      timerfd_gettime         sys_timerfd_gettime
309     common  signalfd4               parisc_signalfd4                parisc_compat_signalfd4
310     common  eventfd2                parisc_eventfd2
311     common  epoll_create1           sys_epoll_create1
312     common  dup3                    sys_dup3
313     common  pipe2                   parisc_pipe2
314     common  inotify_init1           parisc_inotify_init1
315     common  preadv  sys_preadv      compat_sys_preadv
316     common  pwritev sys_pwritev     compat_sys_pwritev
317     common  rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo           compat_sys_rt_tgsigqueueinfo
318     common  perf_event_open         sys_perf_event_open
319     32      recvmmsg                sys_recvmmsg_time32             compat_sys_recvmmsg_time32
319     64      recvmmsg                sys_recvmmsg
320     common  accept4                 sys_accept4
321     common  prlimit64               sys_prlimit64
322     common  fanotify_init           sys_fanotify_init
323     common  fanotify_mark           sys_fanotify_mark               compat_sys_fanotify_mark
324     32      clock_adjtime           sys_clock_adjtime32
324     64      clock_adjtime           sys_clock_adjtime
325     common  name_to_handle_at       sys_name_to_handle_at
326     common  open_by_handle_at       sys_open_by_handle_at           compat_sys_open_by_handle_at
327     common  syncfs                  sys_syncfs
328     common  setns                   sys_setns
329     common  sendmmsg                sys_sendmmsg                    compat_sys_sendmmsg
330     common  process_vm_readv        sys_process_vm_readv
331     common  process_vm_writev       sys_process_vm_writev
332     common  kcmp                    sys_kcmp
333     common  finit_module            sys_finit_module
334     common  sched_setattr           sys_sched_setattr
335     common  sched_getattr           sys_sched_getattr
336     32      utimes                  sys_utimes_time32
336     64      utimes                  sys_utimes
337     common  renameat2               sys_renameat2
338     common  seccomp                 sys_seccomp
339     common  getrandom               sys_getrandom
340     common  memfd_create            sys_memfd_create
341     common  bpf                     sys_bpf
342     common  execveat                sys_execveat                    compat_sys_execveat
343     common  membarrier              sys_membarrier
344     common  userfaultfd             parisc_userfaultfd
345     common  mlock2                  sys_mlock2
346     common  copy_file_range         sys_copy_file_range
347     common  preadv2                 sys_preadv2                     compat_sys_preadv2
348     common  pwritev2                sys_pwritev2                    compat_sys_pwritev2
349     common  statx                   sys_statx
350     32      io_pgetevents           sys_io_pgetevents_time32        compat_sys_io_pgetevents
350     64      io_pgetevents           sys_io_pgetevents
351     common  pkey_mprotect           sys_pkey_mprotect
352     common  pkey_alloc              sys_pkey_alloc
353     common  pkey_free               sys_pkey_free
354     common  rseq                    sys_rseq
355     common  kexec_file_load         sys_kexec_file_load             sys_kexec_file_load
356     common  cacheflush              sys_cacheflush
# up to 402 is unassigned and reserved for arch specific syscalls
403     32      clock_gettime64                 sys_clock_gettime               sys_clock_gettime
404     32      clock_settime64                 sys_clock_settime               sys_clock_settime
405     32      clock_adjtime64                 sys_clock_adjtime               sys_clock_adjtime
406     32      clock_getres_time64             sys_clock_getres                sys_clock_getres
407     32      clock_nanosleep_time64          sys_clock_nanosleep             sys_clock_nanosleep
408     32      timer_gettime64                 sys_timer_gettime               sys_timer_gettime
409     32      timer_settime64                 sys_timer_settime               sys_timer_settime
410     32      timerfd_gettime64               sys_timerfd_gettime             sys_timerfd_gettime
411     32      timerfd_settime64               sys_timerfd_settime             sys_timerfd_settime
412     32      utimensat_time64                sys_utimensat                   sys_utimensat
413     32      pselect6_time64                 sys_pselect6                    compat_sys_pselect6_time64
414     32      ppoll_time64                    sys_ppoll                       compat_sys_ppoll_time64
416     32      io_pgetevents_time64            sys_io_pgetevents               compat_sys_io_pgetevents_time64
417     32      recvmmsg_time64                 sys_recvmmsg                    compat_sys_recvmmsg_time64
418     32      mq_timedsend_time64             sys_mq_timedsend                sys_mq_timedsend
419     32      mq_timedreceive_time64          sys_mq_timedreceive             sys_mq_timedreceive
420     32      semtimedop_time64               sys_semtimedop                  sys_semtimedop
421     32      rt_sigtimedwait_time64          sys_rt_sigtimedwait             compat_sys_rt_sigtimedwait_time64
422     32      futex_time64                    sys_futex                       sys_futex
423     32      sched_rr_get_interval_time64    sys_sched_rr_get_interval       sys_sched_rr_get_interval
424     common  pidfd_send_signal               sys_pidfd_send_signal
425     common  io_uring_setup                  sys_io_uring_setup
426     common  io_uring_enter                  sys_io_uring_enter
427     common  io_uring_register               sys_io_uring_register
428     common  open_tree                       sys_open_tree
429     common  move_mount                      sys_move_mount
430     common  fsopen                          sys_fsopen
431     common  fsconfig                        sys_fsconfig
432     common  fsmount                         sys_fsmount
433     common  fspick                          sys_fspick
434     common  pidfd_open                      sys_pidfd_open
435     common  clone3                          sys_clone3_wrapper
436     common  close_range                     sys_close_range
437     common  openat2                         sys_openat2
438     common  pidfd_getfd                     sys_pidfd_getfd
439     common  faccessat2                      sys_faccessat2
440     common  process_madvise                 sys_process_madvise
441     common  epoll_pwait2                    sys_epoll_pwait2                compat_sys_epoll_pwait2
442     common  mount_setattr                   sys_mount_setattr
443     common  quotactl_fd                     sys_quotactl_fd
444     common  landlock_create_ruleset         sys_landlock_create_ruleset
445     common  landlock_add_rule               sys_landlock_add_rule
446     common  landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     common  process_mrelease                sys_process_mrelease
449     common  futex_waitv                     sys_futex_waitv
450     common  set_mempolicy_home_node         sys_set_mempolicy_home_node
451     common  cachestat                       sys_cachestat
452     common  fchmodat2                       sys_fchmodat2
453     common  map_shadow_stack                sys_map_shadow_stack
454     common  futex_wake                      sys_futex_wake
455     common  futex_wait                      sys_futex_wait
456     common  futex_requeue                   sys_futex_requeue
457     common  statmount                       sys_statmount
458     common  listmount                       sys_listmount
459     common  lsm_get_self_attr               sys_lsm_get_self_attr
460     common  lsm_set_self_attr               sys_lsm_set_self_attr
461     common  lsm_list_modules                sys_lsm_list_modules
462     common  mseal                           sys_mseal
"""


# OpenRISC
#
# [How to make]
# cd /path/to/linux-6.*/
# gcc -I `pwd`/include/uapi/ -E -D__SYSCALL=SYSCALL arch/openrisc/include/uapi/asm/unistd.h \
# | grep ^SYSCALL | sed -e 's/SYSCALL(//;s/[,)]//g' > /tmp/a
# grep -oP "__NR\S+\s+\d+$" include/uapi/asm-generic/unistd.h | grep -v __NR_sync_file_range2 > /tmp/b
# join -2 2 -o 1.1,1.10,2.1,1.2 -e or1k /tmp/a /tmp/b | sed -e 's/\(__NR_\|__NR3264_\)//g' | column -t
#
or1k_syscall_tbl = """
0    or1k  io_setup                 sys_io_setup
1    or1k  io_destroy               sys_io_destroy
2    or1k  io_submit                sys_io_submit
3    or1k  io_cancel                sys_io_cancel
4    or1k  io_getevents             sys_io_getevents
5    or1k  setxattr                 sys_setxattr
6    or1k  lsetxattr                sys_lsetxattr
7    or1k  fsetxattr                sys_fsetxattr
8    or1k  getxattr                 sys_getxattr
9    or1k  lgetxattr                sys_lgetxattr
10   or1k  fgetxattr                sys_fgetxattr
11   or1k  listxattr                sys_listxattr
12   or1k  llistxattr               sys_llistxattr
13   or1k  flistxattr               sys_flistxattr
14   or1k  removexattr              sys_removexattr
15   or1k  lremovexattr             sys_lremovexattr
16   or1k  fremovexattr             sys_fremovexattr
17   or1k  getcwd                   sys_getcwd
18   or1k  lookup_dcookie           sys_ni_syscall
19   or1k  eventfd2                 sys_eventfd2
20   or1k  epoll_create1            sys_epoll_create1
21   or1k  epoll_ctl                sys_epoll_ctl
22   or1k  epoll_pwait              sys_epoll_pwait
23   or1k  dup                      sys_dup
24   or1k  dup3                     sys_dup3
25   or1k  fcntl                    sys_fcntl
26   or1k  inotify_init1            sys_inotify_init1
27   or1k  inotify_add_watch        sys_inotify_add_watch
28   or1k  inotify_rm_watch         sys_inotify_rm_watch
29   or1k  ioctl                    sys_ioctl
30   or1k  ioprio_set               sys_ioprio_set
31   or1k  ioprio_get               sys_ioprio_get
32   or1k  flock                    sys_flock
33   or1k  mknodat                  sys_mknodat
34   or1k  mkdirat                  sys_mkdirat
35   or1k  unlinkat                 sys_unlinkat
36   or1k  symlinkat                sys_symlinkat
37   or1k  linkat                   sys_linkat
38   or1k  renameat                 sys_renameat
39   or1k  umount2                  sys_umount
40   or1k  mount                    sys_mount
41   or1k  pivot_root               sys_pivot_root
42   or1k  nfsservctl               sys_ni_syscall
43   or1k  statfs                   sys_statfs
44   or1k  fstatfs                  sys_fstatfs
45   or1k  truncate                 sys_truncate
46   or1k  ftruncate                sys_ftruncate
47   or1k  fallocate                sys_fallocate
48   or1k  faccessat                sys_faccessat
49   or1k  chdir                    sys_chdir
50   or1k  fchdir                   sys_fchdir
51   or1k  chroot                   sys_chroot
52   or1k  fchmod                   sys_fchmod
53   or1k  fchmodat                 sys_fchmodat
54   or1k  fchownat                 sys_fchownat
55   or1k  fchown                   sys_fchown
56   or1k  openat                   sys_openat
57   or1k  close                    sys_close
58   or1k  vhangup                  sys_vhangup
59   or1k  pipe2                    sys_pipe2
60   or1k  quotactl                 sys_quotactl
61   or1k  getdents64               sys_getdents64
62   or1k  lseek                    sys_lseek
63   or1k  read                     sys_read
64   or1k  write                    sys_write
65   or1k  readv                    sys_readv
66   or1k  writev                   sys_writev
67   or1k  pread64                  sys_pread64
68   or1k  pwrite64                 sys_pwrite64
69   or1k  preadv                   sys_preadv
70   or1k  pwritev                  sys_pwritev
71   or1k  sendfile                 sys_sendfile64
72   or1k  pselect6                 sys_pselect6
73   or1k  ppoll                    sys_ppoll
74   or1k  signalfd4                sys_signalfd4
75   or1k  vmsplice                 sys_vmsplice
76   or1k  splice                   sys_splice
77   or1k  tee                      sys_tee
78   or1k  readlinkat               sys_readlinkat
79   or1k  fstatat                  sys_newfstatat
80   or1k  fstat                    sys_newfstat
81   or1k  sync                     sys_sync
82   or1k  fsync                    sys_fsync
83   or1k  fdatasync                sys_fdatasync
84   or1k  sync_file_range          sys_sync_file_range
85   or1k  timerfd_create           sys_timerfd_create
86   or1k  timerfd_settime          sys_timerfd_settime
87   or1k  timerfd_gettime          sys_timerfd_gettime
88   or1k  utimensat                sys_utimensat
89   or1k  acct                     sys_acct
90   or1k  capget                   sys_capget
91   or1k  capset                   sys_capset
92   or1k  personality              sys_personality
93   or1k  exit                     sys_exit
94   or1k  exit_group               sys_exit_group
95   or1k  waitid                   sys_waitid
96   or1k  set_tid_address          sys_set_tid_address
97   or1k  unshare                  sys_unshare
98   or1k  futex                    sys_futex
99   or1k  set_robust_list          sys_set_robust_list
100  or1k  get_robust_list          sys_get_robust_list
101  or1k  nanosleep                sys_nanosleep
102  or1k  getitimer                sys_getitimer
103  or1k  setitimer                sys_setitimer
104  or1k  kexec_load               sys_kexec_load
105  or1k  init_module              sys_init_module
106  or1k  delete_module            sys_delete_module
107  or1k  timer_create             sys_timer_create
108  or1k  timer_gettime            sys_timer_gettime
109  or1k  timer_getoverrun         sys_timer_getoverrun
110  or1k  timer_settime            sys_timer_settime
111  or1k  timer_delete             sys_timer_delete
112  or1k  clock_settime            sys_clock_settime
113  or1k  clock_gettime            sys_clock_gettime
114  or1k  clock_getres             sys_clock_getres
115  or1k  clock_nanosleep          sys_clock_nanosleep
116  or1k  syslog                   sys_syslog
117  or1k  ptrace                   sys_ptrace
118  or1k  sched_setparam           sys_sched_setparam
119  or1k  sched_setscheduler       sys_sched_setscheduler
120  or1k  sched_getscheduler       sys_sched_getscheduler
121  or1k  sched_getparam           sys_sched_getparam
122  or1k  sched_setaffinity        sys_sched_setaffinity
123  or1k  sched_getaffinity        sys_sched_getaffinity
124  or1k  sched_yield              sys_sched_yield
125  or1k  sched_get_priority_max   sys_sched_get_priority_max
126  or1k  sched_get_priority_min   sys_sched_get_priority_min
127  or1k  sched_rr_get_interval    sys_sched_rr_get_interval
128  or1k  restart_syscall          sys_restart_syscall
129  or1k  kill                     sys_kill
130  or1k  tkill                    sys_tkill
131  or1k  tgkill                   sys_tgkill
132  or1k  sigaltstack              sys_sigaltstack
133  or1k  rt_sigsuspend            sys_rt_sigsuspend
134  or1k  rt_sigaction             sys_rt_sigaction
135  or1k  rt_sigprocmask           sys_rt_sigprocmask
136  or1k  rt_sigpending            sys_rt_sigpending
137  or1k  rt_sigtimedwait          sys_rt_sigtimedwait
138  or1k  rt_sigqueueinfo          sys_rt_sigqueueinfo
139  or1k  rt_sigreturn             sys_rt_sigreturn
140  or1k  setpriority              sys_setpriority
141  or1k  getpriority              sys_getpriority
142  or1k  reboot                   sys_reboot
143  or1k  setregid                 sys_setregid
144  or1k  setgid                   sys_setgid
145  or1k  setreuid                 sys_setreuid
146  or1k  setuid                   sys_setuid
147  or1k  setresuid                sys_setresuid
148  or1k  getresuid                sys_getresuid
149  or1k  setresgid                sys_setresgid
150  or1k  getresgid                sys_getresgid
151  or1k  setfsuid                 sys_setfsuid
152  or1k  setfsgid                 sys_setfsgid
153  or1k  times                    sys_times
154  or1k  setpgid                  sys_setpgid
155  or1k  getpgid                  sys_getpgid
156  or1k  getsid                   sys_getsid
157  or1k  setsid                   sys_setsid
158  or1k  getgroups                sys_getgroups
159  or1k  setgroups                sys_setgroups
160  or1k  uname                    sys_newuname
161  or1k  sethostname              sys_sethostname
162  or1k  setdomainname            sys_setdomainname
163  or1k  getrlimit                sys_getrlimit
164  or1k  setrlimit                sys_setrlimit
165  or1k  getrusage                sys_getrusage
166  or1k  umask                    sys_umask
167  or1k  prctl                    sys_prctl
168  or1k  getcpu                   sys_getcpu
169  or1k  gettimeofday             sys_gettimeofday
170  or1k  settimeofday             sys_settimeofday
171  or1k  adjtimex                 sys_adjtimex
172  or1k  getpid                   sys_getpid
173  or1k  getppid                  sys_getppid
174  or1k  getuid                   sys_getuid
175  or1k  geteuid                  sys_geteuid
176  or1k  getgid                   sys_getgid
177  or1k  getegid                  sys_getegid
178  or1k  gettid                   sys_gettid
179  or1k  sysinfo                  sys_sysinfo
180  or1k  mq_open                  sys_mq_open
181  or1k  mq_unlink                sys_mq_unlink
182  or1k  mq_timedsend             sys_mq_timedsend
183  or1k  mq_timedreceive          sys_mq_timedreceive
184  or1k  mq_notify                sys_mq_notify
185  or1k  mq_getsetattr            sys_mq_getsetattr
186  or1k  msgget                   sys_msgget
187  or1k  msgctl                   sys_msgctl
188  or1k  msgrcv                   sys_msgrcv
189  or1k  msgsnd                   sys_msgsnd
190  or1k  semget                   sys_semget
191  or1k  semctl                   sys_semctl
192  or1k  semtimedop               sys_semtimedop
193  or1k  semop                    sys_semop
194  or1k  shmget                   sys_shmget
195  or1k  shmctl                   sys_shmctl
196  or1k  shmat                    sys_shmat
197  or1k  shmdt                    sys_shmdt
198  or1k  socket                   sys_socket
199  or1k  socketpair               sys_socketpair
200  or1k  bind                     sys_bind
201  or1k  listen                   sys_listen
202  or1k  accept                   sys_accept
203  or1k  connect                  sys_connect
204  or1k  getsockname              sys_getsockname
205  or1k  getpeername              sys_getpeername
206  or1k  sendto                   sys_sendto
207  or1k  recvfrom                 sys_recvfrom
208  or1k  setsockopt               sys_setsockopt
209  or1k  getsockopt               sys_getsockopt
210  or1k  shutdown                 sys_shutdown
211  or1k  sendmsg                  sys_sendmsg
212  or1k  recvmsg                  sys_recvmsg
213  or1k  readahead                sys_readahead
214  or1k  brk                      sys_brk
215  or1k  munmap                   sys_munmap
216  or1k  mremap                   sys_mremap
217  or1k  add_key                  sys_add_key
218  or1k  request_key              sys_request_key
219  or1k  keyctl                   sys_keyctl
220  or1k  clone                    sys_clone
221  or1k  execve                   sys_execve
222  or1k  mmap                     sys_mmap
223  or1k  fadvise64                sys_fadvise64_64
224  or1k  swapon                   sys_swapon
225  or1k  swapoff                  sys_swapoff
226  or1k  mprotect                 sys_mprotect
227  or1k  msync                    sys_msync
228  or1k  mlock                    sys_mlock
229  or1k  munlock                  sys_munlock
230  or1k  mlockall                 sys_mlockall
231  or1k  munlockall               sys_munlockall
232  or1k  mincore                  sys_mincore
233  or1k  madvise                  sys_madvise
234  or1k  remap_file_pages         sys_remap_file_pages
235  or1k  mbind                    sys_mbind
236  or1k  get_mempolicy            sys_get_mempolicy
237  or1k  set_mempolicy            sys_set_mempolicy
238  or1k  migrate_pages            sys_migrate_pages
239  or1k  move_pages               sys_move_pages
240  or1k  rt_tgsigqueueinfo        sys_rt_tgsigqueueinfo
241  or1k  perf_event_open          sys_perf_event_open
242  or1k  accept4                  sys_accept4
243  or1k  recvmmsg                 sys_recvmmsg
260  or1k  wait4                    sys_wait4
261  or1k  prlimit64                sys_prlimit64
262  or1k  fanotify_init            sys_fanotify_init
263  or1k  fanotify_mark            sys_fanotify_mark
264  or1k  name_to_handle_at        sys_name_to_handle_at
265  or1k  open_by_handle_at        sys_open_by_handle_at
266  or1k  clock_adjtime            sys_clock_adjtime
267  or1k  syncfs                   sys_syncfs
268  or1k  setns                    sys_setns
269  or1k  sendmmsg                 sys_sendmmsg
270  or1k  process_vm_readv         sys_process_vm_readv
271  or1k  process_vm_writev        sys_process_vm_writev
272  or1k  kcmp                     sys_kcmp
273  or1k  finit_module             sys_finit_module
274  or1k  sched_setattr            sys_sched_setattr
275  or1k  sched_getattr            sys_sched_getattr
276  or1k  renameat2                sys_renameat2
277  or1k  seccomp                  sys_seccomp
278  or1k  getrandom                sys_getrandom
279  or1k  memfd_create             sys_memfd_create
280  or1k  bpf                      sys_bpf
281  or1k  execveat                 sys_execveat
282  or1k  userfaultfd              sys_userfaultfd
283  or1k  membarrier               sys_membarrier
284  or1k  mlock2                   sys_mlock2
285  or1k  copy_file_range          sys_copy_file_range
286  or1k  preadv2                  sys_preadv2
287  or1k  pwritev2                 sys_pwritev2
288  or1k  pkey_mprotect            sys_pkey_mprotect
289  or1k  pkey_alloc               sys_pkey_alloc
290  or1k  pkey_free                sys_pkey_free
291  or1k  statx                    sys_statx
292  or1k  io_pgetevents            sys_io_pgetevents
293  or1k  rseq                     sys_rseq
294  or1k  kexec_file_load          sys_kexec_file_load
424  or1k  pidfd_send_signal        sys_pidfd_send_signal
425  or1k  io_uring_setup           sys_io_uring_setup
426  or1k  io_uring_enter           sys_io_uring_enter
427  or1k  io_uring_register        sys_io_uring_register
428  or1k  open_tree                sys_open_tree
429  or1k  move_mount               sys_move_mount
430  or1k  fsopen                   sys_fsopen
431  or1k  fsconfig                 sys_fsconfig
432  or1k  fsmount                  sys_fsmount
433  or1k  fspick                   sys_fspick
434  or1k  pidfd_open               sys_pidfd_open
435  or1k  clone3                   sys_clone3
436  or1k  close_range              sys_close_range
437  or1k  openat2                  sys_openat2
438  or1k  pidfd_getfd              sys_pidfd_getfd
439  or1k  faccessat2               sys_faccessat2
440  or1k  process_madvise          sys_process_madvise
441  or1k  epoll_pwait2             sys_epoll_pwait2
442  or1k  mount_setattr            sys_mount_setattr
443  or1k  quotactl_fd              sys_quotactl_fd
444  or1k  landlock_create_ruleset  sys_landlock_create_ruleset
445  or1k  landlock_add_rule        sys_landlock_add_rule
446  or1k  landlock_restrict_self   sys_landlock_restrict_self
448  or1k  process_mrelease         sys_process_mrelease
449  or1k  futex_waitv              sys_futex_waitv
450  or1k  set_mempolicy_home_node  sys_set_mempolicy_home_node
451  or1k  cachestat                sys_cachestat
452  or1k  fchmodat2                sys_fchmodat2
453  or1k  map_shadow_stack         sys_map_shadow_stack
454  or1k  futex_wake               sys_futex_wake
455  or1k  futex_wait               sys_futex_wait
456  or1k  futex_requeue            sys_futex_requeue
457  or1k  statmount                sys_statmount
458  or1k  listmount                sys_listmount
459  or1k  lsm_get_self_attr        sys_lsm_get_self_attr
460  or1k  lsm_set_self_attr        sys_lsm_set_self_attr
461  or1k  lsm_list_modules         sys_lsm_list_modules
462  or1k  mseal                    sys_mseal
"""


# Nios II
#
# [How to make]
# cd /path/to/linux-6.*/
# gcc -I `pwd`/include/uapi/ -E -D__SYSCALL=SYSCALL arch/nios2/include/uapi/asm/unistd.h \
# | grep ^SYSCALL | sed -e 's/SYSCALL(//;s/[,)]//g' > /tmp/a
# grep -oP "__NR\S+\s+\d+$" include/uapi/asm-generic/unistd.h | grep -v __NR_sync_file_range2 > /tmp/b
# join -2 2 -o 1.1,1.10,2.1,1.2 -e nios2 /tmp/a /tmp/b | sed -e 's/\(__NR_\|__NR3264_\)//g' | column -t
#
nios2_syscall_tbl = """
0    nios2  io_setup                 sys_io_setup
1    nios2  io_destroy               sys_io_destroy
2    nios2  io_submit                sys_io_submit
3    nios2  io_cancel                sys_io_cancel
4    nios2  io_getevents             sys_io_getevents
5    nios2  setxattr                 sys_setxattr
6    nios2  lsetxattr                sys_lsetxattr
7    nios2  fsetxattr                sys_fsetxattr
8    nios2  getxattr                 sys_getxattr
9    nios2  lgetxattr                sys_lgetxattr
10   nios2  fgetxattr                sys_fgetxattr
11   nios2  listxattr                sys_listxattr
12   nios2  llistxattr               sys_llistxattr
13   nios2  flistxattr               sys_flistxattr
14   nios2  removexattr              sys_removexattr
15   nios2  lremovexattr             sys_lremovexattr
16   nios2  fremovexattr             sys_fremovexattr
17   nios2  getcwd                   sys_getcwd
18   nios2  lookup_dcookie           sys_ni_syscall
19   nios2  eventfd2                 sys_eventfd2
20   nios2  epoll_create1            sys_epoll_create1
21   nios2  epoll_ctl                sys_epoll_ctl
22   nios2  epoll_pwait              sys_epoll_pwait
23   nios2  dup                      sys_dup
24   nios2  dup3                     sys_dup3
25   nios2  fcntl                    sys_fcntl
26   nios2  inotify_init1            sys_inotify_init1
27   nios2  inotify_add_watch        sys_inotify_add_watch
28   nios2  inotify_rm_watch         sys_inotify_rm_watch
29   nios2  ioctl                    sys_ioctl
30   nios2  ioprio_set               sys_ioprio_set
31   nios2  ioprio_get               sys_ioprio_get
32   nios2  flock                    sys_flock
33   nios2  mknodat                  sys_mknodat
34   nios2  mkdirat                  sys_mkdirat
35   nios2  unlinkat                 sys_unlinkat
36   nios2  symlinkat                sys_symlinkat
37   nios2  linkat                   sys_linkat
38   nios2  renameat                 sys_renameat
39   nios2  umount2                  sys_umount
40   nios2  mount                    sys_mount
41   nios2  pivot_root               sys_pivot_root
42   nios2  nfsservctl               sys_ni_syscall
43   nios2  statfs                   sys_statfs
44   nios2  fstatfs                  sys_fstatfs
45   nios2  truncate                 sys_truncate
46   nios2  ftruncate                sys_ftruncate
47   nios2  fallocate                sys_fallocate
48   nios2  faccessat                sys_faccessat
49   nios2  chdir                    sys_chdir
50   nios2  fchdir                   sys_fchdir
51   nios2  chroot                   sys_chroot
52   nios2  fchmod                   sys_fchmod
53   nios2  fchmodat                 sys_fchmodat
54   nios2  fchownat                 sys_fchownat
55   nios2  fchown                   sys_fchown
56   nios2  openat                   sys_openat
57   nios2  close                    sys_close
58   nios2  vhangup                  sys_vhangup
59   nios2  pipe2                    sys_pipe2
60   nios2  quotactl                 sys_quotactl
61   nios2  getdents64               sys_getdents64
62   nios2  lseek                    sys_lseek
63   nios2  read                     sys_read
64   nios2  write                    sys_write
65   nios2  readv                    sys_readv
66   nios2  writev                   sys_writev
67   nios2  pread64                  sys_pread64
68   nios2  pwrite64                 sys_pwrite64
69   nios2  preadv                   sys_preadv
70   nios2  pwritev                  sys_pwritev
71   nios2  sendfile                 sys_sendfile64
72   nios2  pselect6                 sys_pselect6
73   nios2  ppoll                    sys_ppoll
74   nios2  signalfd4                sys_signalfd4
75   nios2  vmsplice                 sys_vmsplice
76   nios2  splice                   sys_splice
77   nios2  tee                      sys_tee
78   nios2  readlinkat               sys_readlinkat
79   nios2  fstatat                  sys_newfstatat
80   nios2  fstat                    sys_newfstat
81   nios2  sync                     sys_sync
82   nios2  fsync                    sys_fsync
83   nios2  fdatasync                sys_fdatasync
84   nios2  sync_file_range          sys_sync_file_range
85   nios2  timerfd_create           sys_timerfd_create
86   nios2  timerfd_settime          sys_timerfd_settime
87   nios2  timerfd_gettime          sys_timerfd_gettime
88   nios2  utimensat                sys_utimensat
89   nios2  acct                     sys_acct
90   nios2  capget                   sys_capget
91   nios2  capset                   sys_capset
92   nios2  personality              sys_personality
93   nios2  exit                     sys_exit
94   nios2  exit_group               sys_exit_group
95   nios2  waitid                   sys_waitid
96   nios2  set_tid_address          sys_set_tid_address
97   nios2  unshare                  sys_unshare
98   nios2  futex                    sys_futex
99   nios2  set_robust_list          sys_set_robust_list
100  nios2  get_robust_list          sys_get_robust_list
101  nios2  nanosleep                sys_nanosleep
102  nios2  getitimer                sys_getitimer
103  nios2  setitimer                sys_setitimer
104  nios2  kexec_load               sys_kexec_load
105  nios2  init_module              sys_init_module
106  nios2  delete_module            sys_delete_module
107  nios2  timer_create             sys_timer_create
108  nios2  timer_gettime            sys_timer_gettime
109  nios2  timer_getoverrun         sys_timer_getoverrun
110  nios2  timer_settime            sys_timer_settime
111  nios2  timer_delete             sys_timer_delete
112  nios2  clock_settime            sys_clock_settime
113  nios2  clock_gettime            sys_clock_gettime
114  nios2  clock_getres             sys_clock_getres
115  nios2  clock_nanosleep          sys_clock_nanosleep
116  nios2  syslog                   sys_syslog
117  nios2  ptrace                   sys_ptrace
118  nios2  sched_setparam           sys_sched_setparam
119  nios2  sched_setscheduler       sys_sched_setscheduler
120  nios2  sched_getscheduler       sys_sched_getscheduler
121  nios2  sched_getparam           sys_sched_getparam
122  nios2  sched_setaffinity        sys_sched_setaffinity
123  nios2  sched_getaffinity        sys_sched_getaffinity
124  nios2  sched_yield              sys_sched_yield
125  nios2  sched_get_priority_max   sys_sched_get_priority_max
126  nios2  sched_get_priority_min   sys_sched_get_priority_min
127  nios2  sched_rr_get_interval    sys_sched_rr_get_interval
128  nios2  restart_syscall          sys_restart_syscall
129  nios2  kill                     sys_kill
130  nios2  tkill                    sys_tkill
131  nios2  tgkill                   sys_tgkill
132  nios2  sigaltstack              sys_sigaltstack
133  nios2  rt_sigsuspend            sys_rt_sigsuspend
134  nios2  rt_sigaction             sys_rt_sigaction
135  nios2  rt_sigprocmask           sys_rt_sigprocmask
136  nios2  rt_sigpending            sys_rt_sigpending
137  nios2  rt_sigtimedwait          sys_rt_sigtimedwait
138  nios2  rt_sigqueueinfo          sys_rt_sigqueueinfo
139  nios2  rt_sigreturn             sys_rt_sigreturn
140  nios2  setpriority              sys_setpriority
141  nios2  getpriority              sys_getpriority
142  nios2  reboot                   sys_reboot
143  nios2  setregid                 sys_setregid
144  nios2  setgid                   sys_setgid
145  nios2  setreuid                 sys_setreuid
146  nios2  setuid                   sys_setuid
147  nios2  setresuid                sys_setresuid
148  nios2  getresuid                sys_getresuid
149  nios2  setresgid                sys_setresgid
150  nios2  getresgid                sys_getresgid
151  nios2  setfsuid                 sys_setfsuid
152  nios2  setfsgid                 sys_setfsgid
153  nios2  times                    sys_times
154  nios2  setpgid                  sys_setpgid
155  nios2  getpgid                  sys_getpgid
156  nios2  getsid                   sys_getsid
157  nios2  setsid                   sys_setsid
158  nios2  getgroups                sys_getgroups
159  nios2  setgroups                sys_setgroups
160  nios2  uname                    sys_newuname
161  nios2  sethostname              sys_sethostname
162  nios2  setdomainname            sys_setdomainname
163  nios2  getrlimit                sys_getrlimit
164  nios2  setrlimit                sys_setrlimit
165  nios2  getrusage                sys_getrusage
166  nios2  umask                    sys_umask
167  nios2  prctl                    sys_prctl
168  nios2  getcpu                   sys_getcpu
169  nios2  gettimeofday             sys_gettimeofday
170  nios2  settimeofday             sys_settimeofday
171  nios2  adjtimex                 sys_adjtimex
172  nios2  getpid                   sys_getpid
173  nios2  getppid                  sys_getppid
174  nios2  getuid                   sys_getuid
175  nios2  geteuid                  sys_geteuid
176  nios2  getgid                   sys_getgid
177  nios2  getegid                  sys_getegid
178  nios2  gettid                   sys_gettid
179  nios2  sysinfo                  sys_sysinfo
180  nios2  mq_open                  sys_mq_open
181  nios2  mq_unlink                sys_mq_unlink
182  nios2  mq_timedsend             sys_mq_timedsend
183  nios2  mq_timedreceive          sys_mq_timedreceive
184  nios2  mq_notify                sys_mq_notify
185  nios2  mq_getsetattr            sys_mq_getsetattr
186  nios2  msgget                   sys_msgget
187  nios2  msgctl                   sys_msgctl
188  nios2  msgrcv                   sys_msgrcv
189  nios2  msgsnd                   sys_msgsnd
190  nios2  semget                   sys_semget
191  nios2  semctl                   sys_semctl
192  nios2  semtimedop               sys_semtimedop
193  nios2  semop                    sys_semop
194  nios2  shmget                   sys_shmget
195  nios2  shmctl                   sys_shmctl
196  nios2  shmat                    sys_shmat
197  nios2  shmdt                    sys_shmdt
198  nios2  socket                   sys_socket
199  nios2  socketpair               sys_socketpair
200  nios2  bind                     sys_bind
201  nios2  listen                   sys_listen
202  nios2  accept                   sys_accept
203  nios2  connect                  sys_connect
204  nios2  getsockname              sys_getsockname
205  nios2  getpeername              sys_getpeername
206  nios2  sendto                   sys_sendto
207  nios2  recvfrom                 sys_recvfrom
208  nios2  setsockopt               sys_setsockopt
209  nios2  getsockopt               sys_getsockopt
210  nios2  shutdown                 sys_shutdown
211  nios2  sendmsg                  sys_sendmsg
212  nios2  recvmsg                  sys_recvmsg
213  nios2  readahead                sys_readahead
214  nios2  brk                      sys_brk
215  nios2  munmap                   sys_munmap
216  nios2  mremap                   sys_mremap
217  nios2  add_key                  sys_add_key
218  nios2  request_key              sys_request_key
219  nios2  keyctl                   sys_keyctl
220  nios2  clone                    sys_clone
221  nios2  execve                   sys_execve
222  nios2  mmap                     sys_mmap
223  nios2  fadvise64                sys_fadvise64_64
224  nios2  swapon                   sys_swapon
225  nios2  swapoff                  sys_swapoff
226  nios2  mprotect                 sys_mprotect
227  nios2  msync                    sys_msync
228  nios2  mlock                    sys_mlock
229  nios2  munlock                  sys_munlock
230  nios2  mlockall                 sys_mlockall
231  nios2  munlockall               sys_munlockall
232  nios2  mincore                  sys_mincore
233  nios2  madvise                  sys_madvise
234  nios2  remap_file_pages         sys_remap_file_pages
235  nios2  mbind                    sys_mbind
236  nios2  get_mempolicy            sys_get_mempolicy
237  nios2  set_mempolicy            sys_set_mempolicy
238  nios2  migrate_pages            sys_migrate_pages
239  nios2  move_pages               sys_move_pages
240  nios2  rt_tgsigqueueinfo        sys_rt_tgsigqueueinfo
241  nios2  perf_event_open          sys_perf_event_open
242  nios2  accept4                  sys_accept4
243  nios2  recvmmsg                 sys_recvmmsg
260  nios2  wait4                    sys_wait4
261  nios2  prlimit64                sys_prlimit64
262  nios2  fanotify_init            sys_fanotify_init
263  nios2  fanotify_mark            sys_fanotify_mark
264  nios2  name_to_handle_at        sys_name_to_handle_at
265  nios2  open_by_handle_at        sys_open_by_handle_at
266  nios2  clock_adjtime            sys_clock_adjtime
267  nios2  syncfs                   sys_syncfs
268  nios2  setns                    sys_setns
269  nios2  sendmmsg                 sys_sendmmsg
270  nios2  process_vm_readv         sys_process_vm_readv
271  nios2  process_vm_writev        sys_process_vm_writev
272  nios2  kcmp                     sys_kcmp
273  nios2  finit_module             sys_finit_module
274  nios2  sched_setattr            sys_sched_setattr
275  nios2  sched_getattr            sys_sched_getattr
276  nios2  renameat2                sys_renameat2
277  nios2  seccomp                  sys_seccomp
278  nios2  getrandom                sys_getrandom
279  nios2  memfd_create             sys_memfd_create
280  nios2  bpf                      sys_bpf
281  nios2  execveat                 sys_execveat
282  nios2  userfaultfd              sys_userfaultfd
283  nios2  membarrier               sys_membarrier
284  nios2  mlock2                   sys_mlock2
285  nios2  copy_file_range          sys_copy_file_range
286  nios2  preadv2                  sys_preadv2
287  nios2  pwritev2                 sys_pwritev2
288  nios2  pkey_mprotect            sys_pkey_mprotect
289  nios2  pkey_alloc               sys_pkey_alloc
290  nios2  pkey_free                sys_pkey_free
291  nios2  statx                    sys_statx
292  nios2  io_pgetevents            sys_io_pgetevents
293  nios2  rseq                     sys_rseq
294  nios2  kexec_file_load          sys_kexec_file_load
424  nios2  pidfd_send_signal        sys_pidfd_send_signal
425  nios2  io_uring_setup           sys_io_uring_setup
426  nios2  io_uring_enter           sys_io_uring_enter
427  nios2  io_uring_register        sys_io_uring_register
428  nios2  open_tree                sys_open_tree
429  nios2  move_mount               sys_move_mount
430  nios2  fsopen                   sys_fsopen
431  nios2  fsconfig                 sys_fsconfig
432  nios2  fsmount                  sys_fsmount
433  nios2  fspick                   sys_fspick
434  nios2  pidfd_open               sys_pidfd_open
436  nios2  close_range              sys_close_range
437  nios2  openat2                  sys_openat2
438  nios2  pidfd_getfd              sys_pidfd_getfd
439  nios2  faccessat2               sys_faccessat2
440  nios2  process_madvise          sys_process_madvise
441  nios2  epoll_pwait2             sys_epoll_pwait2
442  nios2  mount_setattr            sys_mount_setattr
443  nios2  quotactl_fd              sys_quotactl_fd
444  nios2  landlock_create_ruleset  sys_landlock_create_ruleset
445  nios2  landlock_add_rule        sys_landlock_add_rule
446  nios2  landlock_restrict_self   sys_landlock_restrict_self
448  nios2  process_mrelease         sys_process_mrelease
449  nios2  futex_waitv              sys_futex_waitv
450  nios2  set_mempolicy_home_node  sys_set_mempolicy_home_node
451  nios2  cachestat                sys_cachestat
452  nios2  fchmodat2                sys_fchmodat2
453  nios2  map_shadow_stack         sys_map_shadow_stack
454  nios2  futex_wake               sys_futex_wake
455  nios2  futex_wait               sys_futex_wait
456  nios2  futex_requeue            sys_futex_requeue
457  nios2  statmount                sys_statmount
458  nios2  listmount                sys_listmount
459  nios2  lsm_get_self_attr        sys_lsm_get_self_attr
460  nios2  lsm_set_self_attr        sys_lsm_set_self_attr
461  nios2  lsm_list_modules         sys_lsm_list_modules
462  nios2  mseal                    sys_mseal
"""


# MicroBlaze
# - arch/microblaze/kernel/syscalls/syscall.tbl
microblaze_syscall_tbl = """
# system call numbers and entry vectors for microblaze
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The <abi> is always "common" for this file
#
0       common  restart_syscall                 sys_restart_syscall
1       common  exit                            sys_exit
2       common  fork                            sys_fork
3       common  read                            sys_read
4       common  write                           sys_write
5       common  open                            sys_open
6       common  close                           sys_close
7       common  waitpid                         sys_waitpid
8       common  creat                           sys_creat
9       common  link                            sys_link
10      common  unlink                          sys_unlink
11      common  execve                          sys_execve
12      common  chdir                           sys_chdir
13      common  time                            sys_time32
14      common  mknod                           sys_mknod
15      common  chmod                           sys_chmod
16      common  lchown                          sys_lchown
17      common  break                           sys_ni_syscall
18      common  oldstat                         sys_ni_syscall
19      common  lseek                           sys_lseek
20      common  getpid                          sys_getpid
21      common  mount                           sys_mount
22      common  umount                          sys_oldumount
23      common  setuid                          sys_setuid
24      common  getuid                          sys_getuid
25      common  stime                           sys_stime32
26      common  ptrace                          sys_ptrace
27      common  alarm                           sys_alarm
28      common  oldfstat                        sys_ni_syscall
29      common  pause                           sys_pause
30      common  utime                           sys_utime32
31      common  stty                            sys_ni_syscall
32      common  gtty                            sys_ni_syscall
33      common  access                          sys_access
34      common  nice                            sys_nice
35      common  ftime                           sys_ni_syscall
36      common  sync                            sys_sync
37      common  kill                            sys_kill
38      common  rename                          sys_rename
39      common  mkdir                           sys_mkdir
40      common  rmdir                           sys_rmdir
41      common  dup                             sys_dup
42      common  pipe                            sys_pipe
43      common  times                           sys_times
44      common  prof                            sys_ni_syscall
45      common  brk                             sys_brk
46      common  setgid                          sys_setgid
47      common  getgid                          sys_getgid
48      common  signal                          sys_signal
49      common  geteuid                         sys_geteuid
50      common  getegid                         sys_getegid
51      common  acct                            sys_acct
52      common  umount2                         sys_umount
53      common  lock                            sys_ni_syscall
54      common  ioctl                           sys_ioctl
55      common  fcntl                           sys_fcntl
56      common  mpx                             sys_ni_syscall
57      common  setpgid                         sys_setpgid
58      common  ulimit                          sys_ni_syscall
59      common  oldolduname                     sys_ni_syscall
60      common  umask                           sys_umask
61      common  chroot                          sys_chroot
62      common  ustat                           sys_ustat
63      common  dup2                            sys_dup2
64      common  getppid                         sys_getppid
65      common  getpgrp                         sys_getpgrp
66      common  setsid                          sys_setsid
67      common  sigaction                       sys_ni_syscall
68      common  sgetmask                        sys_sgetmask
69      common  ssetmask                        sys_ssetmask
70      common  setreuid                        sys_setreuid
71      common  setregid                        sys_setregid
72      common  sigsuspend                      sys_ni_syscall
73      common  sigpending                      sys_sigpending
74      common  sethostname                     sys_sethostname
75      common  setrlimit                       sys_setrlimit
76      common  getrlimit                       sys_ni_syscall
77      common  getrusage                       sys_getrusage
78      common  gettimeofday                    sys_gettimeofday
79      common  settimeofday                    sys_settimeofday
80      common  getgroups                       sys_getgroups
81      common  setgroups                       sys_setgroups
82      common  select                          sys_ni_syscall
83      common  symlink                         sys_symlink
84      common  oldlstat                        sys_ni_syscall
85      common  readlink                        sys_readlink
86      common  uselib                          sys_uselib
87      common  swapon                          sys_swapon
88      common  reboot                          sys_reboot
89      common  readdir                         sys_ni_syscall
90      common  mmap                            sys_mmap
91      common  munmap                          sys_munmap
92      common  truncate                        sys_truncate
93      common  ftruncate                       sys_ftruncate
94      common  fchmod                          sys_fchmod
95      common  fchown                          sys_fchown
96      common  getpriority                     sys_getpriority
97      common  setpriority                     sys_setpriority
98      common  profil                          sys_ni_syscall
99      common  statfs                          sys_statfs
100     common  fstatfs                         sys_fstatfs
101     common  ioperm                          sys_ni_syscall
102     common  socketcall                      sys_socketcall
103     common  syslog                          sys_syslog
104     common  setitimer                       sys_setitimer
105     common  getitimer                       sys_getitimer
106     common  stat                            sys_newstat
107     common  lstat                           sys_newlstat
108     common  fstat                           sys_newfstat
109     common  olduname                        sys_ni_syscall
110     common  iopl                            sys_ni_syscall
111     common  vhangup                         sys_vhangup
112     common  idle                            sys_ni_syscall
113     common  vm86old                         sys_ni_syscall
114     common  wait4                           sys_wait4
115     common  swapoff                         sys_swapoff
116     common  sysinfo                         sys_sysinfo
117     common  ipc                             sys_ni_syscall
118     common  fsync                           sys_fsync
119     common  sigreturn                       sys_ni_syscall
120     common  clone                           sys_clone
121     common  setdomainname                   sys_setdomainname
122     common  uname                           sys_newuname
123     common  modify_ldt                      sys_ni_syscall
124     common  adjtimex                        sys_adjtimex_time32
125     common  mprotect                        sys_mprotect
126     common  sigprocmask                     sys_sigprocmask
127     common  create_module                   sys_ni_syscall
128     common  init_module                     sys_init_module
129     common  delete_module                   sys_delete_module
130     common  get_kernel_syms                 sys_ni_syscall
131     common  quotactl                        sys_quotactl
132     common  getpgid                         sys_getpgid
133     common  fchdir                          sys_fchdir
134     common  bdflush                         sys_ni_syscall
135     common  sysfs                           sys_sysfs
136     common  personality                     sys_personality
137     common  afs_syscall                     sys_ni_syscall
138     common  setfsuid                        sys_setfsuid
139     common  setfsgid                        sys_setfsgid
140     common  _llseek                         sys_llseek
141     common  getdents                        sys_getdents
142     common  _newselect                      sys_select
143     common  flock                           sys_flock
144     common  msync                           sys_msync
145     common  readv                           sys_readv
146     common  writev                          sys_writev
147     common  getsid                          sys_getsid
148     common  fdatasync                       sys_fdatasync
149     common  _sysctl                         sys_ni_syscall
150     common  mlock                           sys_mlock
151     common  munlock                         sys_munlock
152     common  mlockall                        sys_mlockall
153     common  munlockall                      sys_munlockall
154     common  sched_setparam                  sys_sched_setparam
155     common  sched_getparam                  sys_sched_getparam
156     common  sched_setscheduler              sys_sched_setscheduler
157     common  sched_getscheduler              sys_sched_getscheduler
158     common  sched_yield                     sys_sched_yield
159     common  sched_get_priority_max          sys_sched_get_priority_max
160     common  sched_get_priority_min          sys_sched_get_priority_min
161     common  sched_rr_get_interval           sys_sched_rr_get_interval_time32
162     common  nanosleep                       sys_nanosleep_time32
163     common  mremap                          sys_mremap
164     common  setresuid                       sys_setresuid
165     common  getresuid                       sys_getresuid
166     common  vm86                            sys_ni_syscall
167     common  query_module                    sys_ni_syscall
168     common  poll                            sys_poll
169     common  nfsservctl                      sys_ni_syscall
170     common  setresgid                       sys_setresgid
171     common  getresgid                       sys_getresgid
172     common  prctl                           sys_prctl
173     common  rt_sigreturn                    sys_rt_sigreturn_wrapper
174     common  rt_sigaction                    sys_rt_sigaction
175     common  rt_sigprocmask                  sys_rt_sigprocmask
176     common  rt_sigpending                   sys_rt_sigpending
177     common  rt_sigtimedwait                 sys_rt_sigtimedwait_time32
178     common  rt_sigqueueinfo                 sys_rt_sigqueueinfo
179     common  rt_sigsuspend                   sys_rt_sigsuspend
180     common  pread64                         sys_pread64
181     common  pwrite64                        sys_pwrite64
182     common  chown                           sys_chown
183     common  getcwd                          sys_getcwd
184     common  capget                          sys_capget
185     common  capset                          sys_capset
186     common  sigaltstack                     sys_ni_syscall
187     common  sendfile                        sys_sendfile
188     common  getpmsg                         sys_ni_syscall
189     common  putpmsg                         sys_ni_syscall
190     common  vfork                           sys_vfork
191     common  ugetrlimit                      sys_getrlimit
192     common  mmap2                           sys_mmap2
193     common  truncate64                      sys_truncate64
194     common  ftruncate64                     sys_ftruncate64
195     common  stat64                          sys_stat64
196     common  lstat64                         sys_lstat64
197     common  fstat64                         sys_fstat64
198     common  lchown32                        sys_lchown
199     common  getuid32                        sys_getuid
200     common  getgid32                        sys_getgid
201     common  geteuid32                       sys_geteuid
202     common  getegid32                       sys_getegid
203     common  setreuid32                      sys_setreuid
204     common  setregid32                      sys_setregid
205     common  getgroups32                     sys_getgroups
206     common  setgroups32                     sys_setgroups
207     common  fchown32                        sys_fchown
208     common  setresuid32                     sys_setresuid
209     common  getresuid32                     sys_getresuid
210     common  setresgid32                     sys_setresgid
211     common  getresgid32                     sys_getresgid
212     common  chown32                         sys_chown
213     common  setuid32                        sys_setuid
214     common  setgid32                        sys_setgid
215     common  setfsuid32                      sys_setfsuid
216     common  setfsgid32                      sys_setfsgid
217     common  pivot_root                      sys_pivot_root
218     common  mincore                         sys_mincore
219     common  madvise                         sys_madvise
220     common  getdents64                      sys_getdents64
221     common  fcntl64                         sys_fcntl64
# 222 is reserved for TUX
# 223 is unused
224     common  gettid                          sys_gettid
225     common  readahead                       sys_readahead
226     common  setxattr                        sys_setxattr
227     common  lsetxattr                       sys_lsetxattr
228     common  fsetxattr                       sys_fsetxattr
229     common  getxattr                        sys_getxattr
230     common  lgetxattr                       sys_lgetxattr
231     common  fgetxattr                       sys_fgetxattr
232     common  listxattr                       sys_listxattr
233     common  llistxattr                      sys_llistxattr
234     common  flistxattr                      sys_flistxattr
235     common  removexattr                     sys_removexattr
236     common  lremovexattr                    sys_lremovexattr
237     common  fremovexattr                    sys_fremovexattr
238     common  tkill                           sys_tkill
239     common  sendfile64                      sys_sendfile64
240     common  futex                           sys_futex_time32
241     common  sched_setaffinity               sys_sched_setaffinity
242     common  sched_getaffinity               sys_sched_getaffinity
243     common  set_thread_area                 sys_ni_syscall
244     common  get_thread_area                 sys_ni_syscall
245     common  io_setup                        sys_io_setup
246     common  io_destroy                      sys_io_destroy
247     common  io_getevents                    sys_io_getevents_time32
248     common  io_submit                       sys_io_submit
249     common  io_cancel                       sys_io_cancel
250     common  fadvise64                       sys_fadvise64
# 251 is available for reuse (was briefly sys_set_zone_reclaim)
252     common  exit_group                      sys_exit_group
253     common  lookup_dcookie                  sys_ni_syscall
254     common  epoll_create                    sys_epoll_create
255     common  epoll_ctl                       sys_epoll_ctl
256     common  epoll_wait                      sys_epoll_wait
257     common  remap_file_pages                sys_remap_file_pages
258     common  set_tid_address                 sys_set_tid_address
259     common  timer_create                    sys_timer_create
260     common  timer_settime                   sys_timer_settime32
261     common  timer_gettime                   sys_timer_gettime32
262     common  timer_getoverrun                sys_timer_getoverrun
263     common  timer_delete                    sys_timer_delete
264     common  clock_settime                   sys_clock_settime32
265     common  clock_gettime                   sys_clock_gettime32
266     common  clock_getres                    sys_clock_getres_time32
267     common  clock_nanosleep                 sys_clock_nanosleep_time32
268     common  statfs64                        sys_statfs64
269     common  fstatfs64                       sys_fstatfs64
270     common  tgkill                          sys_tgkill
271     common  utimes                          sys_utimes_time32
272     common  fadvise64_64                    sys_fadvise64_64
273     common  vserver                         sys_ni_syscall
274     common  mbind                           sys_mbind
275     common  get_mempolicy                   sys_get_mempolicy
276     common  set_mempolicy                   sys_set_mempolicy
277     common  mq_open                         sys_mq_open
278     common  mq_unlink                       sys_mq_unlink
279     common  mq_timedsend                    sys_mq_timedsend_time32
280     common  mq_timedreceive                 sys_mq_timedreceive_time32
281     common  mq_notify                       sys_mq_notify
282     common  mq_getsetattr                   sys_mq_getsetattr
283     common  kexec_load                      sys_kexec_load
284     common  waitid                          sys_waitid
# 285 was setaltroot
286     common  add_key                         sys_add_key
287     common  request_key                     sys_request_key
288     common  keyctl                          sys_keyctl
289     common  ioprio_set                      sys_ioprio_set
290     common  ioprio_get                      sys_ioprio_get
291     common  inotify_init                    sys_inotify_init
292     common  inotify_add_watch               sys_inotify_add_watch
293     common  inotify_rm_watch                sys_inotify_rm_watch
294     common  migrate_pages                   sys_ni_syscall
295     common  openat                          sys_openat
296     common  mkdirat                         sys_mkdirat
297     common  mknodat                         sys_mknodat
298     common  fchownat                        sys_fchownat
299     common  futimesat                       sys_futimesat_time32
300     common  fstatat64                       sys_fstatat64
301     common  unlinkat                        sys_unlinkat
302     common  renameat                        sys_renameat
303     common  linkat                          sys_linkat
304     common  symlinkat                       sys_symlinkat
305     common  readlinkat                      sys_readlinkat
306     common  fchmodat                        sys_fchmodat
307     common  faccessat                       sys_faccessat
308     common  pselect6                        sys_pselect6_time32
309     common  ppoll                           sys_ppoll_time32
310     common  unshare                         sys_unshare
311     common  set_robust_list                 sys_set_robust_list
312     common  get_robust_list                 sys_get_robust_list
313     common  splice                          sys_splice
314     common  sync_file_range                 sys_sync_file_range
315     common  tee                             sys_tee
316     common  vmsplice                        sys_vmsplice
317     common  move_pages                      sys_move_pages
318     common  getcpu                          sys_getcpu
319     common  epoll_pwait                     sys_epoll_pwait
320     common  utimensat                       sys_utimensat_time32
321     common  signalfd                        sys_signalfd
322     common  timerfd_create                  sys_timerfd_create
323     common  eventfd                         sys_eventfd
324     common  fallocate                       sys_fallocate
325     common  semtimedop                      sys_semtimedop_time32
326     common  timerfd_settime                 sys_timerfd_settime32
327     common  timerfd_gettime                 sys_timerfd_gettime32
328     common  semctl                          sys_old_semctl
329     common  semget                          sys_semget
330     common  semop                           sys_semop
331     common  msgctl                          sys_old_msgctl
332     common  msgget                          sys_msgget
333     common  msgrcv                          sys_msgrcv
334     common  msgsnd                          sys_msgsnd
335     common  shmat                           sys_shmat
336     common  shmctl                          sys_old_shmctl
337     common  shmdt                           sys_shmdt
338     common  shmget                          sys_shmget
339     common  signalfd4                       sys_signalfd4
340     common  eventfd2                        sys_eventfd2
341     common  epoll_create1                   sys_epoll_create1
342     common  dup3                            sys_dup3
343     common  pipe2                           sys_pipe2
344     common  inotify_init1                   sys_inotify_init1
345     common  socket                          sys_socket
346     common  socketpair                      sys_socketpair
347     common  bind                            sys_bind
348     common  listen                          sys_listen
349     common  accept                          sys_accept
350     common  connect                         sys_connect
351     common  getsockname                     sys_getsockname
352     common  getpeername                     sys_getpeername
353     common  sendto                          sys_sendto
354     common  send                            sys_send
355     common  recvfrom                        sys_recvfrom
356     common  recv                            sys_recv
357     common  setsockopt                      sys_setsockopt
358     common  getsockopt                      sys_getsockopt
359     common  shutdown                        sys_shutdown
360     common  sendmsg                         sys_sendmsg
361     common  recvmsg                         sys_recvmsg
362     common  accept4                         sys_accept4
363     common  preadv                          sys_preadv
364     common  pwritev                         sys_pwritev
365     common  rt_tgsigqueueinfo               sys_rt_tgsigqueueinfo
366     common  perf_event_open                 sys_perf_event_open
367     common  recvmmsg                        sys_recvmmsg_time32
368     common  fanotify_init                   sys_fanotify_init
369     common  fanotify_mark                   sys_fanotify_mark
370     common  prlimit64                       sys_prlimit64
371     common  name_to_handle_at               sys_name_to_handle_at
372     common  open_by_handle_at               sys_open_by_handle_at
373     common  clock_adjtime                   sys_clock_adjtime32
374     common  syncfs                          sys_syncfs
375     common  setns                           sys_setns
376     common  sendmmsg                        sys_sendmmsg
377     common  process_vm_readv                sys_process_vm_readv
378     common  process_vm_writev               sys_process_vm_writev
379     common  kcmp                            sys_kcmp
380     common  finit_module                    sys_finit_module
381     common  sched_setattr                   sys_sched_setattr
382     common  sched_getattr                   sys_sched_getattr
383     common  renameat2                       sys_renameat2
384     common  seccomp                         sys_seccomp
385     common  getrandom                       sys_getrandom
386     common  memfd_create                    sys_memfd_create
387     common  bpf                             sys_bpf
388     common  execveat                        sys_execveat
389     common  userfaultfd                     sys_userfaultfd
390     common  membarrier                      sys_membarrier
391     common  mlock2                          sys_mlock2
392     common  copy_file_range                 sys_copy_file_range
393     common  preadv2                         sys_preadv2
394     common  pwritev2                        sys_pwritev2
395     common  pkey_mprotect                   sys_pkey_mprotect
396     common  pkey_alloc                      sys_pkey_alloc
397     common  pkey_free                       sys_pkey_free
398     common  statx                           sys_statx
399     common  io_pgetevents                   sys_io_pgetevents_time32
400     common  rseq                            sys_rseq
# 401 and 402 are unused
403     common  clock_gettime64                 sys_clock_gettime
404     common  clock_settime64                 sys_clock_settime
405     common  clock_adjtime64                 sys_clock_adjtime
406     common  clock_getres_time64             sys_clock_getres
407     common  clock_nanosleep_time64          sys_clock_nanosleep
408     common  timer_gettime64                 sys_timer_gettime
409     common  timer_settime64                 sys_timer_settime
410     common  timerfd_gettime64               sys_timerfd_gettime
411     common  timerfd_settime64               sys_timerfd_settime
412     common  utimensat_time64                sys_utimensat
413     common  pselect6_time64                 sys_pselect6
414     common  ppoll_time64                    sys_ppoll
416     common  io_pgetevents_time64            sys_io_pgetevents
417     common  recvmmsg_time64                 sys_recvmmsg
418     common  mq_timedsend_time64             sys_mq_timedsend
419     common  mq_timedreceive_time64          sys_mq_timedreceive
420     common  semtimedop_time64               sys_semtimedop
421     common  rt_sigtimedwait_time64          sys_rt_sigtimedwait
422     common  futex_time64                    sys_futex
423     common  sched_rr_get_interval_time64    sys_sched_rr_get_interval
424     common  pidfd_send_signal               sys_pidfd_send_signal
425     common  io_uring_setup                  sys_io_uring_setup
426     common  io_uring_enter                  sys_io_uring_enter
427     common  io_uring_register               sys_io_uring_register
428     common  open_tree                       sys_open_tree
429     common  move_mount                      sys_move_mount
430     common  fsopen                          sys_fsopen
431     common  fsconfig                        sys_fsconfig
432     common  fsmount                         sys_fsmount
433     common  fspick                          sys_fspick
434     common  pidfd_open                      sys_pidfd_open
435     common  clone3                          sys_clone3
436     common  close_range                     sys_close_range
437     common  openat2                         sys_openat2
438     common  pidfd_getfd                     sys_pidfd_getfd
439     common  faccessat2                      sys_faccessat2
440     common  process_madvise                 sys_process_madvise
441     common  epoll_pwait2                    sys_epoll_pwait2
442     common  mount_setattr                   sys_mount_setattr
443     common  quotactl_fd                     sys_quotactl_fd
444     common  landlock_create_ruleset         sys_landlock_create_ruleset
445     common  landlock_add_rule               sys_landlock_add_rule
446     common  landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     common  process_mrelease                sys_process_mrelease
449     common  futex_waitv                     sys_futex_waitv
450     common  set_mempolicy_home_node         sys_set_mempolicy_home_node
451     common  cachestat                       sys_cachestat
452     common  fchmodat2                       sys_fchmodat2
453     common  map_shadow_stack                sys_map_shadow_stack
454     common  futex_wake                      sys_futex_wake
455     common  futex_wait                      sys_futex_wait
456     common  futex_requeue                   sys_futex_requeue
457     common  statmount                       sys_statmount
458     common  listmount                       sys_listmount
459     common  lsm_get_self_attr               sys_lsm_get_self_attr
460     common  lsm_set_self_attr               sys_lsm_set_self_attr
461     common  lsm_list_modules                sys_lsm_list_modules
462     common  mseal                           sys_mseal
"""


# Xtensa
# arch/xtensa/kernel/syscalls/syscall.tbl
xtensa_syscall_tbl = """
# system call numbers and entry vectors for xtensa
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The <abi> is always "common" for this file
#
0       common  spill                           sys_ni_syscall
1       common  xtensa                          sys_ni_syscall
2       common  available4                      sys_ni_syscall
3       common  available5                      sys_ni_syscall
4       common  available6                      sys_ni_syscall
5       common  available7                      sys_ni_syscall
6       common  available8                      sys_ni_syscall
7       common  available9                      sys_ni_syscall
# File Operations
8       common  open                            sys_open
9       common  close                           sys_close
10      common  dup                             sys_dup
11      common  dup2                            sys_dup2
12      common  read                            sys_read
13      common  write                           sys_write
14      common  select                          sys_select
15      common  lseek                           sys_lseek
16      common  poll                            sys_poll
17      common  _llseek                         sys_llseek
18      common  epoll_wait                      sys_epoll_wait
19      common  epoll_ctl                       sys_epoll_ctl
20      common  epoll_create                    sys_epoll_create
21      common  creat                           sys_creat
22      common  truncate                        sys_truncate
23      common  ftruncate                       sys_ftruncate
24      common  readv                           sys_readv
25      common  writev                          sys_writev
26      common  fsync                           sys_fsync
27      common  fdatasync                       sys_fdatasync
28      common  truncate64                      sys_truncate64
29      common  ftruncate64                     sys_ftruncate64
30      common  pread64                         sys_pread64
31      common  pwrite64                        sys_pwrite64
32      common  link                            sys_link
33      common  rename                          sys_rename
34      common  symlink                         sys_symlink
35      common  readlink                        sys_readlink
36      common  mknod                           sys_mknod
37      common  pipe                            sys_pipe
38      common  unlink                          sys_unlink
39      common  rmdir                           sys_rmdir
40      common  mkdir                           sys_mkdir
41      common  chdir                           sys_chdir
42      common  fchdir                          sys_fchdir
43      common  getcwd                          sys_getcwd
44      common  chmod                           sys_chmod
45      common  chown                           sys_chown
46      common  stat                            sys_newstat
47      common  stat64                          sys_stat64
48      common  lchown                          sys_lchown
49      common  lstat                           sys_newlstat
50      common  lstat64                         sys_lstat64
51      common  available51                     sys_ni_syscall
52      common  fchmod                          sys_fchmod
53      common  fchown                          sys_fchown
54      common  fstat                           sys_newfstat
55      common  fstat64                         sys_fstat64
56      common  flock                           sys_flock
57      common  access                          sys_access
58      common  umask                           sys_umask
59      common  getdents                        sys_getdents
60      common  getdents64                      sys_getdents64
61      common  fcntl64                         sys_fcntl64
62      common  fallocate                       sys_fallocate
63      common  fadvise64_64                    xtensa_fadvise64_64
64      common  utime                           sys_utime32
65      common  utimes                          sys_utimes_time32
66      common  ioctl                           sys_ioctl
67      common  fcntl                           sys_fcntl
68      common  setxattr                        sys_setxattr
69      common  getxattr                        sys_getxattr
70      common  listxattr                       sys_listxattr
71      common  removexattr                     sys_removexattr
72      common  lsetxattr                       sys_lsetxattr
73      common  lgetxattr                       sys_lgetxattr
74      common  llistxattr                      sys_llistxattr
75      common  lremovexattr                    sys_lremovexattr
76      common  fsetxattr                       sys_fsetxattr
77      common  fgetxattr                       sys_fgetxattr
78      common  flistxattr                      sys_flistxattr
79      common  fremovexattr                    sys_fremovexattr
# File Map / Shared Memory Operations
80      common  mmap2                           sys_mmap_pgoff
81      common  munmap                          sys_munmap
82      common  mprotect                        sys_mprotect
83      common  brk                             sys_brk
84      common  mlock                           sys_mlock
85      common  munlock                         sys_munlock
86      common  mlockall                        sys_mlockall
87      common  munlockall                      sys_munlockall
88      common  mremap                          sys_mremap
89      common  msync                           sys_msync
90      common  mincore                         sys_mincore
91      common  madvise                         sys_madvise
92      common  shmget                          sys_shmget
93      common  shmat                           xtensa_shmat
94      common  shmctl                          sys_old_shmctl
95      common  shmdt                           sys_shmdt
# Socket Operations
96      common  socket                          sys_socket
97      common  setsockopt                      sys_setsockopt
98      common  getsockopt                      sys_getsockopt
99      common  shutdown                        sys_shutdown
100     common  bind                            sys_bind
101     common  connect                         sys_connect
102     common  listen                          sys_listen
103     common  accept                          sys_accept
104     common  getsockname                     sys_getsockname
105     common  getpeername                     sys_getpeername
106     common  sendmsg                         sys_sendmsg
107     common  recvmsg                         sys_recvmsg
108     common  send                            sys_send
109     common  recv                            sys_recv
110     common  sendto                          sys_sendto
111     common  recvfrom                        sys_recvfrom
112     common  socketpair                      sys_socketpair
113     common  sendfile                        sys_sendfile
114     common  sendfile64                      sys_sendfile64
115     common  sendmmsg                        sys_sendmmsg
# Process Operations
116     common  clone                           sys_clone
117     common  execve                          sys_execve
118     common  exit                            sys_exit
119     common  exit_group                      sys_exit_group
120     common  getpid                          sys_getpid
121     common  wait4                           sys_wait4
122     common  waitid                          sys_waitid
123     common  kill                            sys_kill
124     common  tkill                           sys_tkill
125     common  tgkill                          sys_tgkill
126     common  set_tid_address                 sys_set_tid_address
127     common  gettid                          sys_gettid
128     common  setsid                          sys_setsid
129     common  getsid                          sys_getsid
130     common  prctl                           sys_prctl
131     common  personality                     sys_personality
132     common  getpriority                     sys_getpriority
133     common  setpriority                     sys_setpriority
134     common  setitimer                       sys_setitimer
135     common  getitimer                       sys_getitimer
136     common  setuid                          sys_setuid
137     common  getuid                          sys_getuid
138     common  setgid                          sys_setgid
139     common  getgid                          sys_getgid
140     common  geteuid                         sys_geteuid
141     common  getegid                         sys_getegid
142     common  setreuid                        sys_setreuid
143     common  setregid                        sys_setregid
144     common  setresuid                       sys_setresuid
145     common  getresuid                       sys_getresuid
146     common  setresgid                       sys_setresgid
147     common  getresgid                       sys_getresgid
148     common  setpgid                         sys_setpgid
149     common  getpgid                         sys_getpgid
150     common  getppid                         sys_getppid
151     common  getpgrp                         sys_getpgrp
# 152 was set_thread_area
152     common  reserved152                     sys_ni_syscall
# 153 was get_thread_area
153     common  reserved153                     sys_ni_syscall
154     common  times                           sys_times
155     common  acct                            sys_acct
156     common  sched_setaffinity               sys_sched_setaffinity
157     common  sched_getaffinity               sys_sched_getaffinity
158     common  capget                          sys_capget
159     common  capset                          sys_capset
160     common  ptrace                          sys_ptrace
161     common  semtimedop                      sys_semtimedop_time32
162     common  semget                          sys_semget
163     common  semop                           sys_semop
164     common  semctl                          sys_old_semctl
165     common  available165                    sys_ni_syscall
166     common  msgget                          sys_msgget
167     common  msgsnd                          sys_msgsnd
168     common  msgrcv                          sys_msgrcv
169     common  msgctl                          sys_old_msgctl
170     common  available170                    sys_ni_syscall
# File System
171     common  umount2                         sys_umount
172     common  mount                           sys_mount
173     common  swapon                          sys_swapon
174     common  chroot                          sys_chroot
175     common  pivot_root                      sys_pivot_root
176     common  umount                          sys_oldumount
177     common  swapoff                         sys_swapoff
178     common  sync                            sys_sync
179     common  syncfs                          sys_syncfs
180     common  setfsuid                        sys_setfsuid
181     common  setfsgid                        sys_setfsgid
182     common  sysfs                           sys_sysfs
183     common  ustat                           sys_ustat
184     common  statfs                          sys_statfs
185     common  fstatfs                         sys_fstatfs
186     common  statfs64                        sys_statfs64
187     common  fstatfs64                       sys_fstatfs64
# System
188     common  setrlimit                       sys_setrlimit
189     common  getrlimit                       sys_getrlimit
190     common  getrusage                       sys_getrusage
191     common  futex                           sys_futex_time32
192     common  gettimeofday                    sys_gettimeofday
193     common  settimeofday                    sys_settimeofday
194     common  adjtimex                        sys_adjtimex_time32
195     common  nanosleep                       sys_nanosleep_time32
196     common  getgroups                       sys_getgroups
197     common  setgroups                       sys_setgroups
198     common  sethostname                     sys_sethostname
199     common  setdomainname                   sys_setdomainname
200     common  syslog                          sys_syslog
201     common  vhangup                         sys_vhangup
202     common  uselib                          sys_uselib
203     common  reboot                          sys_reboot
204     common  quotactl                        sys_quotactl
# 205 was old nfsservctl
205     common  nfsservctl                      sys_ni_syscall
206     common  _sysctl                         sys_ni_syscall
207     common  bdflush                         sys_ni_syscall
208     common  uname                           sys_newuname
209     common  sysinfo                         sys_sysinfo
210     common  init_module                     sys_init_module
211     common  delete_module                   sys_delete_module
212     common  sched_setparam                  sys_sched_setparam
213     common  sched_getparam                  sys_sched_getparam
214     common  sched_setscheduler              sys_sched_setscheduler
215     common  sched_getscheduler              sys_sched_getscheduler
216     common  sched_get_priority_max          sys_sched_get_priority_max
217     common  sched_get_priority_min          sys_sched_get_priority_min
218     common  sched_rr_get_interval           sys_sched_rr_get_interval_time32
219     common  sched_yield                     sys_sched_yield
222     common  available222                    sys_ni_syscall
# Signal Handling
223     common  restart_syscall                 sys_restart_syscall
224     common  sigaltstack                     sys_sigaltstack
225     common  rt_sigreturn                    xtensa_rt_sigreturn
226     common  rt_sigaction                    sys_rt_sigaction
227     common  rt_sigprocmask                  sys_rt_sigprocmask
228     common  rt_sigpending                   sys_rt_sigpending
229     common  rt_sigtimedwait                 sys_rt_sigtimedwait_time32
230     common  rt_sigqueueinfo                 sys_rt_sigqueueinfo
231     common  rt_sigsuspend                   sys_rt_sigsuspend
# Message
232     common  mq_open                         sys_mq_open
233     common  mq_unlink                       sys_mq_unlink
234     common  mq_timedsend                    sys_mq_timedsend_time32
235     common  mq_timedreceive                 sys_mq_timedreceive_time32
236     common  mq_notify                       sys_mq_notify
237     common  mq_getsetattr                   sys_mq_getsetattr
238     common  available238                    sys_ni_syscall
239     common  io_setup                        sys_io_setup
# IO
240     common  io_destroy                      sys_io_destroy
241     common  io_submit                       sys_io_submit
242     common  io_getevents                    sys_io_getevents_time32
243     common  io_cancel                       sys_io_cancel
244     common  clock_settime                   sys_clock_settime32
245     common  clock_gettime                   sys_clock_gettime32
246     common  clock_getres                    sys_clock_getres_time32
247     common  clock_nanosleep                 sys_clock_nanosleep_time32
# Timer
248     common  timer_create                    sys_timer_create
249     common  timer_delete                    sys_timer_delete
250     common  timer_settime                   sys_timer_settime32
251     common  timer_gettime                   sys_timer_gettime32
252     common  timer_getoverrun                sys_timer_getoverrun
# System
253     common  reserved253                     sys_ni_syscall
254     common  lookup_dcookie                  sys_ni_syscall
255     common  available255                    sys_ni_syscall
256     common  add_key                         sys_add_key
257     common  request_key                     sys_request_key
258     common  keyctl                          sys_keyctl
259     common  available259                    sys_ni_syscall
260     common  readahead                       sys_readahead
261     common  remap_file_pages                sys_remap_file_pages
262     common  migrate_pages                   sys_migrate_pages
263     common  mbind                           sys_mbind
264     common  get_mempolicy                   sys_get_mempolicy
265     common  set_mempolicy                   sys_set_mempolicy
266     common  unshare                         sys_unshare
267     common  move_pages                      sys_move_pages
268     common  splice                          sys_splice
269     common  tee                             sys_tee
270     common  vmsplice                        sys_vmsplice
271     common  available271                    sys_ni_syscall
272     common  pselect6                        sys_pselect6_time32
273     common  ppoll                           sys_ppoll_time32
274     common  epoll_pwait                     sys_epoll_pwait
275     common  epoll_create1                   sys_epoll_create1
276     common  inotify_init                    sys_inotify_init
277     common  inotify_add_watch               sys_inotify_add_watch
278     common  inotify_rm_watch                sys_inotify_rm_watch
279     common  inotify_init1                   sys_inotify_init1
280     common  getcpu                          sys_getcpu
281     common  kexec_load                      sys_ni_syscall
282     common  ioprio_set                      sys_ioprio_set
283     common  ioprio_get                      sys_ioprio_get
284     common  set_robust_list                 sys_set_robust_list
285     common  get_robust_list                 sys_get_robust_list
286     common  available286                    sys_ni_syscall
287     common  available287                    sys_ni_syscall
# Relative File Operations
288     common  openat                          sys_openat
289     common  mkdirat                         sys_mkdirat
290     common  mknodat                         sys_mknodat
291     common  unlinkat                        sys_unlinkat
292     common  renameat                        sys_renameat
293     common  linkat                          sys_linkat
294     common  symlinkat                       sys_symlinkat
295     common  readlinkat                      sys_readlinkat
296     common  utimensat                       sys_utimensat_time32
297     common  fchownat                        sys_fchownat
298     common  futimesat                       sys_futimesat_time32
299     common  fstatat64                       sys_fstatat64
300     common  fchmodat                        sys_fchmodat
301     common  faccessat                       sys_faccessat
302     common  available302                    sys_ni_syscall
303     common  available303                    sys_ni_syscall
304     common  signalfd                        sys_signalfd
# 305 was timerfd
306     common  eventfd                         sys_eventfd
307     common  recvmmsg                        sys_recvmmsg_time32
308     common  setns                           sys_setns
309     common  signalfd4                       sys_signalfd4
310     common  dup3                            sys_dup3
311     common  pipe2                           sys_pipe2
312     common  timerfd_create                  sys_timerfd_create
313     common  timerfd_settime                 sys_timerfd_settime32
314     common  timerfd_gettime                 sys_timerfd_gettime32
315     common  available315                    sys_ni_syscall
316     common  eventfd2                        sys_eventfd2
317     common  preadv                          sys_preadv
318     common  pwritev                         sys_pwritev
319     common  available319                    sys_ni_syscall
320     common  fanotify_init                   sys_fanotify_init
321     common  fanotify_mark                   sys_fanotify_mark
322     common  process_vm_readv                sys_process_vm_readv
323     common  process_vm_writev               sys_process_vm_writev
324     common  name_to_handle_at               sys_name_to_handle_at
325     common  open_by_handle_at               sys_open_by_handle_at
326     common  sync_file_range2                sys_sync_file_range2
327     common  perf_event_open                 sys_perf_event_open
328     common  rt_tgsigqueueinfo               sys_rt_tgsigqueueinfo
329     common  clock_adjtime                   sys_clock_adjtime32
330     common  prlimit64                       sys_prlimit64
331     common  kcmp                            sys_kcmp
332     common  finit_module                    sys_finit_module
333     common  accept4                         sys_accept4
334     common  sched_setattr                   sys_sched_setattr
335     common  sched_getattr                   sys_sched_getattr
336     common  renameat2                       sys_renameat2
337     common  seccomp                         sys_seccomp
338     common  getrandom                       sys_getrandom
339     common  memfd_create                    sys_memfd_create
340     common  bpf                             sys_bpf
341     common  execveat                        sys_execveat
342     common  userfaultfd                     sys_userfaultfd
343     common  membarrier                      sys_membarrier
344     common  mlock2                          sys_mlock2
345     common  copy_file_range                 sys_copy_file_range
346     common  preadv2                         sys_preadv2
347     common  pwritev2                        sys_pwritev2
348     common  pkey_mprotect                   sys_pkey_mprotect
349     common  pkey_alloc                      sys_pkey_alloc
350     common  pkey_free                       sys_pkey_free
351     common  statx                           sys_statx
352     common  rseq                            sys_rseq
# 353 through 402 are unassigned to sync up with generic numbers
403     common  clock_gettime64                 sys_clock_gettime
404     common  clock_settime64                 sys_clock_settime
405     common  clock_adjtime64                 sys_clock_adjtime
406     common  clock_getres_time64             sys_clock_getres
407     common  clock_nanosleep_time64          sys_clock_nanosleep
408     common  timer_gettime64                 sys_timer_gettime
409     common  timer_settime64                 sys_timer_settime
410     common  timerfd_gettime64               sys_timerfd_gettime
411     common  timerfd_settime64               sys_timerfd_settime
412     common  utimensat_time64                sys_utimensat
413     common  pselect6_time64                 sys_pselect6
414     common  ppoll_time64                    sys_ppoll
416     common  io_pgetevents_time64            sys_io_pgetevents
417     common  recvmmsg_time64                 sys_recvmmsg
418     common  mq_timedsend_time64             sys_mq_timedsend
419     common  mq_timedreceive_time64          sys_mq_timedreceive
420     common  semtimedop_time64               sys_semtimedop
421     common  rt_sigtimedwait_time64          sys_rt_sigtimedwait
422     common  futex_time64                    sys_futex
423     common  sched_rr_get_interval_time64    sys_sched_rr_get_interval
424     common  pidfd_send_signal               sys_pidfd_send_signal
425     common  io_uring_setup                  sys_io_uring_setup
426     common  io_uring_enter                  sys_io_uring_enter
427     common  io_uring_register               sys_io_uring_register
428     common  open_tree                       sys_open_tree
429     common  move_mount                      sys_move_mount
430     common  fsopen                          sys_fsopen
431     common  fsconfig                        sys_fsconfig
432     common  fsmount                         sys_fsmount
433     common  fspick                          sys_fspick
434     common  pidfd_open                      sys_pidfd_open
435     common  clone3                          sys_clone3
436     common  close_range                     sys_close_range
437     common  openat2                         sys_openat2
438     common  pidfd_getfd                     sys_pidfd_getfd
439     common  faccessat2                      sys_faccessat2
440     common  process_madvise                 sys_process_madvise
441     common  epoll_pwait2                    sys_epoll_pwait2
442     common  mount_setattr                   sys_mount_setattr
443     common  quotactl_fd                     sys_quotactl_fd
444     common  landlock_create_ruleset         sys_landlock_create_ruleset
445     common  landlock_add_rule               sys_landlock_add_rule
446     common  landlock_restrict_self          sys_landlock_restrict_self
# 447 reserved for memfd_secret
448     common  process_mrelease                sys_process_mrelease
449     common  futex_waitv                     sys_futex_waitv
450     common  set_mempolicy_home_node         sys_set_mempolicy_home_node
451     common  cachestat                       sys_cachestat
452     common  fchmodat2                       sys_fchmodat2
453     common  map_shadow_stack                sys_map_shadow_stack
454     common  futex_wake                      sys_futex_wake
455     common  futex_wait                      sys_futex_wait
456     common  futex_requeue                   sys_futex_requeue
457     common  statmount                       sys_statmount
458     common  listmount                       sys_listmount
459     common  lsm_get_self_attr               sys_lsm_get_self_attr
460     common  lsm_set_self_attr               sys_lsm_set_self_attr
461     common  lsm_list_modules                sys_lsm_list_modules
462     common  mseal                           sys_mseal
"""


# CRIS
# [How to make]
# cd /path/to/linux-4.16.18/
# awk '/sys_call_table:/,/^$/' arch/cris/arch-v10/kernel/entry.S \
# | grep -o "\.long \w*" | nl -v0 | awk '{print $1" cris "substr($3,5)" "$3}' |column -t
cris_syscall_tbl = """
0    cris  restart_syscall         sys_restart_syscall
1    cris  exit                    sys_exit
2    cris  fork                    sys_fork
3    cris  read                    sys_read
4    cris  write                   sys_write
5    cris  open                    sys_open
6    cris  close                   sys_close
7    cris  waitpid                 sys_waitpid
8    cris  creat                   sys_creat
9    cris  link                    sys_link
10   cris  unlink                  sys_unlink
11   cris  execve                  sys_execve
12   cris  chdir                   sys_chdir
13   cris  time                    sys_time
14   cris  mknod                   sys_mknod
15   cris  chmod                   sys_chmod
16   cris  lchown16                sys_lchown16
17   cris  ni_syscall              sys_ni_syscall
18   cris  stat                    sys_stat
19   cris  lseek                   sys_lseek
20   cris  getpid                  sys_getpid
21   cris  mount                   sys_mount
22   cris  oldumount               sys_oldumount
23   cris  setuid16                sys_setuid16
24   cris  getuid16                sys_getuid16
25   cris  stime                   sys_stime
26   cris  ptrace                  sys_ptrace
27   cris  alarm                   sys_alarm
28   cris  fstat                   sys_fstat
29   cris  pause                   sys_pause
30   cris  utime                   sys_utime
31   cris  ni_syscall              sys_ni_syscall
32   cris  ni_syscall              sys_ni_syscall
33   cris  access                  sys_access
34   cris  nice                    sys_nice
35   cris  ni_syscall              sys_ni_syscall
36   cris  sync                    sys_sync
37   cris  kill                    sys_kill
38   cris  rename                  sys_rename
39   cris  mkdir                   sys_mkdir
40   cris  rmdir                   sys_rmdir
41   cris  dup                     sys_dup
42   cris  pipe                    sys_pipe
43   cris  times                   sys_times
44   cris  ni_syscall              sys_ni_syscall
45   cris  brk                     sys_brk
46   cris  setgid16                sys_setgid16
47   cris  getgid16                sys_getgid16
48   cris  signal                  sys_signal
49   cris  geteuid16               sys_geteuid16
50   cris  getegid16               sys_getegid16
51   cris  acct                    sys_acct
52   cris  umount                  sys_umount
53   cris  ni_syscall              sys_ni_syscall
54   cris  ioctl                   sys_ioctl
55   cris  fcntl                   sys_fcntl
56   cris  ni_syscall              sys_ni_syscall
57   cris  setpgid                 sys_setpgid
58   cris  ni_syscall              sys_ni_syscall
59   cris  ni_syscall              sys_ni_syscall
60   cris  umask                   sys_umask
61   cris  chroot                  sys_chroot
62   cris  ustat                   sys_ustat
63   cris  dup2                    sys_dup2
64   cris  getppid                 sys_getppid
65   cris  getpgrp                 sys_getpgrp
66   cris  setsid                  sys_setsid
67   cris  sigaction               sys_sigaction
68   cris  sgetmask                sys_sgetmask
69   cris  ssetmask                sys_ssetmask
70   cris  setreuid16              sys_setreuid16
71   cris  setregid16              sys_setregid16
72   cris  sigsuspend              sys_sigsuspend
73   cris  sigpending              sys_sigpending
74   cris  sethostname             sys_sethostname
75   cris  setrlimit               sys_setrlimit
76   cris  old_getrlimit           sys_old_getrlimit
77   cris  getrusage               sys_getrusage
78   cris  gettimeofday            sys_gettimeofday
79   cris  settimeofday            sys_settimeofday
80   cris  getgroups16             sys_getgroups16
81   cris  setgroups16             sys_setgroups16
82   cris  select                  sys_select
83   cris  symlink                 sys_symlink
84   cris  lstat                   sys_lstat
85   cris  readlink                sys_readlink
86   cris  uselib                  sys_uselib
87   cris  swapon                  sys_swapon
88   cris  reboot                  sys_reboot
89   cris  old_readdir             sys_old_readdir
90   cris  old_mmap                sys_old_mmap
91   cris  munmap                  sys_munmap
92   cris  truncate                sys_truncate
93   cris  ftruncate               sys_ftruncate
94   cris  fchmod                  sys_fchmod
95   cris  fchown16                sys_fchown16
96   cris  getpriority             sys_getpriority
97   cris  setpriority             sys_setpriority
98   cris  ni_syscall              sys_ni_syscall
99   cris  statfs                  sys_statfs
100  cris  fstatfs                 sys_fstatfs
101  cris  ni_syscall              sys_ni_syscall
102  cris  socketcall              sys_socketcall
103  cris  syslog                  sys_syslog
104  cris  setitimer               sys_setitimer
105  cris  getitimer               sys_getitimer
106  cris  newstat                 sys_newstat
107  cris  newlstat                sys_newlstat
108  cris  newfstat                sys_newfstat
109  cris  ni_syscall              sys_ni_syscall
110  cris  ni_syscall              sys_ni_syscall
111  cris  vhangup                 sys_vhangup
112  cris  ni_syscall              sys_ni_syscall
113  cris  ni_syscall              sys_ni_syscall
114  cris  wait4                   sys_wait4
115  cris  swapoff                 sys_swapoff
116  cris  sysinfo                 sys_sysinfo
117  cris  ipc                     sys_ipc
118  cris  fsync                   sys_fsync
119  cris  sigreturn               sys_sigreturn
120  cris  clone                   sys_clone
121  cris  setdomainname           sys_setdomainname
122  cris  newuname                sys_newuname
123  cris  ni_syscall              sys_ni_syscall
124  cris  adjtimex                sys_adjtimex
125  cris  mprotect                sys_mprotect
126  cris  sigprocmask             sys_sigprocmask
127  cris  ni_syscall              sys_ni_syscall
128  cris  init_module             sys_init_module
129  cris  delete_module           sys_delete_module
130  cris  ni_syscall              sys_ni_syscall
131  cris  quotactl                sys_quotactl
132  cris  getpgid                 sys_getpgid
133  cris  fchdir                  sys_fchdir
134  cris  bdflush                 sys_bdflush
135  cris  sysfs                   sys_sysfs
136  cris  personality             sys_personality
137  cris  ni_syscall              sys_ni_syscall
138  cris  setfsuid16              sys_setfsuid16
139  cris  setfsgid16              sys_setfsgid16
140  cris  llseek                  sys_llseek
141  cris  getdents                sys_getdents
142  cris  select                  sys_select
143  cris  flock                   sys_flock
144  cris  msync                   sys_msync
145  cris  readv                   sys_readv
146  cris  writev                  sys_writev
147  cris  getsid                  sys_getsid
148  cris  fdatasync               sys_fdatasync
149  cris  sysctl                  sys_sysctl
150  cris  mlock                   sys_mlock
151  cris  munlock                 sys_munlock
152  cris  mlockall                sys_mlockall
153  cris  munlockall              sys_munlockall
154  cris  sched_setparam          sys_sched_setparam
155  cris  sched_getparam          sys_sched_getparam
156  cris  sched_setscheduler      sys_sched_setscheduler
157  cris  sched_getscheduler      sys_sched_getscheduler
158  cris  sched_yield             sys_sched_yield
159  cris  sched_get_priority_max  sys_sched_get_priority_max
160  cris  sched_get_priority_min  sys_sched_get_priority_min
161  cris  sched_rr_get_interval   sys_sched_rr_get_interval
162  cris  nanosleep               sys_nanosleep
163  cris  mremap                  sys_mremap
164  cris  setresuid16             sys_setresuid16
165  cris  getresuid16             sys_getresuid16
166  cris  ni_syscall              sys_ni_syscall
167  cris  ni_syscall              sys_ni_syscall
168  cris  poll                    sys_poll
169  cris  ni_syscall              sys_ni_syscall
170  cris  setresgid16             sys_setresgid16
171  cris  getresgid16             sys_getresgid16
172  cris  prctl                   sys_prctl
173  cris  rt_sigreturn            sys_rt_sigreturn
174  cris  rt_sigaction            sys_rt_sigaction
175  cris  rt_sigprocmask          sys_rt_sigprocmask
176  cris  rt_sigpending           sys_rt_sigpending
177  cris  rt_sigtimedwait         sys_rt_sigtimedwait
178  cris  rt_sigqueueinfo         sys_rt_sigqueueinfo
179  cris  rt_sigsuspend           sys_rt_sigsuspend
180  cris  pread64                 sys_pread64
181  cris  pwrite64                sys_pwrite64
182  cris  chown16                 sys_chown16
183  cris  getcwd                  sys_getcwd
184  cris  capget                  sys_capget
185  cris  capset                  sys_capset
186  cris  sigaltstack             sys_sigaltstack
187  cris  sendfile                sys_sendfile
188  cris  ni_syscall              sys_ni_syscall
189  cris  ni_syscall              sys_ni_syscall
190  cris  vfork                   sys_vfork
191  cris  getrlimit               sys_getrlimit
192  cris  mmap2                   sys_mmap2
193  cris  truncate64              sys_truncate64
194  cris  ftruncate64             sys_ftruncate64
195  cris  stat64                  sys_stat64
196  cris  lstat64                 sys_lstat64
197  cris  fstat64                 sys_fstat64
198  cris  lchown                  sys_lchown
199  cris  getuid                  sys_getuid
200  cris  getgid                  sys_getgid
201  cris  geteuid                 sys_geteuid
202  cris  getegid                 sys_getegid
203  cris  setreuid                sys_setreuid
204  cris  setregid                sys_setregid
205  cris  getgroups               sys_getgroups
206  cris  setgroups               sys_setgroups
207  cris  fchown                  sys_fchown
208  cris  setresuid               sys_setresuid
209  cris  getresuid               sys_getresuid
210  cris  setresgid               sys_setresgid
211  cris  getresgid               sys_getresgid
212  cris  chown                   sys_chown
213  cris  setuid                  sys_setuid
214  cris  setgid                  sys_setgid
215  cris  setfsuid                sys_setfsuid
216  cris  setfsgid                sys_setfsgid
217  cris  pivot_root              sys_pivot_root
218  cris  mincore                 sys_mincore
219  cris  madvise                 sys_madvise
220  cris  getdents64              sys_getdents64
221  cris  fcntl64                 sys_fcntl64
222  cris  ni_syscall              sys_ni_syscall
223  cris  ni_syscall              sys_ni_syscall
224  cris  gettid                  sys_gettid
225  cris  readahead               sys_readahead
226  cris  setxattr                sys_setxattr
227  cris  lsetxattr               sys_lsetxattr
228  cris  fsetxattr               sys_fsetxattr
229  cris  getxattr                sys_getxattr
230  cris  lgetxattr               sys_lgetxattr
231  cris  fgetxattr               sys_fgetxattr
232  cris  listxattr               sys_listxattr
233  cris  llistxattr              sys_llistxattr
234  cris  flistxattr              sys_flistxattr
235  cris  removexattr             sys_removexattr
236  cris  lremovexattr            sys_lremovexattr
237  cris  fremovexattr            sys_fremovexattr
238  cris  tkill                   sys_tkill
239  cris  sendfile64              sys_sendfile64
240  cris  futex                   sys_futex
241  cris  sched_setaffinity       sys_sched_setaffinity
242  cris  sched_getaffinity       sys_sched_getaffinity
243  cris  ni_syscall              sys_ni_syscall
244  cris  ni_syscall              sys_ni_syscall
245  cris  io_setup                sys_io_setup
246  cris  io_destroy              sys_io_destroy
247  cris  io_getevents            sys_io_getevents
248  cris  io_submit               sys_io_submit
249  cris  io_cancel               sys_io_cancel
250  cris  fadvise64               sys_fadvise64
251  cris  ni_syscall              sys_ni_syscall
252  cris  exit_group              sys_exit_group
253  cris  lookup_dcookie          sys_lookup_dcookie
254  cris  epoll_create            sys_epoll_create
255  cris  epoll_ctl               sys_epoll_ctl
256  cris  epoll_wait              sys_epoll_wait
257  cris  remap_file_pages        sys_remap_file_pages
258  cris  set_tid_address         sys_set_tid_address
259  cris  timer_create            sys_timer_create
260  cris  timer_settime           sys_timer_settime
261  cris  timer_gettime           sys_timer_gettime
262  cris  timer_getoverrun        sys_timer_getoverrun
263  cris  timer_delete            sys_timer_delete
264  cris  clock_settime           sys_clock_settime
265  cris  clock_gettime           sys_clock_gettime
266  cris  clock_getres            sys_clock_getres
267  cris  clock_nanosleep         sys_clock_nanosleep
268  cris  statfs64                sys_statfs64
269  cris  fstatfs64               sys_fstatfs64
270  cris  tgkill                  sys_tgkill
271  cris  utimes                  sys_utimes
272  cris  fadvise64_64            sys_fadvise64_64
273  cris  ni_syscall              sys_ni_syscall
274  cris  ni_syscall              sys_ni_syscall
275  cris  ni_syscall              sys_ni_syscall
276  cris  ni_syscall              sys_ni_syscall
277  cris  mq_open                 sys_mq_open
278  cris  mq_unlink               sys_mq_unlink
279  cris  mq_timedsend            sys_mq_timedsend
280  cris  mq_timedreceive         sys_mq_timedreceive
281  cris  mq_notify               sys_mq_notify
282  cris  mq_getsetattr           sys_mq_getsetattr
283  cris  ni_syscall              sys_ni_syscall
284  cris  waitid                  sys_waitid
285  cris  ni_syscall              sys_ni_syscall
286  cris  add_key                 sys_add_key
287  cris  request_key             sys_request_key
288  cris  keyctl                  sys_keyctl
289  cris  ioprio_set              sys_ioprio_set
290  cris  ioprio_get              sys_ioprio_get
291  cris  inotify_init            sys_inotify_init
292  cris  inotify_add_watch       sys_inotify_add_watch
293  cris  inotify_rm_watch        sys_inotify_rm_watch
294  cris  migrate_pages           sys_migrate_pages
295  cris  openat                  sys_openat
296  cris  mkdirat                 sys_mkdirat
297  cris  mknodat                 sys_mknodat
298  cris  fchownat                sys_fchownat
299  cris  futimesat               sys_futimesat
300  cris  fstatat64               sys_fstatat64
301  cris  unlinkat                sys_unlinkat
302  cris  renameat                sys_renameat
303  cris  linkat                  sys_linkat
304  cris  symlinkat               sys_symlinkat
305  cris  readlinkat              sys_readlinkat
306  cris  fchmodat                sys_fchmodat
307  cris  faccessat               sys_faccessat
308  cris  pselect6                sys_pselect6
309  cris  ppoll                   sys_ppoll
310  cris  unshare                 sys_unshare
311  cris  set_robust_list         sys_set_robust_list
312  cris  get_robust_list         sys_get_robust_list
313  cris  splice                  sys_splice
314  cris  sync_file_range         sys_sync_file_range
315  cris  tee                     sys_tee
316  cris  vmsplice                sys_vmsplice
317  cris  move_pages              sys_move_pages
318  cris  getcpu                  sys_getcpu
319  cris  epoll_pwait             sys_epoll_pwait
320  cris  utimensat               sys_utimensat
321  cris  signalfd                sys_signalfd
322  cris  timerfd_create          sys_timerfd_create
323  cris  eventfd                 sys_eventfd
324  cris  fallocate               sys_fallocate
325  cris  timerfd_settime         sys_timerfd_settime
326  cris  timerfd_gettime         sys_timerfd_gettime
327  cris  signalfd4               sys_signalfd4
328  cris  eventfd2                sys_eventfd2
329  cris  epoll_create1           sys_epoll_create1
330  cris  dup3                    sys_dup3
331  cris  pipe2                   sys_pipe2
332  cris  inotify_init1           sys_inotify_init1
333  cris  preadv                  sys_preadv
334  cris  pwritev                 sys_pwritev
335  cris  setns                   sys_setns
336  cris  name_to_handle_at       sys_name_to_handle_at
337  cris  open_by_handle_at       sys_open_by_handle_at
338  cris  rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo
339  cris  perf_event_open         sys_perf_event_open
340  cris  recvmmsg                sys_recvmmsg
341  cris  accept4                 sys_accept4
342  cris  fanotify_init           sys_fanotify_init
343  cris  fanotify_mark           sys_fanotify_mark
344  cris  prlimit64               sys_prlimit64
345  cris  clock_adjtime           sys_clock_adjtime
346  cris  syncfs                  sys_syncfs
347  cris  sendmmsg                sys_sendmmsg
348  cris  process_vm_readv        sys_process_vm_readv
349  cris  process_vm_writev       sys_process_vm_writev
350  cris  kcmp                    sys_kcmp
351  cris  finit_module            sys_finit_module
352  cris  sched_setattr           sys_sched_setattr
353  cris  sched_getattr           sys_sched_getattr
354  cris  renameat2               sys_renameat2
355  cris  seccomp                 sys_seccomp
356  cris  getrandom               sys_getrandom
357  cris  memfd_create            sys_memfd_create
358  cris  bpf                     sys_bpf
359  cris  execveat                sys_execveat
"""


# Loongarch
#
# [How to make]
# cd /path/to/linux-6.*/
# gcc -I `pwd`/include/uapi/ -E -D__SYSCALL=SYSCALL arch/loongarch/include/uapi/asm/unistd.h | grep ^SYSCALL \
# | sed -e 's/SYSCALL(//;s/[,)]//g' > /tmp/a
# grep -oP "__NR\S+\s+\d+$" include/uapi/asm-generic/unistd.h | grep -v __NR_sync_file_range2 > /tmp/b
# join -2 2 -o 1.1,1.10,2.1,1.2 -e loongarch /tmp/a /tmp/b | sed -e 's/\(__NR_\|__NR3264_\)//g' | column -t
loongarch_syscall_tbl = """
0    loongarch  io_setup                 sys_io_setup
1    loongarch  io_destroy               sys_io_destroy
2    loongarch  io_submit                sys_io_submit
3    loongarch  io_cancel                sys_io_cancel
4    loongarch  io_getevents             sys_io_getevents
5    loongarch  setxattr                 sys_setxattr
6    loongarch  lsetxattr                sys_lsetxattr
7    loongarch  fsetxattr                sys_fsetxattr
8    loongarch  getxattr                 sys_getxattr
9    loongarch  lgetxattr                sys_lgetxattr
10   loongarch  fgetxattr                sys_fgetxattr
11   loongarch  listxattr                sys_listxattr
12   loongarch  llistxattr               sys_llistxattr
13   loongarch  flistxattr               sys_flistxattr
14   loongarch  removexattr              sys_removexattr
15   loongarch  lremovexattr             sys_lremovexattr
16   loongarch  fremovexattr             sys_fremovexattr
17   loongarch  getcwd                   sys_getcwd
18   loongarch  lookup_dcookie           sys_ni_syscall
19   loongarch  eventfd2                 sys_eventfd2
20   loongarch  epoll_create1            sys_epoll_create1
21   loongarch  epoll_ctl                sys_epoll_ctl
22   loongarch  epoll_pwait              sys_epoll_pwait
23   loongarch  dup                      sys_dup
24   loongarch  dup3                     sys_dup3
25   loongarch  fcntl                    sys_fcntl
26   loongarch  inotify_init1            sys_inotify_init1
27   loongarch  inotify_add_watch        sys_inotify_add_watch
28   loongarch  inotify_rm_watch         sys_inotify_rm_watch
29   loongarch  ioctl                    sys_ioctl
30   loongarch  ioprio_set               sys_ioprio_set
31   loongarch  ioprio_get               sys_ioprio_get
32   loongarch  flock                    sys_flock
33   loongarch  mknodat                  sys_mknodat
34   loongarch  mkdirat                  sys_mkdirat
35   loongarch  unlinkat                 sys_unlinkat
36   loongarch  symlinkat                sys_symlinkat
37   loongarch  linkat                   sys_linkat
39   loongarch  umount2                  sys_umount
40   loongarch  mount                    sys_mount
41   loongarch  pivot_root               sys_pivot_root
42   loongarch  nfsservctl               sys_ni_syscall
43   loongarch  statfs                   sys_statfs
44   loongarch  fstatfs                  sys_fstatfs
45   loongarch  truncate                 sys_truncate
46   loongarch  ftruncate                sys_ftruncate
47   loongarch  fallocate                sys_fallocate
48   loongarch  faccessat                sys_faccessat
49   loongarch  chdir                    sys_chdir
50   loongarch  fchdir                   sys_fchdir
51   loongarch  chroot                   sys_chroot
52   loongarch  fchmod                   sys_fchmod
53   loongarch  fchmodat                 sys_fchmodat
54   loongarch  fchownat                 sys_fchownat
55   loongarch  fchown                   sys_fchown
56   loongarch  openat                   sys_openat
57   loongarch  close                    sys_close
58   loongarch  vhangup                  sys_vhangup
59   loongarch  pipe2                    sys_pipe2
60   loongarch  quotactl                 sys_quotactl
61   loongarch  getdents64               sys_getdents64
62   loongarch  lseek                    sys_lseek
63   loongarch  read                     sys_read
64   loongarch  write                    sys_write
65   loongarch  readv                    sys_readv
66   loongarch  writev                   sys_writev
67   loongarch  pread64                  sys_pread64
68   loongarch  pwrite64                 sys_pwrite64
69   loongarch  preadv                   sys_preadv
70   loongarch  pwritev                  sys_pwritev
71   loongarch  sendfile                 sys_sendfile64
72   loongarch  pselect6                 sys_pselect6
73   loongarch  ppoll                    sys_ppoll
74   loongarch  signalfd4                sys_signalfd4
75   loongarch  vmsplice                 sys_vmsplice
76   loongarch  splice                   sys_splice
77   loongarch  tee                      sys_tee
78   loongarch  readlinkat               sys_readlinkat
81   loongarch  sync                     sys_sync
82   loongarch  fsync                    sys_fsync
83   loongarch  fdatasync                sys_fdatasync
84   loongarch  sync_file_range          sys_sync_file_range
85   loongarch  timerfd_create           sys_timerfd_create
86   loongarch  timerfd_settime          sys_timerfd_settime
87   loongarch  timerfd_gettime          sys_timerfd_gettime
88   loongarch  utimensat                sys_utimensat
89   loongarch  acct                     sys_acct
90   loongarch  capget                   sys_capget
91   loongarch  capset                   sys_capset
92   loongarch  personality              sys_personality
93   loongarch  exit                     sys_exit
94   loongarch  exit_group               sys_exit_group
95   loongarch  waitid                   sys_waitid
96   loongarch  set_tid_address          sys_set_tid_address
97   loongarch  unshare                  sys_unshare
98   loongarch  futex                    sys_futex
99   loongarch  set_robust_list          sys_set_robust_list
100  loongarch  get_robust_list          sys_get_robust_list
101  loongarch  nanosleep                sys_nanosleep
102  loongarch  getitimer                sys_getitimer
103  loongarch  setitimer                sys_setitimer
104  loongarch  kexec_load               sys_kexec_load
105  loongarch  init_module              sys_init_module
106  loongarch  delete_module            sys_delete_module
107  loongarch  timer_create             sys_timer_create
108  loongarch  timer_gettime            sys_timer_gettime
109  loongarch  timer_getoverrun         sys_timer_getoverrun
110  loongarch  timer_settime            sys_timer_settime
111  loongarch  timer_delete             sys_timer_delete
112  loongarch  clock_settime            sys_clock_settime
113  loongarch  clock_gettime            sys_clock_gettime
114  loongarch  clock_getres             sys_clock_getres
115  loongarch  clock_nanosleep          sys_clock_nanosleep
116  loongarch  syslog                   sys_syslog
117  loongarch  ptrace                   sys_ptrace
118  loongarch  sched_setparam           sys_sched_setparam
119  loongarch  sched_setscheduler       sys_sched_setscheduler
120  loongarch  sched_getscheduler       sys_sched_getscheduler
121  loongarch  sched_getparam           sys_sched_getparam
122  loongarch  sched_setaffinity        sys_sched_setaffinity
123  loongarch  sched_getaffinity        sys_sched_getaffinity
124  loongarch  sched_yield              sys_sched_yield
125  loongarch  sched_get_priority_max   sys_sched_get_priority_max
126  loongarch  sched_get_priority_min   sys_sched_get_priority_min
127  loongarch  sched_rr_get_interval    sys_sched_rr_get_interval
128  loongarch  restart_syscall          sys_restart_syscall
129  loongarch  kill                     sys_kill
130  loongarch  tkill                    sys_tkill
131  loongarch  tgkill                   sys_tgkill
132  loongarch  sigaltstack              sys_sigaltstack
133  loongarch  rt_sigsuspend            sys_rt_sigsuspend
134  loongarch  rt_sigaction             sys_rt_sigaction
135  loongarch  rt_sigprocmask           sys_rt_sigprocmask
136  loongarch  rt_sigpending            sys_rt_sigpending
137  loongarch  rt_sigtimedwait          sys_rt_sigtimedwait
138  loongarch  rt_sigqueueinfo          sys_rt_sigqueueinfo
139  loongarch  rt_sigreturn             sys_rt_sigreturn
140  loongarch  setpriority              sys_setpriority
141  loongarch  getpriority              sys_getpriority
142  loongarch  reboot                   sys_reboot
143  loongarch  setregid                 sys_setregid
144  loongarch  setgid                   sys_setgid
145  loongarch  setreuid                 sys_setreuid
146  loongarch  setuid                   sys_setuid
147  loongarch  setresuid                sys_setresuid
148  loongarch  getresuid                sys_getresuid
149  loongarch  setresgid                sys_setresgid
150  loongarch  getresgid                sys_getresgid
151  loongarch  setfsuid                 sys_setfsuid
152  loongarch  setfsgid                 sys_setfsgid
153  loongarch  times                    sys_times
154  loongarch  setpgid                  sys_setpgid
155  loongarch  getpgid                  sys_getpgid
156  loongarch  getsid                   sys_getsid
157  loongarch  setsid                   sys_setsid
158  loongarch  getgroups                sys_getgroups
159  loongarch  setgroups                sys_setgroups
160  loongarch  uname                    sys_newuname
161  loongarch  sethostname              sys_sethostname
162  loongarch  setdomainname            sys_setdomainname
165  loongarch  getrusage                sys_getrusage
166  loongarch  umask                    sys_umask
167  loongarch  prctl                    sys_prctl
168  loongarch  getcpu                   sys_getcpu
169  loongarch  gettimeofday             sys_gettimeofday
170  loongarch  settimeofday             sys_settimeofday
171  loongarch  adjtimex                 sys_adjtimex
172  loongarch  getpid                   sys_getpid
173  loongarch  getppid                  sys_getppid
174  loongarch  getuid                   sys_getuid
175  loongarch  geteuid                  sys_geteuid
176  loongarch  getgid                   sys_getgid
177  loongarch  getegid                  sys_getegid
178  loongarch  gettid                   sys_gettid
179  loongarch  sysinfo                  sys_sysinfo
180  loongarch  mq_open                  sys_mq_open
181  loongarch  mq_unlink                sys_mq_unlink
182  loongarch  mq_timedsend             sys_mq_timedsend
183  loongarch  mq_timedreceive          sys_mq_timedreceive
184  loongarch  mq_notify                sys_mq_notify
185  loongarch  mq_getsetattr            sys_mq_getsetattr
186  loongarch  msgget                   sys_msgget
187  loongarch  msgctl                   sys_msgctl
188  loongarch  msgrcv                   sys_msgrcv
189  loongarch  msgsnd                   sys_msgsnd
190  loongarch  semget                   sys_semget
191  loongarch  semctl                   sys_semctl
192  loongarch  semtimedop               sys_semtimedop
193  loongarch  semop                    sys_semop
194  loongarch  shmget                   sys_shmget
195  loongarch  shmctl                   sys_shmctl
196  loongarch  shmat                    sys_shmat
197  loongarch  shmdt                    sys_shmdt
198  loongarch  socket                   sys_socket
199  loongarch  socketpair               sys_socketpair
200  loongarch  bind                     sys_bind
201  loongarch  listen                   sys_listen
202  loongarch  accept                   sys_accept
203  loongarch  connect                  sys_connect
204  loongarch  getsockname              sys_getsockname
205  loongarch  getpeername              sys_getpeername
206  loongarch  sendto                   sys_sendto
207  loongarch  recvfrom                 sys_recvfrom
208  loongarch  setsockopt               sys_setsockopt
209  loongarch  getsockopt               sys_getsockopt
210  loongarch  shutdown                 sys_shutdown
211  loongarch  sendmsg                  sys_sendmsg
212  loongarch  recvmsg                  sys_recvmsg
213  loongarch  readahead                sys_readahead
214  loongarch  brk                      sys_brk
215  loongarch  munmap                   sys_munmap
216  loongarch  mremap                   sys_mremap
217  loongarch  add_key                  sys_add_key
218  loongarch  request_key              sys_request_key
219  loongarch  keyctl                   sys_keyctl
220  loongarch  clone                    sys_clone
221  loongarch  execve                   sys_execve
222  loongarch  mmap                     sys_mmap
223  loongarch  fadvise64                sys_fadvise64_64
224  loongarch  swapon                   sys_swapon
225  loongarch  swapoff                  sys_swapoff
226  loongarch  mprotect                 sys_mprotect
227  loongarch  msync                    sys_msync
228  loongarch  mlock                    sys_mlock
229  loongarch  munlock                  sys_munlock
230  loongarch  mlockall                 sys_mlockall
231  loongarch  munlockall               sys_munlockall
232  loongarch  mincore                  sys_mincore
233  loongarch  madvise                  sys_madvise
234  loongarch  remap_file_pages         sys_remap_file_pages
235  loongarch  mbind                    sys_mbind
236  loongarch  get_mempolicy            sys_get_mempolicy
237  loongarch  set_mempolicy            sys_set_mempolicy
238  loongarch  migrate_pages            sys_migrate_pages
239  loongarch  move_pages               sys_move_pages
240  loongarch  rt_tgsigqueueinfo        sys_rt_tgsigqueueinfo
241  loongarch  perf_event_open          sys_perf_event_open
242  loongarch  accept4                  sys_accept4
243  loongarch  recvmmsg                 sys_recvmmsg
260  loongarch  wait4                    sys_wait4
261  loongarch  prlimit64                sys_prlimit64
262  loongarch  fanotify_init            sys_fanotify_init
263  loongarch  fanotify_mark            sys_fanotify_mark
264  loongarch  name_to_handle_at        sys_name_to_handle_at
265  loongarch  open_by_handle_at        sys_open_by_handle_at
266  loongarch  clock_adjtime            sys_clock_adjtime
267  loongarch  syncfs                   sys_syncfs
268  loongarch  setns                    sys_setns
269  loongarch  sendmmsg                 sys_sendmmsg
270  loongarch  process_vm_readv         sys_process_vm_readv
271  loongarch  process_vm_writev        sys_process_vm_writev
272  loongarch  kcmp                     sys_kcmp
273  loongarch  finit_module             sys_finit_module
274  loongarch  sched_setattr            sys_sched_setattr
275  loongarch  sched_getattr            sys_sched_getattr
276  loongarch  renameat2                sys_renameat2
277  loongarch  seccomp                  sys_seccomp
278  loongarch  getrandom                sys_getrandom
279  loongarch  memfd_create             sys_memfd_create
280  loongarch  bpf                      sys_bpf
281  loongarch  execveat                 sys_execveat
282  loongarch  userfaultfd              sys_userfaultfd
283  loongarch  membarrier               sys_membarrier
284  loongarch  mlock2                   sys_mlock2
285  loongarch  copy_file_range          sys_copy_file_range
286  loongarch  preadv2                  sys_preadv2
287  loongarch  pwritev2                 sys_pwritev2
288  loongarch  pkey_mprotect            sys_pkey_mprotect
289  loongarch  pkey_alloc               sys_pkey_alloc
290  loongarch  pkey_free                sys_pkey_free
291  loongarch  statx                    sys_statx
292  loongarch  io_pgetevents            sys_io_pgetevents
293  loongarch  rseq                     sys_rseq
294  loongarch  kexec_file_load          sys_kexec_file_load
424  loongarch  pidfd_send_signal        sys_pidfd_send_signal
425  loongarch  io_uring_setup           sys_io_uring_setup
426  loongarch  io_uring_enter           sys_io_uring_enter
427  loongarch  io_uring_register        sys_io_uring_register
428  loongarch  open_tree                sys_open_tree
429  loongarch  move_mount               sys_move_mount
430  loongarch  fsopen                   sys_fsopen
431  loongarch  fsconfig                 sys_fsconfig
432  loongarch  fsmount                  sys_fsmount
433  loongarch  fspick                   sys_fspick
434  loongarch  pidfd_open               sys_pidfd_open
435  loongarch  clone3                   sys_clone3
436  loongarch  close_range              sys_close_range
437  loongarch  openat2                  sys_openat2
438  loongarch  pidfd_getfd              sys_pidfd_getfd
439  loongarch  faccessat2               sys_faccessat2
440  loongarch  process_madvise          sys_process_madvise
441  loongarch  epoll_pwait2             sys_epoll_pwait2
442  loongarch  mount_setattr            sys_mount_setattr
443  loongarch  quotactl_fd              sys_quotactl_fd
444  loongarch  landlock_create_ruleset  sys_landlock_create_ruleset
445  loongarch  landlock_add_rule        sys_landlock_add_rule
446  loongarch  landlock_restrict_self   sys_landlock_restrict_self
448  loongarch  process_mrelease         sys_process_mrelease
449  loongarch  futex_waitv              sys_futex_waitv
450  loongarch  set_mempolicy_home_node  sys_set_mempolicy_home_node
451  loongarch  cachestat                sys_cachestat
452  loongarch  fchmodat2                sys_fchmodat2
453  loongarch  map_shadow_stack         sys_map_shadow_stack
454  loongarch  futex_wake               sys_futex_wake
455  loongarch  futex_wait               sys_futex_wait
456  loongarch  futex_requeue            sys_futex_requeue
457  loongarch  statmount                sys_statmount
458  loongarch  listmount                sys_listmount
459  loongarch  lsm_get_self_attr        sys_lsm_get_self_attr
460  loongarch  lsm_set_self_attr        sys_lsm_set_self_attr
461  loongarch  lsm_list_modules         sys_lsm_list_modules
462  loongarch  mseal                    sys_mseal
"""


# arc
#
# [How to make]
# cd /path/to/linux-6.*/
# gcc -I `pwd`/include/uapi/ -E -D__SYSCALL=SYSCALL arch/arc/include/uapi/asm/unistd.h | grep ^SYSCALL \
# | sed -e 's/SYSCALL(//;s/[,)]//g' > /tmp/a
# grep -oP "__NR\S+\s+\d+$" include/uapi/asm-generic/unistd.h | grep -v __NR_sync_file_range2 > /tmp/b
# join -2 2 -o 1.1,1.10,2.1,1.2 -e arc /tmp/a /tmp/b | sed -e 's/\(__NR_\|__NR3264_\)//g' | column -t
arc_syscall_tbl = """
0    arc  io_setup                 sys_io_setup
1    arc  io_destroy               sys_io_destroy
2    arc  io_submit                sys_io_submit
3    arc  io_cancel                sys_io_cancel
4    arc  io_getevents             sys_io_getevents
5    arc  setxattr                 sys_setxattr
6    arc  lsetxattr                sys_lsetxattr
7    arc  fsetxattr                sys_fsetxattr
8    arc  getxattr                 sys_getxattr
9    arc  lgetxattr                sys_lgetxattr
10   arc  fgetxattr                sys_fgetxattr
11   arc  listxattr                sys_listxattr
12   arc  llistxattr               sys_llistxattr
13   arc  flistxattr               sys_flistxattr
14   arc  removexattr              sys_removexattr
15   arc  lremovexattr             sys_lremovexattr
16   arc  fremovexattr             sys_fremovexattr
17   arc  getcwd                   sys_getcwd
18   arc  lookup_dcookie           sys_ni_syscall
19   arc  eventfd2                 sys_eventfd2
20   arc  epoll_create1            sys_epoll_create1
21   arc  epoll_ctl                sys_epoll_ctl
22   arc  epoll_pwait              sys_epoll_pwait
23   arc  dup                      sys_dup
24   arc  dup3                     sys_dup3
25   arc  fcntl                    sys_fcntl
26   arc  inotify_init1            sys_inotify_init1
27   arc  inotify_add_watch        sys_inotify_add_watch
28   arc  inotify_rm_watch         sys_inotify_rm_watch
29   arc  ioctl                    sys_ioctl
30   arc  ioprio_set               sys_ioprio_set
31   arc  ioprio_get               sys_ioprio_get
32   arc  flock                    sys_flock
33   arc  mknodat                  sys_mknodat
34   arc  mkdirat                  sys_mkdirat
35   arc  unlinkat                 sys_unlinkat
36   arc  symlinkat                sys_symlinkat
37   arc  linkat                   sys_linkat
38   arc  renameat                 sys_renameat
39   arc  umount2                  sys_umount
40   arc  mount                    sys_mount
41   arc  pivot_root               sys_pivot_root
42   arc  nfsservctl               sys_ni_syscall
43   arc  statfs                   sys_statfs
44   arc  fstatfs                  sys_fstatfs
45   arc  truncate                 sys_truncate
46   arc  ftruncate                sys_ftruncate
47   arc  fallocate                sys_fallocate
48   arc  faccessat                sys_faccessat
49   arc  chdir                    sys_chdir
50   arc  fchdir                   sys_fchdir
51   arc  chroot                   sys_chroot
52   arc  fchmod                   sys_fchmod
53   arc  fchmodat                 sys_fchmodat
54   arc  fchownat                 sys_fchownat
55   arc  fchown                   sys_fchown
56   arc  openat                   sys_openat
57   arc  close                    sys_close
58   arc  vhangup                  sys_vhangup
59   arc  pipe2                    sys_pipe2
60   arc  quotactl                 sys_quotactl
61   arc  getdents64               sys_getdents64
62   arc  lseek                    sys_lseek
63   arc  read                     sys_read
64   arc  write                    sys_write
65   arc  readv                    sys_readv
66   arc  writev                   sys_writev
67   arc  pread64                  sys_pread64
68   arc  pwrite64                 sys_pwrite64
69   arc  preadv                   sys_preadv
70   arc  pwritev                  sys_pwritev
71   arc  sendfile                 sys_sendfile64
72   arc  pselect6                 sys_pselect6
73   arc  ppoll                    sys_ppoll
74   arc  signalfd4                sys_signalfd4
75   arc  vmsplice                 sys_vmsplice
76   arc  splice                   sys_splice
77   arc  tee                      sys_tee
78   arc  readlinkat               sys_readlinkat
79   arc  fstatat                  sys_newfstatat
80   arc  fstat                    sys_newfstat
81   arc  sync                     sys_sync
82   arc  fsync                    sys_fsync
83   arc  fdatasync                sys_fdatasync
84   arc  sync_file_range          sys_sync_file_range
85   arc  timerfd_create           sys_timerfd_create
86   arc  timerfd_settime          sys_timerfd_settime
87   arc  timerfd_gettime          sys_timerfd_gettime
88   arc  utimensat                sys_utimensat
89   arc  acct                     sys_acct
90   arc  capget                   sys_capget
91   arc  capset                   sys_capset
92   arc  personality              sys_personality
93   arc  exit                     sys_exit
94   arc  exit_group               sys_exit_group
95   arc  waitid                   sys_waitid
96   arc  set_tid_address          sys_set_tid_address
97   arc  unshare                  sys_unshare
98   arc  futex                    sys_futex
99   arc  set_robust_list          sys_set_robust_list
100  arc  get_robust_list          sys_get_robust_list
101  arc  nanosleep                sys_nanosleep
102  arc  getitimer                sys_getitimer
103  arc  setitimer                sys_setitimer
104  arc  kexec_load               sys_kexec_load
105  arc  init_module              sys_init_module
106  arc  delete_module            sys_delete_module
107  arc  timer_create             sys_timer_create
108  arc  timer_gettime            sys_timer_gettime
109  arc  timer_getoverrun         sys_timer_getoverrun
110  arc  timer_settime            sys_timer_settime
111  arc  timer_delete             sys_timer_delete
112  arc  clock_settime            sys_clock_settime
113  arc  clock_gettime            sys_clock_gettime
114  arc  clock_getres             sys_clock_getres
115  arc  clock_nanosleep          sys_clock_nanosleep
116  arc  syslog                   sys_syslog
117  arc  ptrace                   sys_ptrace
118  arc  sched_setparam           sys_sched_setparam
119  arc  sched_setscheduler       sys_sched_setscheduler
120  arc  sched_getscheduler       sys_sched_getscheduler
121  arc  sched_getparam           sys_sched_getparam
122  arc  sched_setaffinity        sys_sched_setaffinity
123  arc  sched_getaffinity        sys_sched_getaffinity
124  arc  sched_yield              sys_sched_yield
125  arc  sched_get_priority_max   sys_sched_get_priority_max
126  arc  sched_get_priority_min   sys_sched_get_priority_min
127  arc  sched_rr_get_interval    sys_sched_rr_get_interval
128  arc  restart_syscall          sys_restart_syscall
129  arc  kill                     sys_kill
130  arc  tkill                    sys_tkill
131  arc  tgkill                   sys_tgkill
132  arc  sigaltstack              sys_sigaltstack
133  arc  rt_sigsuspend            sys_rt_sigsuspend
134  arc  rt_sigaction             sys_rt_sigaction
135  arc  rt_sigprocmask           sys_rt_sigprocmask
136  arc  rt_sigpending            sys_rt_sigpending
137  arc  rt_sigtimedwait          sys_rt_sigtimedwait
138  arc  rt_sigqueueinfo          sys_rt_sigqueueinfo
139  arc  rt_sigreturn             sys_rt_sigreturn
140  arc  setpriority              sys_setpriority
141  arc  getpriority              sys_getpriority
142  arc  reboot                   sys_reboot
143  arc  setregid                 sys_setregid
144  arc  setgid                   sys_setgid
145  arc  setreuid                 sys_setreuid
146  arc  setuid                   sys_setuid
147  arc  setresuid                sys_setresuid
148  arc  getresuid                sys_getresuid
149  arc  setresgid                sys_setresgid
150  arc  getresgid                sys_getresgid
151  arc  setfsuid                 sys_setfsuid
152  arc  setfsgid                 sys_setfsgid
153  arc  times                    sys_times
154  arc  setpgid                  sys_setpgid
155  arc  getpgid                  sys_getpgid
156  arc  getsid                   sys_getsid
157  arc  setsid                   sys_setsid
158  arc  getgroups                sys_getgroups
159  arc  setgroups                sys_setgroups
160  arc  uname                    sys_newuname
161  arc  sethostname              sys_sethostname
162  arc  setdomainname            sys_setdomainname
163  arc  getrlimit                sys_getrlimit
164  arc  setrlimit                sys_setrlimit
165  arc  getrusage                sys_getrusage
166  arc  umask                    sys_umask
167  arc  prctl                    sys_prctl
168  arc  getcpu                   sys_getcpu
169  arc  gettimeofday             sys_gettimeofday
170  arc  settimeofday             sys_settimeofday
171  arc  adjtimex                 sys_adjtimex
172  arc  getpid                   sys_getpid
173  arc  getppid                  sys_getppid
174  arc  getuid                   sys_getuid
175  arc  geteuid                  sys_geteuid
176  arc  getgid                   sys_getgid
177  arc  getegid                  sys_getegid
178  arc  gettid                   sys_gettid
179  arc  sysinfo                  sys_sysinfo
180  arc  mq_open                  sys_mq_open
181  arc  mq_unlink                sys_mq_unlink
182  arc  mq_timedsend             sys_mq_timedsend
183  arc  mq_timedreceive          sys_mq_timedreceive
184  arc  mq_notify                sys_mq_notify
185  arc  mq_getsetattr            sys_mq_getsetattr
186  arc  msgget                   sys_msgget
187  arc  msgctl                   sys_msgctl
188  arc  msgrcv                   sys_msgrcv
189  arc  msgsnd                   sys_msgsnd
190  arc  semget                   sys_semget
191  arc  semctl                   sys_semctl
192  arc  semtimedop               sys_semtimedop
193  arc  semop                    sys_semop
194  arc  shmget                   sys_shmget
195  arc  shmctl                   sys_shmctl
196  arc  shmat                    sys_shmat
197  arc  shmdt                    sys_shmdt
198  arc  socket                   sys_socket
199  arc  socketpair               sys_socketpair
200  arc  bind                     sys_bind
201  arc  listen                   sys_listen
202  arc  accept                   sys_accept
203  arc  connect                  sys_connect
204  arc  getsockname              sys_getsockname
205  arc  getpeername              sys_getpeername
206  arc  sendto                   sys_sendto
207  arc  recvfrom                 sys_recvfrom
208  arc  setsockopt               sys_setsockopt
209  arc  getsockopt               sys_getsockopt
210  arc  shutdown                 sys_shutdown
211  arc  sendmsg                  sys_sendmsg
212  arc  recvmsg                  sys_recvmsg
213  arc  readahead                sys_readahead
214  arc  brk                      sys_brk
215  arc  munmap                   sys_munmap
216  arc  mremap                   sys_mremap
217  arc  add_key                  sys_add_key
218  arc  request_key              sys_request_key
219  arc  keyctl                   sys_keyctl
220  arc  clone                    sys_clone
221  arc  execve                   sys_execve
222  arc  mmap                     sys_mmap
223  arc  fadvise64                sys_fadvise64_64
224  arc  swapon                   sys_swapon
225  arc  swapoff                  sys_swapoff
226  arc  mprotect                 sys_mprotect
227  arc  msync                    sys_msync
228  arc  mlock                    sys_mlock
229  arc  munlock                  sys_munlock
230  arc  mlockall                 sys_mlockall
231  arc  munlockall               sys_munlockall
232  arc  mincore                  sys_mincore
233  arc  madvise                  sys_madvise
234  arc  remap_file_pages         sys_remap_file_pages
235  arc  mbind                    sys_mbind
236  arc  get_mempolicy            sys_get_mempolicy
237  arc  set_mempolicy            sys_set_mempolicy
238  arc  migrate_pages            sys_migrate_pages
239  arc  move_pages               sys_move_pages
240  arc  rt_tgsigqueueinfo        sys_rt_tgsigqueueinfo
241  arc  perf_event_open          sys_perf_event_open
242  arc  accept4                  sys_accept4
243  arc  recvmmsg                 sys_recvmmsg
260  arc  wait4                    sys_wait4
261  arc  prlimit64                sys_prlimit64
262  arc  fanotify_init            sys_fanotify_init
263  arc  fanotify_mark            sys_fanotify_mark
264  arc  name_to_handle_at        sys_name_to_handle_at
265  arc  open_by_handle_at        sys_open_by_handle_at
266  arc  clock_adjtime            sys_clock_adjtime
267  arc  syncfs                   sys_syncfs
268  arc  setns                    sys_setns
269  arc  sendmmsg                 sys_sendmmsg
270  arc  process_vm_readv         sys_process_vm_readv
271  arc  process_vm_writev        sys_process_vm_writev
272  arc  kcmp                     sys_kcmp
273  arc  finit_module             sys_finit_module
274  arc  sched_setattr            sys_sched_setattr
275  arc  sched_getattr            sys_sched_getattr
276  arc  renameat2                sys_renameat2
277  arc  seccomp                  sys_seccomp
278  arc  getrandom                sys_getrandom
279  arc  memfd_create             sys_memfd_create
280  arc  bpf                      sys_bpf
281  arc  execveat                 sys_execveat
282  arc  userfaultfd              sys_userfaultfd
283  arc  membarrier               sys_membarrier
284  arc  mlock2                   sys_mlock2
285  arc  copy_file_range          sys_copy_file_range
286  arc  preadv2                  sys_preadv2
287  arc  pwritev2                 sys_pwritev2
288  arc  pkey_mprotect            sys_pkey_mprotect
289  arc  pkey_alloc               sys_pkey_alloc
290  arc  pkey_free                sys_pkey_free
291  arc  statx                    sys_statx
292  arc  io_pgetevents            sys_io_pgetevents
293  arc  rseq                     sys_rseq
294  arc  kexec_file_load          sys_kexec_file_load
424  arc  pidfd_send_signal        sys_pidfd_send_signal
425  arc  io_uring_setup           sys_io_uring_setup
426  arc  io_uring_enter           sys_io_uring_enter
427  arc  io_uring_register        sys_io_uring_register
428  arc  open_tree                sys_open_tree
429  arc  move_mount               sys_move_mount
430  arc  fsopen                   sys_fsopen
431  arc  fsconfig                 sys_fsconfig
432  arc  fsmount                  sys_fsmount
433  arc  fspick                   sys_fspick
434  arc  pidfd_open               sys_pidfd_open
435  arc  clone3                   sys_clone3
436  arc  close_range              sys_close_range
437  arc  openat2                  sys_openat2
438  arc  pidfd_getfd              sys_pidfd_getfd
439  arc  faccessat2               sys_faccessat2
440  arc  process_madvise          sys_process_madvise
441  arc  epoll_pwait2             sys_epoll_pwait2
442  arc  mount_setattr            sys_mount_setattr
443  arc  quotactl_fd              sys_quotactl_fd
444  arc  landlock_create_ruleset  sys_landlock_create_ruleset
445  arc  landlock_add_rule        sys_landlock_add_rule
446  arc  landlock_restrict_self   sys_landlock_restrict_self
448  arc  process_mrelease         sys_process_mrelease
449  arc  futex_waitv              sys_futex_waitv
450  arc  set_mempolicy_home_node  sys_set_mempolicy_home_node
451  arc  cachestat                sys_cachestat
452  arc  fchmodat2                sys_fchmodat2
453  arc  map_shadow_stack         sys_map_shadow_stack
454  arc  futex_wake               sys_futex_wake
455  arc  futex_wait               sys_futex_wait
456  arc  futex_requeue            sys_futex_requeue
457  arc  statmount                sys_statmount
458  arc  listmount                sys_listmount
459  arc  lsm_get_self_attr        sys_lsm_get_self_attr
460  arc  lsm_set_self_attr        sys_lsm_set_self_attr
461  arc  lsm_list_modules         sys_lsm_list_modules
462  arc  mseal                    sys_mseal
"""


# csky
#
# [How to make]
# cd /path/to/linux-6.*/
# gcc -I `pwd`/include/uapi/ -E -D__SYSCALL=SYSCALL arch/csky/include/uapi/asm/unistd.h | grep ^SYSCALL \
# | sed -e 's/SYSCALL(//;s/[,)]//g' > /tmp/a
# grep -oP "__NR\S+\s+\d+$" include/uapi/asm-generic/unistd.h | grep -v __NR_sync_file_range2 > /tmp/b
# join -2 2 -o 1.1,1.10,2.1,1.2 -e csky /tmp/a /tmp/b | sed -e 's/\(__NR_\|__NR3264_\)//g' | column -t
csky_syscall_tbl = """
0    csky  io_setup                 sys_io_setup
1    csky  io_destroy               sys_io_destroy
2    csky  io_submit                sys_io_submit
3    csky  io_cancel                sys_io_cancel
4    csky  io_getevents             sys_io_getevents
5    csky  setxattr                 sys_setxattr
6    csky  lsetxattr                sys_lsetxattr
7    csky  fsetxattr                sys_fsetxattr
8    csky  getxattr                 sys_getxattr
9    csky  lgetxattr                sys_lgetxattr
10   csky  fgetxattr                sys_fgetxattr
11   csky  listxattr                sys_listxattr
12   csky  llistxattr               sys_llistxattr
13   csky  flistxattr               sys_flistxattr
14   csky  removexattr              sys_removexattr
15   csky  lremovexattr             sys_lremovexattr
16   csky  fremovexattr             sys_fremovexattr
17   csky  getcwd                   sys_getcwd
18   csky  lookup_dcookie           sys_ni_syscall
19   csky  eventfd2                 sys_eventfd2
20   csky  epoll_create1            sys_epoll_create1
21   csky  epoll_ctl                sys_epoll_ctl
22   csky  epoll_pwait              sys_epoll_pwait
23   csky  dup                      sys_dup
24   csky  dup3                     sys_dup3
25   csky  fcntl                    sys_fcntl
26   csky  inotify_init1            sys_inotify_init1
27   csky  inotify_add_watch        sys_inotify_add_watch
28   csky  inotify_rm_watch         sys_inotify_rm_watch
29   csky  ioctl                    sys_ioctl
30   csky  ioprio_set               sys_ioprio_set
31   csky  ioprio_get               sys_ioprio_get
32   csky  flock                    sys_flock
33   csky  mknodat                  sys_mknodat
34   csky  mkdirat                  sys_mkdirat
35   csky  unlinkat                 sys_unlinkat
36   csky  symlinkat                sys_symlinkat
37   csky  linkat                   sys_linkat
39   csky  umount2                  sys_umount
40   csky  mount                    sys_mount
41   csky  pivot_root               sys_pivot_root
42   csky  nfsservctl               sys_ni_syscall
43   csky  statfs                   sys_statfs
44   csky  fstatfs                  sys_fstatfs
45   csky  truncate                 sys_truncate
46   csky  ftruncate                sys_ftruncate
47   csky  fallocate                sys_fallocate
48   csky  faccessat                sys_faccessat
49   csky  chdir                    sys_chdir
50   csky  fchdir                   sys_fchdir
51   csky  chroot                   sys_chroot
52   csky  fchmod                   sys_fchmod
53   csky  fchmodat                 sys_fchmodat
54   csky  fchownat                 sys_fchownat
55   csky  fchown                   sys_fchown
56   csky  openat                   sys_openat
57   csky  close                    sys_close
58   csky  vhangup                  sys_vhangup
59   csky  pipe2                    sys_pipe2
60   csky  quotactl                 sys_quotactl
61   csky  getdents64               sys_getdents64
62   csky  lseek                    sys_lseek
63   csky  read                     sys_read
64   csky  write                    sys_write
65   csky  readv                    sys_readv
66   csky  writev                   sys_writev
67   csky  pread64                  sys_pread64
68   csky  pwrite64                 sys_pwrite64
69   csky  preadv                   sys_preadv
70   csky  pwritev                  sys_pwritev
71   csky  sendfile                 sys_sendfile64
72   csky  pselect6                 sys_pselect6
73   csky  ppoll                    sys_ppoll
74   csky  signalfd4                sys_signalfd4
75   csky  vmsplice                 sys_vmsplice
76   csky  splice                   sys_splice
77   csky  tee                      sys_tee
78   csky  readlinkat               sys_readlinkat
79   csky  fstatat                  sys_newfstatat
80   csky  fstat                    sys_newfstat
81   csky  sync                     sys_sync
82   csky  fsync                    sys_fsync
83   csky  fdatasync                sys_fdatasync
84   csky  sync_file_range          sys_sync_file_range2
85   csky  timerfd_create           sys_timerfd_create
86   csky  timerfd_settime          sys_timerfd_settime
87   csky  timerfd_gettime          sys_timerfd_gettime
88   csky  utimensat                sys_utimensat
89   csky  acct                     sys_acct
90   csky  capget                   sys_capget
91   csky  capset                   sys_capset
92   csky  personality              sys_personality
93   csky  exit                     sys_exit
94   csky  exit_group               sys_exit_group
95   csky  waitid                   sys_waitid
96   csky  set_tid_address          sys_set_tid_address
97   csky  unshare                  sys_unshare
98   csky  futex                    sys_futex
99   csky  set_robust_list          sys_set_robust_list
100  csky  get_robust_list          sys_get_robust_list
101  csky  nanosleep                sys_nanosleep
102  csky  getitimer                sys_getitimer
103  csky  setitimer                sys_setitimer
104  csky  kexec_load               sys_kexec_load
105  csky  init_module              sys_init_module
106  csky  delete_module            sys_delete_module
107  csky  timer_create             sys_timer_create
108  csky  timer_gettime            sys_timer_gettime
109  csky  timer_getoverrun         sys_timer_getoverrun
110  csky  timer_settime            sys_timer_settime
111  csky  timer_delete             sys_timer_delete
112  csky  clock_settime            sys_clock_settime
113  csky  clock_gettime            sys_clock_gettime
114  csky  clock_getres             sys_clock_getres
115  csky  clock_nanosleep          sys_clock_nanosleep
116  csky  syslog                   sys_syslog
117  csky  ptrace                   sys_ptrace
118  csky  sched_setparam           sys_sched_setparam
119  csky  sched_setscheduler       sys_sched_setscheduler
120  csky  sched_getscheduler       sys_sched_getscheduler
121  csky  sched_getparam           sys_sched_getparam
122  csky  sched_setaffinity        sys_sched_setaffinity
123  csky  sched_getaffinity        sys_sched_getaffinity
124  csky  sched_yield              sys_sched_yield
125  csky  sched_get_priority_max   sys_sched_get_priority_max
126  csky  sched_get_priority_min   sys_sched_get_priority_min
127  csky  sched_rr_get_interval    sys_sched_rr_get_interval
128  csky  restart_syscall          sys_restart_syscall
129  csky  kill                     sys_kill
130  csky  tkill                    sys_tkill
131  csky  tgkill                   sys_tgkill
132  csky  sigaltstack              sys_sigaltstack
133  csky  rt_sigsuspend            sys_rt_sigsuspend
134  csky  rt_sigaction             sys_rt_sigaction
135  csky  rt_sigprocmask           sys_rt_sigprocmask
136  csky  rt_sigpending            sys_rt_sigpending
137  csky  rt_sigtimedwait          sys_rt_sigtimedwait
138  csky  rt_sigqueueinfo          sys_rt_sigqueueinfo
139  csky  rt_sigreturn             sys_rt_sigreturn
140  csky  setpriority              sys_setpriority
141  csky  getpriority              sys_getpriority
142  csky  reboot                   sys_reboot
143  csky  setregid                 sys_setregid
144  csky  setgid                   sys_setgid
145  csky  setreuid                 sys_setreuid
146  csky  setuid                   sys_setuid
147  csky  setresuid                sys_setresuid
148  csky  getresuid                sys_getresuid
149  csky  setresgid                sys_setresgid
150  csky  getresgid                sys_getresgid
151  csky  setfsuid                 sys_setfsuid
152  csky  setfsgid                 sys_setfsgid
153  csky  times                    sys_times
154  csky  setpgid                  sys_setpgid
155  csky  getpgid                  sys_getpgid
156  csky  getsid                   sys_getsid
157  csky  setsid                   sys_setsid
158  csky  getgroups                sys_getgroups
159  csky  setgroups                sys_setgroups
160  csky  uname                    sys_newuname
161  csky  sethostname              sys_sethostname
162  csky  setdomainname            sys_setdomainname
163  csky  getrlimit                sys_getrlimit
164  csky  setrlimit                sys_setrlimit
165  csky  getrusage                sys_getrusage
166  csky  umask                    sys_umask
167  csky  prctl                    sys_prctl
168  csky  getcpu                   sys_getcpu
169  csky  gettimeofday             sys_gettimeofday
170  csky  settimeofday             sys_settimeofday
171  csky  adjtimex                 sys_adjtimex
172  csky  getpid                   sys_getpid
173  csky  getppid                  sys_getppid
174  csky  getuid                   sys_getuid
175  csky  geteuid                  sys_geteuid
176  csky  getgid                   sys_getgid
177  csky  getegid                  sys_getegid
178  csky  gettid                   sys_gettid
179  csky  sysinfo                  sys_sysinfo
180  csky  mq_open                  sys_mq_open
181  csky  mq_unlink                sys_mq_unlink
182  csky  mq_timedsend             sys_mq_timedsend
183  csky  mq_timedreceive          sys_mq_timedreceive
184  csky  mq_notify                sys_mq_notify
185  csky  mq_getsetattr            sys_mq_getsetattr
186  csky  msgget                   sys_msgget
187  csky  msgctl                   sys_msgctl
188  csky  msgrcv                   sys_msgrcv
189  csky  msgsnd                   sys_msgsnd
190  csky  semget                   sys_semget
191  csky  semctl                   sys_semctl
192  csky  semtimedop               sys_semtimedop
193  csky  semop                    sys_semop
194  csky  shmget                   sys_shmget
195  csky  shmctl                   sys_shmctl
196  csky  shmat                    sys_shmat
197  csky  shmdt                    sys_shmdt
198  csky  socket                   sys_socket
199  csky  socketpair               sys_socketpair
200  csky  bind                     sys_bind
201  csky  listen                   sys_listen
202  csky  accept                   sys_accept
203  csky  connect                  sys_connect
204  csky  getsockname              sys_getsockname
205  csky  getpeername              sys_getpeername
206  csky  sendto                   sys_sendto
207  csky  recvfrom                 sys_recvfrom
208  csky  setsockopt               sys_setsockopt
209  csky  getsockopt               sys_getsockopt
210  csky  shutdown                 sys_shutdown
211  csky  sendmsg                  sys_sendmsg
212  csky  recvmsg                  sys_recvmsg
213  csky  readahead                sys_readahead
214  csky  brk                      sys_brk
215  csky  munmap                   sys_munmap
216  csky  mremap                   sys_mremap
217  csky  add_key                  sys_add_key
218  csky  request_key              sys_request_key
219  csky  keyctl                   sys_keyctl
220  csky  clone                    sys_clone
221  csky  execve                   sys_execve
222  csky  mmap                     sys_mmap
223  csky  fadvise64                sys_fadvise64_64
224  csky  swapon                   sys_swapon
225  csky  swapoff                  sys_swapoff
226  csky  mprotect                 sys_mprotect
227  csky  msync                    sys_msync
228  csky  mlock                    sys_mlock
229  csky  munlock                  sys_munlock
230  csky  mlockall                 sys_mlockall
231  csky  munlockall               sys_munlockall
232  csky  mincore                  sys_mincore
233  csky  madvise                  sys_madvise
234  csky  remap_file_pages         sys_remap_file_pages
235  csky  mbind                    sys_mbind
236  csky  get_mempolicy            sys_get_mempolicy
237  csky  set_mempolicy            sys_set_mempolicy
238  csky  migrate_pages            sys_migrate_pages
239  csky  move_pages               sys_move_pages
240  csky  rt_tgsigqueueinfo        sys_rt_tgsigqueueinfo
241  csky  perf_event_open          sys_perf_event_open
242  csky  accept4                  sys_accept4
243  csky  recvmmsg                 sys_recvmmsg
260  csky  wait4                    sys_wait4
261  csky  prlimit64                sys_prlimit64
262  csky  fanotify_init            sys_fanotify_init
263  csky  fanotify_mark            sys_fanotify_mark
264  csky  name_to_handle_at        sys_name_to_handle_at
265  csky  open_by_handle_at        sys_open_by_handle_at
266  csky  clock_adjtime            sys_clock_adjtime
267  csky  syncfs                   sys_syncfs
268  csky  setns                    sys_setns
269  csky  sendmmsg                 sys_sendmmsg
270  csky  process_vm_readv         sys_process_vm_readv
271  csky  process_vm_writev        sys_process_vm_writev
272  csky  kcmp                     sys_kcmp
273  csky  finit_module             sys_finit_module
274  csky  sched_setattr            sys_sched_setattr
275  csky  sched_getattr            sys_sched_getattr
276  csky  renameat2                sys_renameat2
277  csky  seccomp                  sys_seccomp
278  csky  getrandom                sys_getrandom
279  csky  memfd_create             sys_memfd_create
280  csky  bpf                      sys_bpf
281  csky  execveat                 sys_execveat
282  csky  userfaultfd              sys_userfaultfd
283  csky  membarrier               sys_membarrier
284  csky  mlock2                   sys_mlock2
285  csky  copy_file_range          sys_copy_file_range
286  csky  preadv2                  sys_preadv2
287  csky  pwritev2                 sys_pwritev2
288  csky  pkey_mprotect            sys_pkey_mprotect
289  csky  pkey_alloc               sys_pkey_alloc
290  csky  pkey_free                sys_pkey_free
291  csky  statx                    sys_statx
292  csky  io_pgetevents            sys_io_pgetevents
293  csky  rseq                     sys_rseq
294  csky  kexec_file_load          sys_kexec_file_load
424  csky  pidfd_send_signal        sys_pidfd_send_signal
425  csky  io_uring_setup           sys_io_uring_setup
426  csky  io_uring_enter           sys_io_uring_enter
427  csky  io_uring_register        sys_io_uring_register
428  csky  open_tree                sys_open_tree
429  csky  move_mount               sys_move_mount
430  csky  fsopen                   sys_fsopen
431  csky  fsconfig                 sys_fsconfig
432  csky  fsmount                  sys_fsmount
433  csky  fspick                   sys_fspick
434  csky  pidfd_open               sys_pidfd_open
435  csky  clone3                   sys_clone3
436  csky  close_range              sys_close_range
437  csky  openat2                  sys_openat2
438  csky  pidfd_getfd              sys_pidfd_getfd
439  csky  faccessat2               sys_faccessat2
440  csky  process_madvise          sys_process_madvise
441  csky  epoll_pwait2             sys_epoll_pwait2
442  csky  mount_setattr            sys_mount_setattr
443  csky  quotactl_fd              sys_quotactl_fd
444  csky  landlock_create_ruleset  sys_landlock_create_ruleset
445  csky  landlock_add_rule        sys_landlock_add_rule
446  csky  landlock_restrict_self   sys_landlock_restrict_self
448  csky  process_mrelease         sys_process_mrelease
449  csky  futex_waitv              sys_futex_waitv
450  csky  set_mempolicy_home_node  sys_set_mempolicy_home_node
451  csky  cachestat                sys_cachestat
452  csky  fchmodat2                sys_fchmodat2
453  csky  map_shadow_stack         sys_map_shadow_stack
454  csky  futex_wake               sys_futex_wake
455  csky  futex_wait               sys_futex_wait
456  csky  futex_requeue            sys_futex_requeue
457  csky  statmount                sys_statmount
458  csky  listmount                sys_listmount
459  csky  lsm_get_self_attr        sys_lsm_get_self_attr
460  csky  lsm_set_self_attr        sys_lsm_set_self_attr
461  csky  lsm_list_modules         sys_lsm_list_modules
462  csky  mseal                    sys_mseal
"""


# ARM/ARM64 OP-TEE (at secure world)
# - core/include/tee/tee_svc.h
# - core/include/tee/tee_svc_cryp.h
# - core/include/tee/tee_svc_storage.h
# - core/include/tee/svc_cache.h
arm_OPTEE_syscall_list = [
    [0x00, "syscall_sys_return", ["unsigned long ret"]],
    [0x01, "syscall_log", ["const void *buf", "size_t len"]],
    [0x02, "syscall_panic", ["unsigned long code"]],
    [0x03, "syscall_get_property", ["unsigned long prop_set", "unsigned long index", "void *name", "uint32_t *name_len", "void *buf", "uint32_t *blen", "uint32_t *prop_type"]],
    [0x04, "syscall_get_property_name_to_index", ["unsigned long prop_set", "void *name", "unsigned long name_len", "uint32_t *index"]],
    [0x05, "syscall_open_ta_session", ["const TEE_UUID *dest", "unsigned long cancel_req_to", "struct utee_params *params", "uint32_t *sess", "uint32_t *ret_orig"]],
    [0x06, "syscall_close_ta_session", ["unsigned long sess"]],
    [0x07, "syscall_invoke_ta_command", ["unsigned long sess", "unsigned long cancel_req_to", "unsigned long cmd_id", "struct utee_params *params", "uint32_t *ret_orig"]],
    [0x08, "syscall_check_access_rights", ["unsigned long flags", "const void *buf", "size_t len"]],
    [0x09, "syscall_get_cancellation_flag", ["uint32_t *cancel", ]],
    [0x0a, "syscall_unmask_cancellation", ["uint32_t *old_mask"]],
    [0x0b, "syscall_mask_cancellation", ["uint32_t *old_mask"]],
    [0x0c, "syscall_wait", ["unsigned long timeout"]],
    [0x0d, "syscall_get_time", ["unsigned long cat", "TEE_Time *time"]],
    [0x0e, "syscall_set_ta_time", ["const TEE_Time *time"]],
    [0x0f, "syscall_cryp_state_alloc", ["unsigned long algo", "unsigned long op_mode", "unsigned long key1", "unsigned long key2", "uint32_t *state"]],
    [0x10, "syscall_cryp_state_copy", ["unsigned long dst", "unsigned long src"]],
    [0x11, "syscall_cryp_state_free", ["unsigned long state"]],
    [0x12, "syscall_hash_init", ["unsigned long state", "const void *iv", "size_t iv_len"]],
    [0x13, "syscall_hash_update", ["unsigned long state", "const void *chunk", "size_t chunk_size"]],
    [0x14, "syscall_hash_final", ["unsigned long state", "const void *chunk", "size_t chunk_size", "void *hash", "uint64_t *hash_len"]],
    [0x15, "syscall_cipher_init", ["unsigned long state", "const void *iv", "size_t iv_len"]],
    [0x16, "syscall_cipher_update", ["unsigned long state", "const void *src", "size_t src_len", "void *dest", "uint64_t *dest_len"]],
    [0x17, "syscall_cipher_final", ["unsigned long state", "const void *src", "size_t src_len", "void *dest", "uint64_t *dest_len"]],
    [0x18, "syscall_cryp_obj_get_info", ["unsigned long obj", "TEE_ObjectInfo *info"]],
    [0x19, "syscall_cryp_obj_restrict_usage", ["unsigned long obj", "unsigned long usage"]],
    [0x1a, "syscall_cryp_obj_get_attr", ["unsigned long obj", "unsigned long attr_id", "void *buffer", "uint64_t *size"]],
    [0x1b, "syscall_cryp_obj_alloc", ["unsigned long obj_type", "unsigned long max_key_size", "uint32_t *obj"]],
    [0x1c, "syscall_cryp_obj_close", ["unsigned long obj"]],
    [0x1d, "syscall_cryp_obj_reset", ["unsigned long obj"]],
    [0x1e, "syscall_cryp_obj_populate", ["unsigned long obj", "struct utee_attribute *attrs", "unsigned long attr_count"]],
    [0x1f, "syscall_cryp_obj_copy", ["unsigned long dst_obj", "unsigned long src_obj"]],
    [0x20, "syscall_cryp_derive_key", ["unsigned long state", "const struct utee_attribute *params", "unsigned long param_count", "unsigned long derived_key"]],
    [0x21, "syscall_cryp_random_number_generate", ["void *buf", "size_t blen"]],
    [0x22, "syscall_authenc_init", ["unsigned long state", "const void *nonce", "size_t nonce_len", "size_t tag_len", "size_t aad_len", "size_t payload_len"]],
    [0x23, "syscall_authenc_update_aad", ["unsigned long state", "const void *aad_data", "size_t aad_data_len"]],
    [0x24, "syscall_authenc_update_payload", ["unsigned long state", "const void *src_data", "size_t src_len", "void *dest_data", "uint64_t *dest_len"]],
    [0x25, "syscall_authenc_enc_final", ["unsigned long state", "const void *src_data", "size_t src_len", "void *dest_data", "uint64_t *dest_len", "void *tag", "uint64_t *tag_len"]],
    [0x26, "syscall_authenc_dec_final", ["unsigned long state", "const void *src_data", "size_t src_len", "void *dest_data", "uint64_t *dest_len", "const void *tag", "uint64_t *tag_len"]],
    [0x27, "syscall_asymm_operate", ["unsigned long state", "const struct utee_attribute *usr_params", "size_t num_params", "const void *src_data", "size_t src_len", "void *dest_data", "uint64_t *dest_len"]],
    [0x28, "syscall_asymm_verify", ["unsigned long state", "const struct utee_attribute *usr_params", "size_t num_params", "const void *data", "size_t data_len", "const void *sig", "size_t sig_len"]],
    [0x29, "syscall_storage_obj_open", ["unsigned long storage_id", "void *object_id", "size_t object_id_len", "unsigned long flags", "uint32_t *obj"]],
    [0x2a, "syscall_storage_obj_create", ["unsigned long storage_id", "void *object_id", "size_t object_id_len", "unsigned long flags", "unsigned long attr", "void *data", "size_t len", "uint32_t *obj"]],
    [0x2b, "syscall_storage_obj_del", ["unsigned long obj"]],
    [0x2c, "syscall_storage_obj_rename", ["unsigned long obj", "void *object_id", "size_t object_id_len"]],
    [0x2d, "syscall_storage_alloc_enum", ["uint32_t *obj_enum"]],
    [0x2e, "syscall_storage_free_enum", ["nsigned long obj_enum"]],
    [0x2f, "syscall_storage_reset_enum", ["unsigned long obj_enum"]],
    [0x30, "syscall_storage_start_enum", ["unsigned long obj_enum", "unsigned long storage_id"]],
    [0x31, "syscall_storage_next_enum", ["unsigned long obj_enum", "TEE_ObjectInfo *info", "void *obj_id", "uint64_t *len"]],
    [0x32, "syscall_storage_obj_read", ["unsigned long obj", "void *data", "size_t len", "uint64_t *count"]],
    [0x33, "syscall_storage_obj_write", ["unsigned long obj", "void *data", "size_t len"]],
    [0x34, "syscall_storage_obj_trunc", ["unsigned long obj, size_t len"]],
    [0x35, "syscall_storage_obj_seek", ["unsigned long obj", "int32_t offset", "unsigned long whence"]],
    [0x36, "syscall_obj_generate_key", ["unsigned long obj", "unsigned long key_size", "const struct utee_attribute *params", "unsigned long param_count"]],
    [0x37, "syscall_not_supported", []],
    [0x38, "syscall_not_supported", []],
    [0x39, "syscall_not_supported", []],
    [0x3a, "syscall_not_supported", []],
    [0x3b, "syscall_not_supported", []],
    [0x3c, "syscall_not_supported", []],
    [0x3d, "syscall_not_supported", []],
    [0x3e, "syscall_not_supported", []],
    [0x3f, "syscall_not_supported", []],
    [0x40, "syscall_not_supported", []],
    [0x41, "syscall_not_supported", []],
    [0x42, "syscall_not_supported", []],
    [0x43, "syscall_not_supported", []],
    [0x44, "syscall_not_supported", []],
    [0x45, "syscall_not_supported", []],
    [0x46, "syscall_cache_operation", ["void *va, size_t len", "unsigned long op"]],
]


# ARM/ARM64 OP-TEE ldelf (at secure world)
# - core/include/tee/tee_svc.h
# - core/include/kernel/ldelf_syscalls.h
arm_ldelf_syscall_list = [ # noqa: F841
    [0x00, "syscall_sys_return", ["unsigned long ret"]],
    [0x01, "syscall_log", ["const void *buf", "size_t len"]],
    [0x02, "syscall_panic", ["unsigned long code"]],
    [0x03, "ldelf_syscall_map_zi", ["vaddr_t *va", "size_t num_bytes", "size_t pad_begin", "size_t pad_end", "unsigned long flags"]],
    [0x04, "ldelf_syscall_unmap", ["vaddr_t va", "size_t num_bytes"]],
    [0x05, "ldelf_syscall_open_bin", ["const TEE_UUID *uuid", "size_t uuid_size", "uint32_t *handle"]],
    [0x06, "ldelf_syscall_close_bin", ["unsigned long handle"]],
    [0x07, "ldelf_syscall_map_bin", ["vaddr_t *va", "size_t num_bytes", "unsigned long handle", "size_t offs_bytes", "size_t pad_begin", "size_t pad_end", "unsigned long flags"]],
    [0x08, "ldelf_syscall_copy_from_bin", ["void *dst", "size_t offs", "size_t num_bytes", "unsigned long handle"]],
    [0x09, "ldelf_syscall_set_prot", ["unsigned long va", "size_t num_bytes", "unsigned long flags"]],
    [0x0a, "ldelf_syscall_remap", ["unsigned long old_va", "addr_t *new_va", "size_t num_bytes", "size_t pad_begin", "size_t pad_end"]],
    [0x0b, "ldelf_syscall_gen_rnd_num", ["void *buf", "size_t num_bytes"]],
]


# x86_16 FreeDOS int 0x21
# https://en.wikipedia.org/wiki/DOS_API
# https://stanislavs.org/helppc/int_21.html
# http://www2.ift.ulaval.ca/~marchand/ift17583/dosints.pdf
x86_16_dos_syscall_list = [
    # nr, syscall name, return registers, args, arg registers
    # 1.0+
    [0x00, "ProgramTerminate", [], [], []],
    [0x01, "CharacterInput", ["$al"], [], []],
    [0x02, "CharacterOutput", [], ["character"], ["$dl"]],
    [0x03, "AuxiliaryInput", ["$al"], [], []],
    [0x04, "AuxiliaryOutput", [], ["character"], ["$dl"]],
    [0x05, "PrinterOutput", [], ["character"], ["$dl"]],
    [0x06, "DirectConsoleIo", ["$al", "$eflags.zf"], ["character"], ["$dl"]],
    [0x07, "DirectStdinInputNoEcho", ["$al"], [], []],
    [0x08, "ConsoleInputNoEcho", ["$al"], [], []],
    [0x09, "DisplayString", [], ["string"], ["$ds:$dx"]],
    [0x0a, "BufferedKeyboardInput", [], ["buffer"], ["$ds:$dx"]],
    [0x0b, "GetInputStatus", ["$al"], [], []],
    [0x0c, "FlushInputBufferAndInput", ["$al"], ["function"], ["$al"]],
    [0x0d, "DiskReset", [], [], []],
    [0x0e, "SetDefaultDrive", ["$al"], ["drive_number"], ["$dl"]],
    [0x0f, "OpenFile", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x10, "CloseFile", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x11, "FindFirstFile", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x12, "FindNextFile", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x13, "DeleteFile", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x14, "SequentialRead", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x15, "SequentialWrite", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x16, "CreateFile", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x17, "RenameFile", ["$al"], ["FCB"], ["$ds:$dx"]],
    # 0x18: reserved
    [0x19, "GetDefaultDrive", ["$al"], [], []],
    [0x1a, "SetDiskTransferAddress", [], ["DTA"], ["$ds:$dx"]],
    [0x1b, "GetAllocationInfoForDefaultDrive", ["$al", "$cx", "$dx", "$ds:$bx"], [], []],
    [0x1c, "GetAllocationInfoForSpecifiedDrive", ["$al", "$cx", "$dx", "$ds:$bx"], ["drive_number"], ["$dl"]],
    # 0x1d: reserved
    # 0x1e: reserved
    [0x1f, "GetDiskParameterBlockForDefaultDrive", ["$al"], ["drive_number"], ["$dl"]],
    # 0x20: reserved
    [0x21, "RandomRead", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x22, "RandomWrite", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x23, "GetFileSizeInRecords", ["$al"], ["FCB"], ["$ds:$dx"]],
    [0x24, "SetRandomRecordNumber", [], ["FCB"], ["$ds:$dx"]],
    [0x25, "SetInterruptVector", [], ["interrupt_number", "handler"], ["$al", "$ds:$dx"]],
    [0x26, "CreatePSP", [], ["segment_number"], ["$dx"]],
    [0x27, "RandomBlockRead", ["$al", "$cx"], ["FCB", "record_count"], ["$ds:$dx", "$cx"]],
    [0x28, "RandomBlockWrite", ["$al", "$cx"], ["FCB", "record_count"], ["$ds:$dx", "$cx"]],
    [0x29, "ParseFilename", ["$al", "$ds:$si", "$es:$di"], ["control", "string", "buffer"], ["$al", "$ds:$si", "$es:$di"]],
    [0x2a, "GetDate", ["$al", "$cx", "$dh", "$dl"], [], []],
    [0x2b, "SetDate", ["$al"], ["year", "month", "day"], ["$cx", "$dh", "$dl"]],
    [0x2c, "GetTime", ["$ch", "$cl", "$dh", "$dl"], [], []],
    [0x2d, "SetTime", ["$al"], ["hour", "minutes", "seconds", "hundredths"], ["$ch", "$cl", "$dh", "$dl"]],
    [0x2e, "SetVerifyFlag", [], ["verify_flag", "0"], ["$al", "$dl"]],
    # 2.0+
    [0x2f, "GetDiskTransferAddress", ["$es:$bx"], [], []],
    [0x30, "GetDosVersion", ["$al", "$ah", "$bh", "$bl", "$cx"], [], []],
    [0x31, "TerminateAndStayResident", [], ["exit_code", "program_size"], ["$al", "$dx"]],
    [0x32, "GetDiskParameterBlock", ["$al", "$ds:$bx"], ["drive"], ["$dl"]],
    [0x33, "GetOrSetCtrlBreak", ["$al", "$dl"], ["subfunction", "value"], ["$al", "$dl"]],
    [0x34, "GetDosCriticalFlagPointer", ["$es:$bx"], [], []],
    [0x35, "GetInterruptVector", ["$es:$bx"], ["interrupt_number"], ["$al"]],
    [0x36, "GetFreeDiskSpace", ["$ax", "$bx", "$cx", "$dx"], ["drive_number"], ["$dl"]],
    [0x37, "GetOrSetSwitchCharacter", ["$al", "$dl"], ["subfunction", "value"], ["$al", "$dl"]],
    [0x38, "GetOrSetCountryInfo", ["$ax", "$bx", "$ds:$dx"], ["subfunction", "country_code", "buffer"], ["$al", "$bx", "$ds:dx"]],
    [0x39, "CreateSubDirectory", ["$ax"], ["pathname"], ["$ds:$dx"]],
    [0x3a, "RemoveSubDirectory", ["$ax"], ["pathname"], ["$ds:$dx"]],
    [0x3b, "ChangeCurrentDirectory", ["$ax"], ["pathname"], ["$ds:$dx"]],
    [0x3c, "CreateFile", ["$ax"], ["pathname", "attribute"], ["$ds:$dx", "$cx"]],
    [0x3d, "OpenFile", ["$ax"], ["mode", "pathname"], ["$al", "$ds:$dx"]],
    [0x3e, "CloseFile", ["$ax"], ["handle"], ["$bx"]],
    [0x3f, "ReadFileOrDevice", ["$ax"], ["handle", "size"], ["$bx", "$cx", "$ds:$dx"]],
    [0x40, "WriteFileOrDevice", ["$ax"], ["handle", "size", "buffer"], ["$bx", "$cx", "$ds:$dx"]],
    [0x41, "DeleteFile", ["$ax"], ["pathname"], ["$ds:$dx"]],
    [0x42, "SeekFile", ["$dx", "$ax"], ["origin", "handle", "move_size_high", "move_size_low"], ["$al", "$bx", "$cx", "$dx"]],
    [0x43, "GetOrSetFileAttributes", ["$ax", "$cx"], ["subfunction", "pathname", "attribute"], ["$al", "$ds:$dx", "$cx"]],
    [0x44, "IoControlForDevices", ["$ax", "$dx"], ["subfunction", "arg1", "arg2", "arg3"], ["$al", "$bx", "$cx", "$ds:$dx"]],
    [0x45, "DuplicateHandle", ["$ax"], ["handle"], ["$bx"]],
    [0x46, "RedirectHandle", ["$ax"], ["old_handle", "new_handle"], ["$bx", "$cx"]],
    [0x47, "GetCurrentDirectory", ["$ds:$si", "$ax"], ["drive_number", "buffer"], ["$dl", "$ds:$si"]],
    [0x48, "AllocateMemory", ["$ax", "$bx"], ["block_size"], ["$bx"]],
    [0x49, "ReleaseMemory", ["$ax"], ["segment"], ["$es"]],
    [0x4a, "ReallocateMemory", ["$ax", "$bx"], ["new_block_size", "segment"], ["$bx", "$es"]],
    [0x4b, "ExecuteProgram", ["$ax", "$es:$bx"], ["subfunction", "pathname", "parameter"], ["$al", "$ds:$dx", "$es:$bx"]],
    [0x4c, "TerminateWithReturnCode", [], ["return_code"], ["$al"]],
    [0x4d, "GetProgramReturnCode", ["$ah", "$al"], [], []],
    [0x4e, "FindFirstFile", ["$ax"], ["pathname", "attribute"], ["$ds:$dx", "$cx"]], # DTA omitted
    [0x4f, "FindNextFile", ["$ax"], ["pathname"], ["$ds:$dx"]], # DTA omitted
    [0x50, "SetCurrentPSP", [], ["segment"], ["$bx"]],
    [0x51, "GetCurrentPSP", ["$bx"], [], []],
    [0x52, "GetListOfLists", ["$es:$bx"], [], []],
    [0x53, "CreateDiskParameterBlock", ["$es:$bp"], ["bios_parameter", "buffer"], ["$ds:si", "$es:$bp"]],
    [0x54, "GetVerifyFlag", ["$al"], [], []],
    [0x55, "CreateProgramPSP", [], ["segment", "size"], ["$dx", "$si"]],
    [0x56, "RenameFile", ["$ax"], ["old_pathname", "new_pathname"], ["$ds:$dx", "$es:$di"]],
    [0x57, "GetOrSetFileDateAndTime", ["$ax", "$cx", "$dx"], ["subfunction", "handle", "time", "date", "buffer"], ["$al", "$bx", "$cx", "$dx", "$es:$di"]],
    # 2.11+
    [0x58, "GetOrSetAllocationStrategy", ["$ax"], ["subfunction", "strategy"], ["$al", "$bx"]],
    # 3.0+
    [0x59, "GetExtendedErrorInfo", ["$ax", "$bh", "$bl", "$ch"], ["0"], ["$bx"]],
    [0x5a, "CreateTempFile", ["$ax", "$ds:$dx"], ["pathname", "attribute"], ["$ds:$dx", "$cx"]],
    [0x5b, "CreateNewFile", ["$ax"], ["pathname", "attribute"], ["$ds:$dx", "$cx"]],
    [0x5c, "LockOrUnlockFile", ["$ax"], ["subfunction", "handle", "offset_high", "offset_low", "length_high", "length_low"], ["$al", "$bx", "$cx", "$dx", "$si", "$di"]],
    [0x5d, "FileSharingFunctions", ["$ds:$si"], ["subfunction", "arg1"], ["$al", "$ds:$dx"]],
    [0x5e, "NetworkFunctions", ["$ax"], ["subfunction"], ["$al"]], # too complicated
    [0x5f, "NetworkRedirectionFunctions", ["$ax"], ["subfunction"], ["$al"]], # too complicated
    [0x60, "QualifyFilename", ["$es:$di", "$ah"], ["pathname", "buffer"], ["$ds:$si", "$es:$di"]],
    # 0x61: reserved
    [0x62, "GetCurrentPSP", ["$bx"], [], []],
    [0x63, "GetLeadByteTable", ["$ax", "$ds:$si", "$dl"], ["subfunction", "flag"], ["$al", "$dl"]],
    # 3.2+
    [0x64, "SetDeviceDriverLookAhead", ["$dl"], ["subfunction", "arg1"], ["$al", "$dl"]],
    # 3.3+
    [0x65, "GetExtendedCountryInfo", ["$ax"], ["subfunction"], ["$al"]], # too complicated
    [0x66, "GetOrSetGlobalCodePage", ["$ax", "$bx", "$cx"], ["subfunction", "active_codepage", "system_codepage"], ["$al", "$bx", "$dx"]],
    [0x67, "SetHandleCount", ["$ax"], ["max_handle_count"], ["$bx"]],
    [0x68, "CommitFile", ["$ax"], ["handle"], ["$bx"]],
    # 4.0+
    [0x69, "GetOrSetMediaId", ["$ax", "$ds:$dx"], ["subfunction", "drive_number", "buffer"], ["$al", "$bl", "$ds:$dx"]],
    # 0x6a: reserved
    # 0x6b: reserved
    [0x6c, "ExtendedOpenCreateFile", ["$ax", "$cx"], ["0", "mode", "attribute", "control", "spec"], ["$al", "$bx", "$cx", "$dx", "$ds:$si"]],
]


class Syscall:
    @staticmethod
    def parse_common_syscall_defs():
        sc_defs = [
            syscall_defs,
            syscall_defs_compat,
        ]
        dic = {}
        for defs in sc_defs:
            for line in defs.splitlines():
                if line == "":
                    continue
                if line.startswith("#"):
                    continue
                m = re.search(r"asmlinkage\s+(?:long|ssize_t)\s+(\S+)\((.+?)\);", line)
                if not m:
                    continue
                name, args = m.group(1), m.group(2)
                args = [x.strip() for x in args.split(",")]
                if name in dic:
                    err("duplicate: {:s}".format(name))
                    raise
                if len(args) == 1 and args[0] == "void":
                    dic[name] = []
                else:
                    dic[name] = args
        return dic

    @staticmethod
    def parse_syscall_table_defs(table_defs):
        table = []
        for line in table_defs.splitlines():
            if line == "":
                continue
            if line.startswith("#"):
                continue
            entry = line.split()
            if len(entry) == 3: # it is unimplemented
                continue
            entry[0] = int(entry[0])
            table.append(entry)
        return table

    @staticmethod
    @Cache.cache_this_session
    def make_syscall_table(arch, mode):
        if arch == "X86" and mode == "64":
            return_register = X86_64.return_register
            args_register = X86_64.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(x64_syscall_tbl)
            arch_specific_dic = {
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "int __user *child_tidptr", "unsigned long tls",
                ], # kernel/fork.c
                "sys_modify_ldt": [
                    "int func", "void __user *ptr", "unsigned long bytecount",
                ], # arch/x86/kernel/ldt.c
                "sys_arch_prctl": [
                    "int option", "unsigned long arg2",
                ], # arch/x86/kernel/process_64.c
                "sys_iopl": [
                    "unsigned int level",
                ], # arch/x86/kernel/ioport.c
                "compat_sys_x32_rt_sigreturn": [], # arch/x86/kernel/signal.c
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long off",
                ], # arch/x86/kernel/sys_x86_64.c
                "sys_rt_sigreturn": [], # arch/x86/kernel/signal.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # include/linux/syscalls.h
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi not in ["common", "64", "x32"]:
                    continue
                # special case
                if func in arch_specific_dic:
                    if abi in ["common", "64"]:
                        syscall_list.append([nr, name, arch_specific_dic[func]])
                    if abi in ["common", "x32"]:
                        syscall_list.append([nr + 0x40000000, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                if abi in ["common", "64"]:
                    syscall_list.append([nr, name, sc_def[func]])
                if abi in ["common", "x32"]:
                    syscall_list.append([nr + 0x40000000, name, sc_def[func]])

        elif arch == "X86" and mode == "Emulated-32":
            return_register = X86.return_register
            args_register = X86.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(x86_syscall_tbl)
            arch_specific_dic = {
                "compat_sys_sigreturn": [], # arch/x86/ia32/ia32_signal.c
                "compat_sys_rt_sigreturn": [], # arch/x86/ia32/ia32_signal.c
                "compat_sys_old_getrlimit": [
                    "unsigned int resource", "struct compat_rlimit *rlim",
                ], # kernel/sys.c
                "compat_sys_ia32_mmap": [
                    "struct mmap_arg_struct32 __user *arg",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_iopl": [
                    "unsigned int level",
                ], # arch/x86/kernel/ioport.c
                "compat_sys_ia32_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls_val", "int __user *child_tidptr",
                ], # arch/x86/kernel/sys_ia32.c (CONFIG_CLONE_BACKWARDS)
                "sys_modify_ldt": [
                    "int func", "void __user *ptr", "unsigned long bytecount",
                ], # arch/x86/kernel/ldt.c
                "sys_ia32_pread64": [
                    "unsigned int fd", "char __user *ubuf", "u32 count", "u32 poslo", "u32 poshi",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_pwrite64": [
                    "unsigned int fd", "const char __user *ubuf", "u32 count", "u32 poslo", "u32 poshi",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_truncate64": [
                    "const char __user *filename", "unsigned long offset_low", "unsigned long offset_high",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_ftruncate64": [
                    "unsigned int fd", "unsigned long offset_low", "unsigned long offset_high",
                ], # arch/x86/kernel/sys_ia32.c
                "compat_sys_ia32_stat64": [
                    "const char __user *filename", "struct stat64 __user *statbuf",
                ], # arch/x86/kernel/sys_ia32.c
                "compat_sys_ia32_lstat64": [
                    "const char __user *filename", "struct stat64 __user *statbuf",
                ], # arch/x86/kernel/sys_ia32.c
                "compat_sys_ia32_fstat64": [
                    "unsigned long fd", "struct stat64 __user *statbuf",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_readahead": [
                    "int fd", "unsigned int off_lo", "unsigned int off_high", "size_t count",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_set_thread_area": [
                    "struct user_desc __user *u_info",
                ], # arch/x86/kernel/tls.c
                "sys_get_thread_area": [
                    "struct user_desc __user *u_info",
                ], # arch/x86/kernel/tls.c
                "sys_ia32_fadvise64": [
                    "int fd", "unsigned int offset_lo", "unsigned int offset_hi", "size_t len", "int advice",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_fadvise64_64": [
                    "int fd", "__u32 offset_low", "__u32 offset_high", "__u32 len_low", "__u32 len_high", "int advice",
                ], # arch/x86/kernel/sys_ia32.c
                "compat_sys_ia32_fstatat64": [
                    "unsigned int dfd", "const char __user *filename", "struct stat64 __user *statbuf", "int flag",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_sync_file_range": [
                    "int fd", "unsigned int off_low", "unsigned int off_hi", "unsigned int n_low",
                    "unsigned int n_hi", "unsigned int flags",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_fallocate": [
                    "int fd", "int mode", "unsigned int offset_lo", "unsigned int offset_hi",
                    "unsigned int len_lo", "unsigned int len_hi",
                ], # arch/x86/kernel/sys_ia32.c
                "compat_sys_arch_prctl": [
                    "int option", "unsigned long arg2",
                ], # arch/x86/kernel/process_64.c
            }

            syscall_list = []
            for entry in tbl:
                if len(entry) == 5:
                    nr, abi, name, _, func = entry # use compat
                else:
                    nr, abi, name, func = entry
                if abi != "i386":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "X86" and mode == "Native-32":
            return_register = X86.return_register
            args_register = X86.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(x86_syscall_tbl)
            arch_specific_dic = {
                "sys_iopl": [
                    "unsigned int level",
                ], # arch/x86/kernel/ioport.c
                "sys_vm86old": [
                    "struct vm86_struct __user *user_vm86",
                ], # arch/x86/kernel/vm86_32.c
                "sys_sigreturn": [], # arch/x86/kernel/signal.c
                "sys_rt_sigreturn": [], # arch/x86/kernel/signal.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "sys_modify_ldt": [
                    "int func", "void __user *ptr", "unsigned long bytecount",
                ], # arch/x86/kernel/ldt.c
                "sys_vm86": [
                    "unsigned long cmd", "unsigned long arg",
                ], # arch/x86/kernel/vm86_32.c
                "sys_ia32_pread64": [
                    "unsigned int fd", "char __user *ubuf", "u32 count", "u32 poslo", "u32 poshi",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_pwrite64": [
                    "unsigned int fd", "const char __user *ubuf", "u32 count", "u32 poslo", "u32 poshi",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_truncate64": [
                    "const char __user *filename", "unsigned long offset_low", "unsigned long offset_high",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_ftruncate64": [
                    "unsigned int fd", "unsigned long offset_low", "unsigned long offset_high",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_readahead": [
                    "int fd", "unsigned int off_lo", "unsigned int off_high", "size_t count",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_set_thread_area": [
                    "struct user_desc __user *u_info",
                ], # arch/x86/kernel/tls.c
                "sys_get_thread_area": [
                    "struct user_desc __user *u_info",
                ], # arch/x86/kernel/tls.c
                "sys_ia32_fadvise64": [
                    "int fd", "unsigned int offset_lo", "unsigned int offset_hi", "size_t len", "int advice",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_fadvise64_64": [
                    "int fd", "__u32 offset_low", "__u32 offset_high", "__u32 len_low", "__u32 len_high", "int advice",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_sync_file_range": [
                    "int fd", "unsigned int off_low", "unsigned int off_hi", "unsigned int n_low",
                    "unsigned int n_hi", "unsigned int flags",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_ia32_fallocate": [
                    "int fd", "int mode", "unsigned int offset_lo", "unsigned int offset_hi",
                    "unsigned int len_lo", "unsigned int len_hi",
                ], # arch/x86/kernel/sys_ia32.c
                "sys_arch_prctl": [
                    "int option", "unsigned long arg2",
                ], # arch/x86/kernel/process_32.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "unsigned int mask_1",
                    "unsigned int mask_2", "int dfd", "const char  __user *pathname",
                ], # include/linux/syscalls.h
            }

            syscall_list = []
            for entry in tbl:
                if len(entry) == 5:
                    nr, abi, name, func, _ = entry # dont use compat
                else:
                    nr, abi, name, func = entry
                if abi != "i386":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "X86" and mode == "16":
            syscall_list = []
            return_register = {}
            args_register = {}
            for nr, name, ret_regs, args, arg_regs in x86_16_dos_syscall_list:
                syscall_list.append([nr, name, args])
                return_register[nr] = ret_regs
                args_register[nr] = arg_regs

        elif arch == "ARM64" and mode == "ARM":
            return_register = AARCH64.return_register
            args_register = AARCH64.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(arm64_syscall_tbl)
            arch_specific_dic = {
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int __user *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "sys_rt_sigreturn": [], # arch/arm64/kernel/signal.c
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long off",
                ], # arch/arm64/kernel/sys.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # include/linux/syscalls.h
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "arm64":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "ARM" and mode == "Emulated-32": # only support EABI
            return_register = ARM.return_register
            args_register = ARM.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(arm_compat_syscall_tbl)
            arch_specific_dic = {
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int __user *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "compat_sys_aarch32_pread64": [
                    "unsigned int fd", "char *buf", "size_t count", "u32 __pad", "arg_u32p(pos)",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_aarch32_pwrite64": [
                    "unsigned int fd", "const char *buf", "size_t count", "u32 __pad", "arg_u32p(pos)",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_aarch32_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long off_4k",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_aarch32_truncate64": [
                    "const char *path", "u32 __pad", "arg_u32p(length)",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_aarch32_ftruncate64": [
                    "unsigned int fd", "u32 __pad", "arg_u32p(length)",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_aarch32_readahead": [
                    "int fd", "u32 __pad", "arg_u32(offset)", "size_t count",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_aarch32_statfs64": [
                    "const char *pathname", "compat_size_t sz", "struct compat_statfs64 *buf",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_aarch32_fstatfs64": [
                    "unsigned int fd", "compat_size_t sz", "struct compat_statfs64 *buf",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_aarch32_fadvise64_64": [
                    "int fd", "int advice", "arg_u32p(offset)", "arg_u32p(len)",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_aarch32_sync_file_range2": [
                    "int fd", "unsigned int flags", "arg_u32p(offset)", "arg_u32p(nbytes)",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_aarch32_fallocate": [
                    "int fd", "int mode", "arg_u32p(offset)", "arg_u32p(len)",
                ], # arch/arm64/kernel/sys32.c
                "compat_sys_old_semctl": [
                    "int semid", "int semnum", "int cmd", "int arg",
                ], # ipc/sem.c
                "compat_sys_old_msgctl": [
                    "int msqid", "int cmd", "void *uptr",
                ], # ipc/msg.c
                "compat_sys_old_shmctl": [
                    "int shmid", "int cmd", "void *uptr",
                ], # ipc/shm.c
                "compat_sys_sigreturn": [], # arch/arm64/kernel/signal32.c
                "compat_sys_rt_sigreturn": [], # arch/arm64/kernel/signal32.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "arm":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

            arch_specific_extra = [
                [0xf0002, "cacheflush", [
                    "unsigned long start", "unsigned long end", "int flags",
                ]], # arch/arm64/kernel/sys_compat.c
                [0xf0005, "set_tls", [
                    "unsigned long val",
                ]], # arch/arm64/kernel/sys_compat.c
            ]
            syscall_list += arch_specific_extra

        elif arch == "ARM" and mode == "Native-32": # only support EABI
            return_register = ARM.return_register
            args_register = ARM.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(arm_native_syscall_tbl)
            arch_specific_dic = {
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int __user *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "sys_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff",
                ], # include/asm-generic/syscalls.h
                "sys_sigreturn_wrapper": [], # arch/arm/kernel/entry-common.S
                "sys_rt_sigreturn_wrapper": [], # arch/arm/kernel/entry-common.S
                "sys_statfs64_wrapper": [
                    "const char __user *path", "size_t sz", "struct statfs64 __user *buf",
                ], # arch/arm/kernel/entry-common.S
                "sys_fstatfs64_wrapper": [
                    "unsigned int fd", "size_t sz", "struct statfs64 __user *buf",
                ], # arch/arm/kernel/entry-common.S
                "sys_arm_fadvise64_64": [
                    "int fd", "int advice", "loff_t offset", "loff_t len",
                ], # arch/arm/kernel/sys_arm.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use OABI
                if abi not in ["common", "eabi"]:
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

            arch_specific_extra = [
                [0xf0001, "breakpoint", []], # arch/arm/kernel/traps.c
                [0xf0002, "cacheflush", [
                    "unsigned long start", "unsigned long end", "int flags",
                ]], # arch/arm/kernel/traps.c
                [0xf0003, "usr26", []], # arch/arm/kernel/traps.c
                [0xf0004, "usr32", []], # arch/arm/kernel/traps.c
                [0xf0005, "set_tls", [
                    "unsigned long val",
                ]], # arch/arm/kernel/traps.c
                [0xf0006, "get_tls", []], # arch/arm/kernel/traps.c
            ]
            syscall_list += arch_specific_extra

        elif arch in ["ARM64", "ARM"] and mode == "Secure-World":
            if arch == "ARM64":
                return_register = AARCH64.return_register
                args_register = AARCH64.syscall_parameters + ["$x6"] # OPTEE uses 7 args
            else:
                return_register = ARM.return_register
                args_register = ARM.syscall_parameters
            syscall_list = arm_OPTEE_syscall_list.copy()

        elif arch == "MIPS" and mode == "32":
            return_register = MIPS.return_register
            args_register = MIPS.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(mips_o32_syscall_tbl)
            arch_specific_dic = {
                "sys_syscall": ["...", ], #
                "__sys_fork": [], #
                "sys_rt_sigreturn": [], # arch/mips/kernel/signal.c
                "sysm_pipe": [], # arch/mips/kernel/syscall.c
                "sys_mips_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t offset",
                ], # arch/mips/kernel/syscall.c
                "sys_sigreturn": [], #
                "__sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int __user *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "sys_cacheflush": [
                    "unsigned long addr", "unsigned long bytes", "unsigned int cache",
                ], # arch/mips/mm/cache.c
                "sys_cachectl": [
                    "char *addr", "int nbytes", "int op",
                ], # arch/mips/kernel/syscall.c
                "__sys_sysmips": [
                    "long cmd", "long arg1", "long arg2",
                ], # arch/mips/kernel/syscall.c
                "sys_mips_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff",
                ], # arch/mips/kernel/syscall.c
                "sys_set_thread_area": [
                    "unsigned long addr",
                ], # arch/mips/kernel/syscall.c
                "__sys_clone3": [
                    "struct clone_args __user *uargs", "size_t size",
                ], #
                "sys_sigsuspend": [
                    "sigset_t __user *uset",
                ], # arch/mips/kernel/signal.c
                "sys_sigaction": [
                    "int sig2", "const struct sigaction __user *act", "struct sigaction __user *oact",
                ], # arch/mips/kernel/signal.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use compat
                if abi != "o32":
                    continue
                nr += 4000 # arch/mips/include/asm/unistd.h
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "MIPS" and mode == "n32":
            return_register = MIPSN32.return_register
            args_register = MIPSN32.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(mips_n32_syscall_tbl)
            arch_specific_dic = {
                "__sys_fork": [], #
                "sysm_pipe": [], # arch/mips/kernel/syscall.c
                "sys_mips_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t offset",
                ], # arch/mips/kernel/syscall.c
                "__sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int __user *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "sys_cacheflush": [
                    "unsigned long addr", "unsigned long bytes", "unsigned int cache",
                ], # arch/mips/mm/cache.c
                "sys_cachectl": [
                    "char *addr", "int nbytes", "int op",
                ], # arch/mips/kernel/syscall.c
                "__sys_sysmips": [
                    "long cmd", "long arg1", "long arg2",
                ], # arch/mips/kernel/syscall.c
                "sys_set_thread_area": [
                    "unsigned long addr",
                ], # arch/mips/kernel/syscall.c
                "__sys_clone3": [
                    "struct clone_args __user *uargs", "size_t size",
                ], #
                "compat_sys_old_shmctl": [
                    "int shmid", "int cmd", "void *uptr",
                ], # ipc/shm.c
                "compat_sys_old_semctl": [
                    "int semid", "int semnum", "int cmd", "int arg",
                ], # ipc/sem.c
                "compat_sys_old_msgctl": [
                    "int msqid", "int cmd", "void *uptr",
                ], # ipc/msg.c
                "sys_32_personality": [
                    "unsigned long personality",
                ], # arch/mips/kernel/linux32.c
                "sysn32_rt_sigreturn": [], # arch/mips/kernel/signal_n32.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use compat
                if abi != "n32":
                    continue
                nr += 6000 # arch/mips/include/asm/unistd.h
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "MIPS" and mode == "64":
            return_register = MIPS64.return_register
            args_register = MIPS64.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(mips_n64_syscall_tbl)
            arch_specific_dic = {
                "sys_mips_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t offset",
                ], # arch/mips/kernel/syscall.c
                "sysm_pipe": [], # arch/mips/kernel/syscall.c
                "__sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int __user *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "__sys_fork": [], #
                "sys_rt_sigreturn": [], # arch/mips/kernel/signal.c
                "sys_cacheflush": [
                    "unsigned long addr", "unsigned long bytes", "unsigned int cache",
                ], # arch/mips/mm/cache.c
                "sys_cachectl": [
                    "char *addr", "int nbytes", "int op",
                ], # arch/mips/kernel/syscall.c
                "__sys_sysmips": [
                    "long cmd", "long arg1", "long arg2",
                ], # arch/mips/kernel/syscall.c
                "sys_set_thread_area": [
                    "unsigned long addr",
                ], # arch/mips/kernel/syscall.c
                "__sys_clone3": [
                    "struct clone_args __user *uargs", "size_t size",
                ], #
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use compat
                if abi != "n64":
                    continue
                nr += 5000 # arch/mips/include/asm/unistd.h
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "PPC" and mode == "32":
            return_register = PPC.return_register
            args_register = PPC.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(ppc_syscall_tbl)
            arch_specific_dic = {
                "sys_sigreturn": [], # arch/powerpc/kernel/signal_32.c
                "sys_rt_sigreturn": [], # arch/powerpc/kernel/signal_32.c
                "sys_mmap": [
                    "unsigned long addr", "size_t len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t offset",
                ], # arch/powerpc/kernel/syscalls.c
                "sys_mmap2": [
                    "unsigned long addr", "size_t len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff",
                ], # arch/powerpc/kernel/syscalls.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int __user *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "sys_swapcontext": [
                    "struct ucontext __user *old_ctx", "struct ucontext __user *new_ctx", "long ctx_size",
                ], # arch/powerpc/kernel/signal_32.c
                "ppc_fadvise64_64": [
                    "int fd", "int advice", "u32 offset_high", "u32 offset_low", "u32 len_high", "u32 len_low",
                ], # arch/poerpc/kernel/syscalls.c
                "sys_rtas": [
                    "struct rtas_args __user *uargs",
                ], # arch/powerpc/include/asm/syscalls.h
                "sys_debug_setcontext": [
                    "struct ucontext __user *ctx", "int ndbg", "struct sig_dbg_op __user *dbg",
                ], # arch/powerpc/kernel/signal_32.c
                "sys_subpage_prot": [
                    "unsigned long addr", "unsigned long len", "u32 __user *map",
                ], # arch/powerpc/mm/book3s64/subpage_prot.c
                "sys_ppc_pread64": [
                    "unsigned int fd", "char __user *ubuf", "compat_size_t count", "u32 reg6", "u32 pos1", "u32 pos2",
                ], # arch/powerpc/kernel/sys_ppc32.c
                "sys_ppc_pwrite64": [
                    "unsigned int fd", "const char __user *ubuf", "compat_size_t count", "u32 reg6", "u32 pos1", "u32 pos2",
                ], # arch/powerpc/kernel/sys_ppc32.c
                "sys_ppc_readahead": [
                    "int fd", "u32 r4", "u32 offset1", "u32 offset2", "u32 count",
                ], # arch/powerpc/kernel/sys_ppc32.c
                "sys_ppc_truncate64": [
                    "const char __user *path", "u32 reg4", "unsigned long len1", "unsigned long len2",
                ], # arch/powerpc/kernel/sys_ppc32.c
                "sys_ppc_ftruncate64": [
                    "unsigned int fd", "u32 reg4", "unsigned long len1", "unsigned long len2",
                ], # arch/powerpc/kernel/sys_ppc32.c
                "sys_ppc32_fadvise64": [
                    "int fd", "u32 unused", "u32 offset1", "u32 offset2", "size_t len", "int advice",
                ], # arch/powerpc/kernel/sys_ppc32.c
                "sys_ppc_fadvise64_64": [
                    "int fd", "int advice", "u32 offset_high", "u32 offset_low", "u32 len_high", "u32 len_low",
                ], # arch/powerpc/kernel/syscalls.c
                "sys_ppc_sync_file_range2": [
                    "int fd", "unsigned int flags", "unsigned int offset1", "unsigned int offset2", "unsigned int nbytes1", "unsigned int nbytes2",
                ], # arch/powerpc/kernel/sys_ppc32.c
                "sys_ppc_fallocate": [
                    "int fd", "int mode", "u32 offset1", "u32 offset2", "u32 len1", "u32 len2",
                ], # arch/powerpc/kernel/sys_ppc32.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "unsigned int mask_1",
                    "unsigned int mask_2", "int dfd", "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use compat
                if abi not in ["common", "32", "nospu"]:
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "PPC" and mode == "64":
            return_register = PPC64.return_register
            args_register = PPC64.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(ppc_syscall_tbl)
            arch_specific_dic = {
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int __user *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "sys_rt_sigreturn": [], # arch/powerpc/kernel/signal_64.c
                "sys_mmap": [
                    "unsigned long addr", "size_t len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t offset",
                ], # arch/powerpc/kernel/syscalls.c
                "sys_mmap2": [
                    "unsigned long addr", "size_t len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff",
                ], # arch/powerpc/kernel/syscalls.c
                "sys_ppc64_personality": [
                    "unsigned long personality",
                ], # arch/powerpc/kernel/syscalls.c
                "sys_swapcontext": [
                    "struct ucontext __user *old_ctx", "struct ucontext __user *new_ctx", "long ctx_size",
                ], # arch/powerpc/kernel/signal_64.c
                "sys_rtas": [
                    "struct rtas_args __user *uargs",
                ], # arch/powerpc/include/asm/syscalls.h
                "sys_subpage_prot": [
                    "unsigned long addr", "unsigned long len", "u32 __user *map",
                ], # arch/powerpc/mm/book3s64/subpage_prot.c
                "sys_switch_endian": [], # arch/powerpc/kernel/syscalls.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use compat
                if abi not in ["common", "64", "nospu"]:
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "SPARC" and mode in ["32", "32PLUS"]:
            if mode == "32":
                return_register = SPARC.return_register
                args_register = SPARC.syscall_parameters
            elif mode == "32PLUS":
                return_register = SPARC32PLUS.return_register
                args_register = SPARC32PLUS.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(sparc_syscall_tbl)
            arch_specific_dic = {
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long off"
                ], # arch/sparc/kernel/sys_sparc_32.c
                "sys_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff"
                ], # arch/sparc/kernel/sys_sparc_32.c
                "sunos_execv": [
                    "const char __user *filename", "const char __user *const __user *argv",
                    "const char __user *const __user *envp",
                ], # arch/sparc/kernel/entry.S
                "sys_sparc_pipe": [], # arch/sparc/kernel/sys_sparc_32.c
                "sys_getpagesize": [], # arch/sparc/kernel/sys_sparc_32.c
                "sys_getdomainname": [
                    "char __user *name", "int len"
                ], # arch/sparc/kernel/sys_sparc_32.c
                "sys_sparc_remap_file_pages": [
                    "unsigned long start", "unsigned long size", "unsigned long prot",
                    "unsigned long pgoff", "unsigned long flags",
                ], # kernel/sys_sparc_32.c
                "sys_sparc_sigaction": [
                    "int, sig", "struct old_sigaction __user *act", "struct old_sigaction __user *oact",
                ], # arch/sparc/kernel/sys_sparc_32.c
                "sys_sigreturn": [], # arch/sparc/kernel/syscalls.S
                "sys_rt_sigreturn": [], # arch/sparc/kernel/syscalls.S
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "int __user *child_tidptr", "unsigned long tls",
                ], # kernel/fork.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use compat
                if abi not in ["common", "32"]:
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func in ["sys_ni_syscall", "sys_nis_syscall"]:
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "SPARC" and mode == "64":
            return_register = SPARC64.return_register
            args_register = SPARC64.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(sparc_syscall_tbl)
            arch_specific_dic = {
                "sparc_exit": [
                    "int error_code",
                ], # arch/sparc/kernel/syscalls.S
                "sys_sparc_pipe": [], # arch/sparc/kernel/sys_sparc_64.c
                "sys_memory_ordering": [
                    "unsigned long model",
                ], # arch/sparc/kernel/sys_sparc_64.c
                "sys64_execve": [
                    "const char __user *filename", "const char __user *const __user *argv",
                    "const char __user *const __user *envp",
                ], # arch/sparc/kernel/syscalls.S
                "sys_getpagesize": [], # arch/sparc/kernel/sys_sparc_64.c
                "sys_64_munmap": [
                    "unsigned long addr", "size_t len",
                ], # arch/sparc/kernel/sys_sparc_64.c
                "sys_getdomainname": [
                    "char __user *name", "int len"
                ], # arch/sparc/kernel/sys_sparc_64.c
                "sys_utrap_install": [
                    "utrap_entry_t type", "utrap_handler_t new_p", "utrap_handler_t new_d",
                    "utrap_handler_t __user * old_p", "utrap_handler_t __user *old_d",
                ], # arch/sparc/kernel/sys_sparc_64.c
                "sparc_exit_group": [
                    "int error_code",
                ], # arch/sparc/kernel/syscalls.S
                "sys_sparc64_personality": [
                    "unsigned long personality",
                ], # arch/sparc/kernel/sys_sparc_64.c
                "sys_sparc_ipc": [
                    "unsigned int call", "int first", "unsigned long second",
                    "unsigned long third", "void __user *ptr", "long fifth",
                ], # arch/sparc/kernel/sys_sparc_64.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "int __user *child_tidptr", "unsigned long tls",
                ], # kernel/fork.c
                "sys_sparc_adjtimex": [
                    "struct __kernel_timex __user *txc_p",
                ], # arch/sparc/kernel/sys_sparc_64.c
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long off"
                ], # arch/sparc/kernel/sys_sparc_64.c
                "sys_64_mremap": [
                    "unsigned long addr", "unsigned long old_len", "unsigned long new_len",
                    "unsigned long flags", "unsigned long new_addr",
                ], # arch/sparc/kernel/sys_sparc_64.c
                "sys_sparc_clock_adjtime": [
                    "const clockid_t which_clock", "struct __kernel_timex __user *txc_p",
                ], # arch/sparc/kernel/sys_sparc_64.c
                "sys_kern_features": [], # arch/sparc/kernel/sys_sparc_64.c
                "sys64_execveat": [
                    "int dfd", "const char __user *filename", "const char __user *const __user *argv",
                    "const char __user *const __user *envp", "int flags",
                ] ,# arch/sparc/kernel/syscalls.S
                "sys_rt_sigreturn": [
                    "struct pt_regs *regs",
                ], # arch/sparc/kernel/signal_64.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use compat
                if abi not in ["common", "64"]:
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func in ["sys_ni_syscall", "sys_nis_syscall"]:
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "RISCV" and mode == "32":
            return_register = RISCV.return_register
            args_register = RISCV.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(riscv32_syscall_tbl)
            arch_specific_dic = {
                "sys_rt_sigreturn": [], # arch/riscv/kernel/signal.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "sys_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t offset",
                ], # arch/riscv/kernel/sys_riscv.c"
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "riscv32":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

            arch_specific_extra = [
                [259, "riscv_flush_icache", [
                    "uintptr_t start", "uintptr_t end", "uintptr_t flags",
                ]], # arch/riscv/include/uapi/asm/unistd.h, arch/riscv/kernel/sys_riscv.c
            ]
            syscall_list += arch_specific_extra

        elif arch == "RISCV" and mode == "64":
            return_register = RISCV64.return_register
            args_register = RISCV64.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(riscv64_syscall_tbl)
            arch_specific_dic = {
                "sys_rt_sigreturn": [], # arch/riscv/kernel/signal.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t offset",
                ], # arch/riscv/kernel/sys_riscv.c"
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "riscv64":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

            arch_specific_extra = [
                [259, "riscv_flush_icache", [
                    "uintptr_t start", "uintptr_t end", "uintptr_t flags",
                ]], # arch/riscv/include/uapi/asm/unistd.h, arch/riscv/kernel/sys_riscv.c
            ]
            syscall_list += arch_specific_extra

        elif arch == "S390X" and mode == "64":
            return_register = S390X.return_register
            args_register = S390X.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(s390x_syscall_tbl)
            arch_specific_dic = {
                "sys_s390_ipc": [
                    "uint, call", "int first", "unsigned long second",
                    "unsigned long third", "void __user *ptr",
                ], # arch/s390/kernel/syscall.c
                "sys_sigreturn": [], # arch/s390/kernel/signal.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int stack_size",
                    "int __user *parent_tidptr", "int __user *child_tidptr", "unsigned long tls",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS2)
                "sys_s390_personality": [
                    "unsigned int personality",
                ], # arch/s390/kernel/syscall.c
                "sys_rt_sigreturn": [], # arch/s390/kernel/signal.c
                "sys_s390_runtime_instr": [
                    "int, command", "int signum",
                ], # arch/s390/kernel/runtime_instr.c
                "sys_s390_pci_mmio_write": [
                    "unsigned long mmio_addr", "const void __user *user_buffer", "size_t length",
                ], # arch/s390/pci/pci_mmio.c
                "sys_s390_pci_mmio_read": [
                    "unsigned long mmio_addr", "void __user *user_buffer", "size_t length",
                ], # arch/s390/pci/pci_mmio.c
                "sys_s390_guarded_storage": [
                    "int command", "struct gs_cb __user *gs_cb",
                ], # arch/s390/kernel/guarded_storage.c
                "sys_s390_sthyi": [
                    "unsigned long function_code", "void __user *buffer", "u64 __user *return_code",
                    "unsigned long flags",
                ], # arch/s390/kernel/sthyi.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use compat
                if abi not in ["common", "64"]:
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func in ["sys_ni_syscall", "-"]:
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "SH4" and mode == "SH4":
            return_register = SH4.return_register
            args_register = SH4.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(sh4_syscall_tbl)
            arch_specific_dic = {
                "sys_sh_pipe": [], # arch/sh/kernel/sys_sh32.c
                "old_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "int fd", "unsigned long off",
                ], # arch/sh/kernel/sys_sh.c
                "sys_sigreturn": [], # arch/sh/kernel/signal_32.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "int __user *child_tidptr", "unsigned long tls",
                ], # kernel/fork.c
                "sys_cacheflush": [
                    "unsigned long addr", "unsigned long len", "int op",
                ], # arch/sh/kernel/sys_sh.c
                "sys_rt_sigreturn": [], # arch/sh/kernel/signal_32.c
                "sys_pread_wrapper": [
                    "unsigned int fd", "char __user *buf", "size_t count", "long dummy", "loff_t pos",
                ], # arch/sh/kernel/sys_sh32.c
                "sys_pwrite_wrapper": [
                    "unsigned int fd", "const char __user *buf", "size_t count", "long dummy", "loff_t pos",
                ], # arch/sh/kernel/sys_sh32.c
                "sys_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff",
                ], # arch/sh/kernel/sys_sh.c
                "sys_fadvise64_64_wrapper": [
                    "int fd", "u32 offset0", "u32 offset1", "u32 len0", "u32 len1", "int advice",
                ], # arch/sh/kernel/sys_sh32.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
                "sys_sh_sync_file_range6": [
                    "int fd", "u64 offset", "u64 nbytes", "unsigned int flags",
                ], # sh/kernel/sys_sh32.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "common":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "M68K" and mode == "32":
            return_register = M68K.return_register
            args_register = M68K.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(m68k_syscall_tbl)
            arch_specific_dic = {
                "__sys_fork": [], # kernel/fork.c
                "sys_sigreturn": [], # arch/m68k/kernel/entry.S
                "__sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "int __user *child_tidptr", "unsigned long tls",
                ], # kernel/fork.c
                "sys_cacheflush": [
                    "unsigned long addr", "int scope", "int cache", "unsigned long len",
                ], #
                "sys_getpagesize": [], # arch/m68k/kernel/sys_m68k.c
                "sys_rt_sigreturn": [], # arch/m68k/kernel/entry.S
                "__sys_vfork": [], # kernel/fork.c
                "sys_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff",
                ], # arch/m68k/kernel/sys_m68k.c
                "sys_get_thread_area": [], # arch/m68k/kernel/sys_m68k.c
                "sys_set_thread_area": [
                    "unsigned long tp",
                ], # arch/m68k/kernel/sys_m68k.c
                "sys_atomic_cmpxchg_32": [
                    "unsigned long newval", "int oldval", "int d3", "int d4", "int d5",
                    "unsigned long __user *mem",
                ], # arch/m68k/kernel/sys_m68k.c
                "sys_atomic_barrier": [], # arch/m68k/kernel/sys_m68k.c
                "__sys_clone3": [
                    "struct clone_args __user *uargs", "size_t size",
                ], #
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "common":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "ALPHA" and mode == "ALPHA":
            return_register = ALPHA.return_register
            args_register = ALPHA.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(alpha_syscall_tbl)
            arch_specific_dic = {
                "alpha_syscall_zero": [], # arch/alpha/kernel/entry.S
                "alpha_fork": [], # arch/alpha/kernel/entry.S (fork_like macro)
                "sys_osf_wait4": [
                    "pid_t pid", "int __user *ustatus", "int options", "struct rusage32 __user *ur",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_brk": [
                    "unsigned long brk",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_getxpid": [], # arch/alpha/kernel/osf_sys.c
                "sys_osf_mount": [
                    "unsigned long typenr", "const char __user *path", "int flag", "void __user *data"
                ], # arch/alpha/kernel/osf_sys.c
                "sys_getxuid": [], # arch/alpha/kernel/osf_sys.c
                "sys_alpha_pipe": [], # arch/alpha/kernel/osf_sys.c
                "sys_osf_set_program_attributes": [
                    "unsigned long text_start", "unsigned long text_len",
                    "unsigned long bss_start", "unsigned long bss_len",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_getxgid": [], # arch/alpha/kernel/osf_sys.c
                "sys_osf_sigprocmask": [
                    "int how", "unsigned long newmask",
                ], # arch/alpha/kernel/signal.c
                "sys_getpagesize": [], # arch/alpha/kernel/osf_sys.c
                "alpha_vfork": [], # arch/alpha/kernel/entry.S (fork_like macro)
                "sys_osf_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long off",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_getdtablesize": [], # arch/alpha/kernel/osf_sys.c
                "sys_osf_select": [
                    "int, n, fd_set __user *inp", "fd_set __user *outp",
                    "fd_set __user *exp", "struct timeval32 __user *tvp",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_getpriority": [
                    "int which", "int who",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_sigreturn": [], # arch/alpha/kernel/entry.S (sigreturn_like macro)
                "sys_osf_sigstack": [
                    "struct sigstack __user *uss", "struct sigstack __user *uoss",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_gettimeofday": [
                    "struct timeval32 __user *tv", "struct timezone __user *tz",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_getrusage": [
                    "int who", "struct rusage32 __user *ru",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_settimeofday": [
                    "struct timeval32 __user *tv", "struct timezone __user *tz",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_utimes": [
                    "const char __user *filename", "struct timeval32 __user *tvs",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_sigaction": [
                    "int, sig", "const struct osf_sigaction __user *act", "struct osf_sigaction __user *oact",
                ], # arch/alpha/kernel/signal.c
                "sys_osf_getdirentries": [
                    "unsigned int fd", "struct osf_dirent __user *dirent",
                    "unsigned int count", "long __user *basep",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_statfs": [
                    "const char __user *pathname", "struct osf_statfs __user *buffer", "unsigned long bufsiz",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_fstatfs": [
                    "unsigned long fd", "struct osf_statfs __user *buffer", "unsigned long bufsiz",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_getdomainname": [
                    "char __user *name", "int namelen",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_utsname": [
                    "char __user *name",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_stat": [
                    "char __user *name", "struct osf_stat __user *buf",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_lstat": [
                    "char __user *name", "struct osf_stat __user *buf",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_fstat": [
                    "int fd", "struct osf_stat __user *buf",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_statfs64": [
                    "char __user *pathname", "struct osf_statfs64 __user *buffer", "unsigned long bufsiz",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_fstatfs64": [
                    "unsigned long fd", "struct osf_statfs64 __user *buffer", "unsigned long bufsiz",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_sysinfo": [
                    "int command", "char __user *buf", "long count",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_proplist_syscall": [
                    "enum pl_code code", "union pl_args __user *args",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_usleep_thread": [
                    "struct timeval32 __user *sleep", "struct timeval32 __user *remain",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_getsysinfo": [
                    "unsigned long op", "void __user *buffer", "unsigned long nbytes",
                    "int __user *start", "void __user *arg",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_osf_setsysinfo": [
                    "unsigned long op", "void __user *buffer", "unsigned long nbytes",
                    "int __user *start", "void __user *arg",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_sethae": [
                    "unsigned long val",
                ], # arch/alpha/kernel/osf_sys.c
                "sys_old_adjtimex": [
                    "struct timex32 __user *txc_p",
                ], # arch/alpha/kernel/osf_sys.c
                "alpha_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "int __user *child_tidptr", "unsigned long tls",
                ], # arch/alpha/kernel/entry.S (fork_like macro)
                "alpha_clone3": [
                    "struct clone_args __user *uargs", "size_t size",
                ], # arch/alpha/kernel/entry.S (fork_like macro)
                "sys_rt_sigreturn": [], # arch/alpha/kernel/entry.S (sigreturn_like macro)
                "sys_rt_sigaction": [
                    "int sig", "const struct sigaction __user *act", "struct sigaction __user *oact",
                    "size_t sigsetsize", "void __user *restorer",
                ], # arch/alpha/kernel/signal.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "common":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "HPPA" and mode == "32":
            return_register = HPPA.return_register
            args_register = HPPA.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(hppa_syscall_tbl)
            arch_specific_dic = {
                "sys_fork_wrapper": [], # arch/parisc/kernel/entry.S (fork_like macro)
                "sys_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff",
                ], # arch/parisc/kernel/sys_parisc.c
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long offset",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_pread64": [
                    "unsigned int fd", "char __user *buf", "size_t count",
                    "unsigned int high", "unsigned int low",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_pwrite64": [
                    "unsigned int fd", "const char __user *buf", "size_t count",
                    "unsigned int high", "unsigned int low",
                ], # arch/parisc/kernel/sys_parisc.c
                "sys_vfork_wrapper": [], # arch/parisc/kernel/entry.S (fork_like macro)
                "sys_clone_wrapper": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int *child_tidptr",
                ], # arch/parisc/kernel/entry.S (fork_like macro, CONFIG_CLONE_BACKWARDS)
                "parisc_personality": [
                    "unsigned long personality",
                ], # arch/parisc/kernel/sys_parisc.c
                "sys_rt_sigreturn_wrapper": [], # arch/parisc/kernel/entry.S
                "parisc_truncate64": [
                    "const char __user * path", "unsigned int high", "unsigned int low",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_ftruncate64": [
                    "unsigned int fd", "unsigned int high", "unsigned int low",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_readahead": [
                    "int fd", "unsigned int high", "unsigned int low", "size_t count",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_fadvise64_64": [
                    "int fd", "unsigned int high_off", "unsigned int low_off",
                    "unsigned int high_len", "unsigned int low_len", "int advice",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_sync_file_range": [
                    "int fd", "u32 hi_off", "u32 lo_off", "u32 hi_nbytes", "u32 lo_nbytes",
                    "unsigned int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_fallocate": [
                    "int fd", "int mode", "u32 offhi", "u32 offlo", "u32 lenhi", "u32 lenlo",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_timerfd_create": [
                    "int clockid", "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_signalfd4": [
                    "int ufd", "sigset_t __user *user_mask", "size_t sizemask", "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_eventfd2": [
                    "unsigned int count", "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_pipe2": [
                    "int __user *fildes", "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_inotify_init1": [
                    "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_userfaultfd": [
                    "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "sys_clone3_wrapper": [
                    "struct clone_args __user *uargs", "size_t size",
                ], # arch/parisc/kernel/entry.S (fork_like macro)
                "parisc_madvise": [
                    "unsigned long start", "size_t len_in", "int behavior",
                ], # arch/parisc/kernel/sys_parisc.c
                "sys_cacheflush": [
                    "unsigned long addr", "unsigned long bytes", "unsigned int cache",
                ], # arch/parisc/kernel/cache.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "unsigned int mask_1",
                    "unsigned int mask_2", "int dfd", "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use compat
                if abi not in ["common", "32"]:
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "HPPA" and mode == "64":
            return_register = HPPA64.return_register
            args_register = HPPA64.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(hppa_syscall_tbl)
            arch_specific_dic = {
                "sys_fork_wrapper": [], # arch/parisc/kernel/entry.S (fork_like macro)
                "sys_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff",
                ], # arch/parisc/kernel/sys_parisc.c
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long offset",
                ], # arch/parisc/kernel/sys_parisc.c
                "sys_vfork_wrapper": [], # arch/parisc/kernel/entry.S (fork_like macro)
                "sys_clone_wrapper": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int *child_tidptr",
                ], # arch/parisc/kernel/entry.S (fork_like macro, CONFIG_CLONE_BACKWARDS)
                "sys_rt_sigreturn_wrapper": [], # arch/parisc/kernel/entry.S
                "parisc_timerfd_create": [
                    "int clockid", "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_signalfd4": [
                    "int ufd", "sigset_t __user *user_mask", "size_t sizemask", "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_eventfd2": [
                    "unsigned int count", "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_pipe2": [
                    "int __user *fildes", "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_inotify_init1": [
                    "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "parisc_userfaultfd": [
                    "int flags",
                ], # arch/parisc/kernel/sys_parisc.c
                "sys_clone3_wrapper": [
                    "struct clone_args __user *uargs", "size_t size",
                ], # arch/parisc/kernel/entry.S (fork_like macro)
                "parisc_madvise": [
                    "unsigned long start", "size_t len_in", "int behavior",
                ], # arch/parisc/kernel/sys_parisc.c
                "sys_cacheflush": [
                    "unsigned long addr", "unsigned long bytes", "unsigned int cache",
                ], # arch/parisc/kernel/cache.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c

            }
            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry[:4] # dont use compat
                if abi not in ["common", "64"]:
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "OR1K" and mode == "OR1K":
            return_register = OR1K.return_register
            args_register = OR1K.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(or1k_syscall_tbl)
            arch_specific_dic = {
                "sys_rt_sigreturn": [], # arch/openrisc/kernel/entry.S
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp",
                    "void __user *parent_tid", "void __user *child_tid", "int tls",
                ], # arch/openrisc/include/syscalls.h
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t pgoff",
                ], # include/asm-generic/syscalls.h
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "or1k":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "NIOS2" and mode == "NIOS2":
            return_register = NIOS2.return_register
            args_register = NIOS2.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(nios2_syscall_tbl)
            arch_specific_dic = {
                "sys_rt_sigreturn": [], # arch/nios2/kernel/entry.S
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp",
                    "int __user *parent_tidptr", "int __user *child_tidptr", "int tls_val",
                ], # arch/nios2/kernel/entry.S
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t pgoff",
                ], # include/asm-generic/syscalls.h
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "nios2":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "MICROBLAZE" and mode == "MICROBLAZE":
            return_register = MICROBLAZE.return_register
            args_register = MICROBLAZE.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(microblaze_syscall_tbl)
            arch_specific_dic = {
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t pgoff",
                ], # arch/microblaze/kernel/sys_microblaze.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int stack_size",
                    "int __user *parent_tidptr", "int __user *child_tidptr", "unsigned long tls",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS3)
                "sys_rt_sigreturn_wrapper": [], # arch/microblaze/kernel/entry.S
                "sys_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff",
                ], # arch/microblaze/kernel/sys_microblaze.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "common":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "XTENSA" and mode == "XTENSA":
            return_register = XTENSA.return_register
            args_register = XTENSA.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(xtensa_syscall_tbl)
            arch_specific_dic = {
                "xtensa_fadvise64_64": [
                    "int fd", "int advice", "unsigned long long offset", "unsigned long long len",
                ], # arch/xtensa/kernel/syscall.c
                "xtensa_shmat": [
                    "int shmid", "char __user *shmaddr", "int shmflg",
                ], # arch/xtensa/kernel/syscall.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int *child_tidptr",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS)
                "xtensa_rt_sigreturn": [], # arch/xtensa/kernel/signal.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "common":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "CRIS" and mode == "CRIS":
            return_register = CRIS.return_register
            args_register = CRIS.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(cris_syscall_tbl)
            arch_specific_dic = {
                "sys_sigreturn": [], # arch/cris/arch-v10/kernel/signal.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int stack_size",
                    "int __user *parent_tidptr", "int __user *child_tidptr", "unsigned long tls",
                ], # kernel/fork.c (CONFIG_CLONE_BACKWARDS2)
                "sys_bdflush": [
                    "int func", "long data",
                ], # include/linux/syscalls.h
                "sys_sysctl": [
                    "struct __sysctl_args __user *args",
                ], # include/linux/syscalls.h
                "sys_rt_sigreturn": [], # arch/cris/arch-v10/kernel/signal.c
                "sys_mmap2": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "unsigned long pgoff",
                ], # arch/cris/kernel/sys_cris.c
                "sys_lookup_dcookie": [
                    "u64 cookie64", "char __user *buf", "size_t, len",
                ], # fs/dcookies.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "cris":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "LOONGARCH" and mode == "64":
            return_register = LOONGARCH64.return_register
            args_register = LOONGARCH64.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(loongarch_syscall_tbl)
            arch_specific_dic = {
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "int __user *child_tidptr", "unsigned long tls",
                ], # kernel/fork.c
                "sys_rt_sigreturn": [], # arch/loongarch/kernel/signal.c
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t pgoff",
                ], # arch/loongarch/kernel/syscall.c
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "loongarch":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

        elif arch == "ARC":
            if mode in ["32v2", "32"]:
                return_register = ARC.return_register
                args_register = ARC.syscall_parameters
            elif mode in ["32v3"]:
                return_register = ARCv3.return_register
                args_register = ARCv3.syscall_parameters
            elif mode in ["64v3", "64"]:
                return_register = ARC64.return_register
                args_register = ARC64.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(arc_syscall_tbl)
            arch_specific_dic = {
                "sys_rt_sigreturn": [], # arch/arc/kernel/signal.c
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "unsigned long tls", "int *child_tidptr",
                ], # arch/arc/kernel/entry.S (sys_clone_wrapper, CONFIG_CLONE_BACKWARDS)
                "sys_clone3": [
                    "struct clone_args __user *uargs", "size_t size",
                ], # arch/arc/kernel/entry.S (sys_clone3_wrapper)
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t pgoff",
                ], # include/uapi/asm/unistd.h (sys_mmap_pgoff)
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "arc":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

            arch_specific_extra = [
                [244, "cacheflush", [
                    "uint32_t start", "uint32_t sz", "uint32_t flags",
                ]], # arch/arc/mm/cache.c
                [245, "arc_set_tls", [
                    "void* user_tls_data_ptr",
                ]], # arch/arc/kernel/process.c
                [246, "arc_get_tls", []], # arch/arc/kernel/process.c
                [247, "sysfs", [
                    "int option", "unsigned long arg1", "unsigned long arg2",
                ]],
                [248, "arc_usr_cmpxchg", [
                    "int __user *uaddr", "int expected", "int new",
                ]], # arch/arc/kernel/process.c
            ]
            syscall_list += arch_specific_extra

        elif arch == "CSKY" and mode == "CSKY":
            return_register = CSKY.return_register
            args_register = CSKY.syscall_parameters
            sc_def = Syscall.parse_common_syscall_defs()
            tbl = Syscall.parse_syscall_table_defs(csky_syscall_tbl)
            arch_specific_dic = {
                "sys_clone": [
                    "unsigned long clone_flags", "unsigned long newsp", "int __user *parent_tidptr",
                    "int __user *child_tidptr", "unsigned long tls",
                ], # kernel/fork.c
                "sys_rt_sigreturn": [], # arch/csky/kernel/signal.c
                "sys_mmap": [
                    "unsigned long addr", "unsigned long len", "unsigned long prot",
                    "unsigned long flags", "unsigned long fd", "off_t offset",
                ], # arch/csky/kernel/syscall.c
                "sys_fadvise64_64": [
                    "int fd", "int advice", "loff_t offset", "loff_t len",
                ], # arch/csky/include/asm/syscalls.h
                "sys_fanotify_mark": [
                    "int fanotify_fd", "unsigned int flags", "u64 mask", "int fd",
                    "const char  __user *pathname",
                ], # fs/notify/fanotify/fanotify_user.c
            }

            syscall_list = []
            for entry in tbl:
                nr, abi, name, func = entry
                if abi != "csky":
                    continue
                # special case
                if func in arch_specific_dic:
                    syscall_list.append([nr, name, arch_specific_dic[func]])
                    continue
                # common case
                if func == "sys_ni_syscall":
                    continue
                if func not in sc_def:
                    err("Not found: {:s}".format(func))
                    raise
                syscall_list.append([nr, name, sc_def[func]])

            arch_specific_extra = [
                [244, "set_thread_area", [
                    "unsigned long addr",
                ]], # arch/csky/kernel/signal.c
                [245, "cacheflush", [
                    "void __user *addr", "unsigned long len", "int op",
                ]], # arch/csky/include/asm/syscalls.h
            ]
            syscall_list += arch_specific_extra

        else:
            raise

        Table = collections.namedtuple("Table", "arch mode table")
        Entry = collections.namedtuple("Entry", "name ret_regs arg_regs args_full args")
        syscall_table = Table(arch=arch, mode=mode, table={})

        # example:
        #   syscall_table.arch: 'X86'
        #   syscall_table.mode: '64'
        #   syscall_table.table[0].name: 'read'
        #   syscall_table.table[0].ret_regs: ['$rax']
        #   syscall_table.table[0].arg_regs: ['$rdi', '$rsi', ...]
        #   syscall_table.table[0].args_full: ['unsigned int fd', ...]
        #   syscall_table.table[0].args: ['fd', ...]
        for nr, name, args_full in sorted(syscall_list, key=lambda x: x[0]):
            args = [re.split(r" |\*", p)[-1] for p in args_full]
            if (arch, mode) == ("X86", "16"):
                entry = Entry(name, return_register[nr], args_register[nr], args_full, args)
            else:
                entry = Entry(name, [return_register], args_register[:len(args)], args_full, args)
            syscall_table.table[nr] = entry
        return syscall_table


def get_syscall_table(arch=None, mode=None):

    def is_secure():
        scr = get_register("$SCR" if is_arm32() else "$SCR_EL3")
        if scr is None:
            return False
        return (scr & 0b1) == 0

    if arch is None and mode is None :
        if is_x86_64():
            arch, mode = "X86", "64"
        elif is_x86_32():
            if is_emulated32():
                arch, mode = "X86", "Emulated-32"
            else:
                arch, mode = "X86", "Native-32"
        elif is_arm64():
            if is_secure():
                arch, mode = "ARM64", "Secure-World"
            else:
                arch, mode = "ARM64", "ARM"
        elif is_arm32():
            if is_secure():
                arch, mode = "ARM", "Secure-World"
            elif is_emulated32():
                arch, mode = "ARM", "Emulated-32"
            else:
                arch, mode = "ARM", "Native-32"
        else:
            arch = current_arch.arch
            mode = current_arch.mode

    if arch in ["ARM", "ARM64"] and mode == "S":
        mode = "Secure-World"
    if arch in ["X86", "ARM"] and mode == "32":
        mode = "Emulated-32"
    elif arch in ["X86", "ARM"] and mode == "N32":
        mode = "Native-32"

    return Syscall.make_syscall_table(arch, mode)


@register_command
class SyscallArgsCommand(GenericCommand):
    """Get the syscall name and arguments based on the register values in the current state."""
    _cmdline_ = "syscall-args"
    _category_ = "01-a. Debugging Support - Context"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("nr", metavar="SYSCALL_NUM", nargs="?", type=lambda x: int(x, 0),
                        help="syscall number to search.")
    _syntax_ = parser.format_help()

    @staticmethod
    def get_nr():
        # str or list
        syscall_register = current_arch.syscall_register

        # hppa specific. hppa syscall instruction has a delay slot and _NR may be set there.
        if is_hppa32() or is_hppa64():
            next_insn = Disasm.gef_instruction_n(current_arch.pc, 1)
            if next_insn.mnemonic == "ldi" and next_insn.operands[1] == "r20":
                nr = int(next_insn.operands[0], 16)
            else:
                # already set
                nr = get_register(syscall_register)

        # s390x specific. s390x syscall number may be embedded in the instruction.
        elif is_s390x():
            insn = get_insn()
            r = re.search(syscall_register[0], str(insn))
            nr = int(r.group(1), 0)
            if nr == 0:
                syscall_register = syscall_register[1] # use $r1
                nr = get_register(syscall_register)
            else:
                syscall_register = syscall_register[0]

        # normal pattern
        else:
            nr = get_register(syscall_register)

        return syscall_register, nr

    def get_values(self, registers):
        values = []
        for reg in registers:
            if "+" in reg: # `$sp + 0x10`
                _reg, _off = reg.split("+")
                values.append(read_int_from_memory(get_register(_reg) + int(_off, 0)))
            elif is_x86_16() and ":" in reg: # $ds:$dx
                seg, reg = reg.split(":")
                values.append(current_arch.real2phys(seg, reg))
            else:
                values.append(get_register(reg))
        return values

    def print_syscall(self, syscall_table, syscall_register, nr):
        if syscall_table:
            syscall_name = syscall_table.table[nr].name
            ret_regs = syscall_table.table[nr].ret_regs
            arg_regs = syscall_table.table[nr].arg_regs
            args_full = syscall_table.table[nr].args_full
            args = syscall_table.table[nr].args
            arch = syscall_table.arch
            mode = syscall_table.mode
        else:
            syscall_name = None
            ret_regs = [current_arch.return_register]
            arg_regs = current_arch.syscall_parameters
            args_full = None
            args = ["?"] * len(arg_regs)
            arch = current_arch.arch
            mode = current_arch.mode

        # header
        info("Detected syscall (arch:{:s}, mode:{:s})".format(arch, mode))
        if syscall_name and args_full is not None:
            gef_print("    " + Color.colorify("{}({})".format(syscall_name, ", ".join(args_full)), "bold yellow"))
        headers = ["Parameter", "Register", "Value"]
        info(Color.colorify("{:<20} {:<20} {}".format(*headers), Config.get_gef_setting("theme.table_heading")))

        # ret
        for ret in ret_regs:
            gef_print("    {:<20} {:<20} {:<20}".format("RET", ret, "-"))

        # syscall number
        gef_print("    {:<20} {:<20} {:#x}".format("NR", syscall_register, nr))

        # syscall args
        values = self.get_values(arg_regs)
        for name, register, value in zip(args, arg_regs, values):
            line = "    {:<20} {:<20} ".format(name, register)
            if value is not None:
                line += AddressUtil.recursive_dereference_to_string(value)
            gef_print(line)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("wine",))
    def do_invoke(self, args):
        if args.nr is not None:
            syscall_register, nr = "-", args.nr
        else:
            syscall_register, nr = SyscallArgsCommand.get_nr()

        try:
            syscall_table = get_syscall_table()
            if nr not in syscall_table.table:
                warn("There is no system call for {:#x}".format(nr))
                return
        except Exception:
            syscall_table = None

        self.print_syscall(syscall_table, syscall_register, nr)
        return


@register_command
class SyscallSampleCommand(GenericCommand):
    """Show the syscall calling sample for specified architecture."""
    _cmdline_ = "syscall-sample"
    _category_ = "05-c. Syscall - Show Example"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-l", "--list", action="store_true", help="show valid architecture name.")
    parser.add_argument("-a", "--arch", nargs="?", help="specify the architecture name. (default: current_arch)")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        arch_list = []
        queue = Architecture.__subclasses__()
        while queue:
            cls = queue.pop(0)
            arch_list.append(cls)
            queue = cls.__subclasses__() + queue

        if args.list:
            for a in arch_list:
                gef_print(a.__name__)
            return

        if args.arch:
            for a in arch_list:
                if a.__name__ == args.arch:
                    target_arch = a
                    break
            else:
                err("Not found architecture")
                return
        else:
            target_arch = current_arch

        if not hasattr(target_arch, "mprotect_asm"):
            err("Unsupported architecture")
            return

        s = GefUtil.get_source(target_arch.mprotect_asm)
        for line in s.splitlines():
            line = re.sub("^    ", "", line)
            gef_print(line)
        return


@register_command
class CodebaseCommand(GenericCommand):
    """Display various base addresses."""
    _cmdline_ = "codebase"
    _category_ = "02-b. Process Information - Base Address"
    _aliases_ = ["base"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet execution.")
    _syntax_ = parser.format_help()

    def quiet_print(self, msg):
        if self.quiet:
            return
        gef_print(msg)
        return

    def define_section_variable(self, elf, bin_base, section_name):
        sec = elf.get_shdr(section_name)
        if not sec:
            return

        if elf.is_pie():
            addr = sec.sh_addr + bin_base
        else:
            addr = sec.sh_addr

        self.quiet_print(titlify(section_name))
        var_name = section_name.lstrip(".")
        self.quiet_print("${:s} = {:#x}".format(var_name, addr))
        gdb.execute("set ${:s} = {:#x}".format(var_name, addr))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        self.quiet = args.quiet

        # The codebase may be heuristically determined from the memory map.
        bin_base = ProcessMap.get_section_base_address(Path.get_filepath(append_proc_root_prefix=False))
        if bin_base is None:
            bin_base = ProcessMap.get_section_base_address(Path.get_filepath_from_info_proc())
        if bin_base is None:
            if not self.quiet:
                err("Binary base is not found")
            return
        self.quiet_print(titlify("code base"))
        gdb.execute(f"set $codebase = {bin_base:#x}")
        self.quiet_print(f"$codebase = {bin_base:#x}")
        gdb.execute(f"set $binbase = {bin_base:#x}")
        self.quiet_print(f"$binbase = {bin_base:#x}")

        # Any other area should use a section header.
        elf = Elf.get_elf()
        if not elf.is_valid():
            if not self.quiet:
                err("Failed to load an elf")
            return

        self.define_section_variable(elf, bin_base, ".text")
        self.define_section_variable(elf, bin_base, ".rodata")
        self.define_section_variable(elf, bin_base, ".data")
        self.define_section_variable(elf, bin_base, ".bss")
        return


@register_command
class HeapbaseCommand(GenericCommand):
    """Display heap base address."""
    _cmdline_ = "heapbase"
    _category_ = "02-b. Process Information - Base Address"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet execution.")
    _syntax_ = parser.format_help()

    @staticmethod
    def heap_base():
        if Cache.cached_heap_base:
            return Cache.cached_heap_base

        # fast path
        # The value of mp_->sbrk_base is correct in x86 or x64.
        # However, for architectures that have TLS in the bss area (such as ARM or ARM64),
        # the start position of the heap seems to shift by the amount of the area used as the TLS variable.
        # This method should not be used on ARM or ARM64, as there seems to be no way to predetermine the TLS size.
        if is_x86():
            try:
                # symbol and type are defined
                Cache.cached_heap_base = AddressUtil.parse_address("mp_->sbrk_base")
                return Cache.cached_heap_base
            except gdb.error:
                pass

        # slow path
        # If glibc has tcache, there is tcache_perthread_struct* in TLS.
        if get_libc_version() >= (2, 26) and current_arch.tls_supported:
            main_arena_ptr = GlibcHeap.search_for_main_arena_from_tls()

            if main_arena_ptr:
                # get first_chunk (=tcache_perthread_struct*)
                first_chunk_p = None
                if is_x86() or is_sparc64() or is_alpha() or is_mips32() or is_mips64() or is_mipsn32() or \
                   is_nios2() or is_microblaze() or is_arc32() or is_ppc32() or is_ppc64() or \
                   is_hppa32() or is_sh4():
                    first_chunk_p = main_arena_ptr - current_arch.ptrsize * 2
                elif is_arm32() or is_arm64() or is_riscv32() or is_riscv64() or \
                   is_loongarch64() or is_or1k() or is_s390x():
                    first_chunk_p = main_arena_ptr + current_arch.ptrsize

                if first_chunk_p:
                    first_chunk = read_int_from_memory(first_chunk_p)

                    # get heap_base
                    if is_x86_32() or is_riscv32() or is_ppc32():
                        first_chunk_offset = 0x10
                    else:
                        first_chunk_offset = current_arch.ptrsize * 2
                    heap_base = first_chunk - first_chunk_offset

                    # save cache
                    Cache.cached_heap_base = heap_base
                    return Cache.cached_heap_base

        # fall through
        Cache.cached_heap_base = ProcessMap.get_section_base_address("[heap]")
        return Cache.cached_heap_base

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        heap = HeapbaseCommand.heap_base()
        if heap is None:
            err("Heap is not found")
            return

        if not args.quiet:
            gef_print(titlify("Heap base"))
        gdb.execute(f"set $heapbase = {heap}")
        if args.quiet:
            return
        gef_print(f"$heapbase = {heap:#x}")
        return


@register_command
class LibcCommand(GenericCommand):
    """Display libc base address."""
    _cmdline_ = "libc"
    _category_ = "02-b. Process Information - Base Address"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet execution.")
    _syntax_ = parser.format_help()

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.add_setting("assume_version", "()", "The default libc version")
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        Cache.reset_gef_caches(all=True) # get_process_maps may be caching old information

        libc_targets = ("libc-2.", "libc.so.6", "libuClibc-")

        libc = ProcessMap.get_section_base_address_by_list(libc_targets)
        if libc is None:
            err("libc is not found")
            return

        if not args.quiet:
            gef_print(titlify("libc info"))
        gdb.execute(f"set $libc = {libc}")
        if args.quiet:
            return
        gef_print(f"$libc = {libc:#x}")

        libc = ProcessMap.process_lookup_path(libc_targets)
        real_libc_path = None

        if is_container_attach():
            real_libc_path = Path.append_proc_root(libc.path)
            if not os.path.exists(real_libc_path):
                return
            data = open(real_libc_path, "rb").read()

        elif is_remote_debug():
            if is_qemu_user():
                data = None
                for maps in ProcessMap.get_process_maps(outer=True):
                    if os.path.basename(maps.path) != os.path.basename(libc.path):
                        continue
                    if maps.size != libc.size:
                        continue
                    real_libc_path = maps.path
                    data = open(real_libc_path, "rb").read()
                    break
            else:
                data = Path.read_remote_file(libc.path)
            if not data:
                return
        else:
            if not os.path.exists(libc.path):
                return
            data = open(libc.path, "rb").read()

        gef_print("path:\t{:s}{:s}".format(libc.path, " (remote)" if is_remote_debug() else ""))
        if real_libc_path:
            gef_print("path:\t{:s} (real)".format(real_libc_path))
        gef_print("sha512:\t{:s}".format(hashlib.sha512(data).hexdigest()))
        gef_print("sha256:\t{:s}".format(hashlib.sha256(data).hexdigest()))
        gef_print("sha1:\t{:s}".format(hashlib.sha1(data).hexdigest()))
        gef_print("md5:\t{:s}".format(hashlib.md5(data).hexdigest()))

        pos = re.search(b"(GNU C Library|uClibc-ng release) [\x20-\x7e]*", data)
        if pos:
            gef_print("ver:\t{:s}".format(String.bytes2str(pos.group(0))))
        return


@register_command
class LdCommand(GenericCommand):
    """Display ld base address."""
    _cmdline_ = "ld"
    _category_ = "02-b. Process Information - Base Address"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet execution.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        Cache.reset_gef_caches(all=True) # get_process_maps may be caching old information

        ld_targets = ("ld-2.", "ld-linux-", "ld-linux.", "ld64-uClibc-", "ld-uClibc-")

        ld = ProcessMap.get_section_base_address_by_list(ld_targets)
        if ld is None:
            err("ld is not found")
            return

        if not args.quiet:
            gef_print(titlify("ld info"))
        gdb.execute(f"set $ld = {ld}")
        if args.quiet:
            return
        gef_print(f"$ld = {ld:#x}")

        ld = ProcessMap.process_lookup_path(ld_targets)
        real_ld_path = None

        if is_container_attach():
            real_ld_path = Path.append_proc_root(ld.path)
            if not os.path.exists(real_ld_path):
                return
            data = open(real_ld_path, "rb").read()

        elif is_remote_debug():
            if is_qemu_user():
                data = None
                for maps in ProcessMap.get_process_maps(outer=True):
                    if os.path.basename(maps.path) != os.path.basename(ld.path):
                        continue
                    if maps.size != ld.size:
                        continue
                    real_ld_path = maps.path
                    data = open(real_ld_path, "rb").read()
                    break
            else:
                data = Path.read_remote_file(ld.path)
            if not data:
                return
        else:
            if not os.path.exists(ld.path):
                return
            data = open(ld.path, "rb").read()

        gef_print("path:\t{:s}{:s}".format(ld.path, " (remote)" if is_remote_debug() else ""))
        if real_ld_path:
            gef_print("path:\t{:s} (real)".format(real_ld_path))
        gef_print("sha512:\t{:s}".format(hashlib.sha512(data).hexdigest()))
        gef_print("sha256:\t{:s}".format(hashlib.sha256(data).hexdigest()))
        gef_print("sha1:\t{:s}".format(hashlib.sha1(data).hexdigest()))
        gef_print("md5:\t{:s}".format(hashlib.md5(data).hexdigest()))

        pos = re.search(b"ld.so [\x20-\x7e]+ version [\x20-\x7e]*", data)
        if pos:
            gef_print("ver:\t{:s}".format(String.bytes2str(pos.group(0))))
        return


@register_command
class MagicCommand(GenericCommand):
    """Display useful userland addresses and offsets."""
    _cmdline_ = "magic"
    _category_ = "02-g. Process Information - Symbol"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--fj", action="store_true", help="print _IO_xxx_jumps functions")
    parser.add_argument("filter", metavar="FILTER", nargs="*", help="filter string.")
    _syntax_ = parser.format_help()

    def should_be_print(self, sym):
        if not self.filter:
            return True

        for filt in self.filter:
            if filt in sym:
                return True
        return False

    def resolve_and_print(self, sym, base):
        if not self.should_be_print(sym):
            return

        width = AddressUtil.get_format_address_width()
        try:
            addr = int(gdb.parse_and_eval(f"&{sym}"))
            addr = ProcessMap.lookup_address(addr)
            perm = addr.section.permission
            if is_ascii_string(addr.value):
                val = read_cstring_from_memory(addr.value)
                gef_print("{:45s} {!s} [{!s}] (+{:#010x}){:s}{:s}".format(
                    sym, addr, perm, addr.value - base, RIGHT_ARROW, val,
                ))
            else:
                val = ProcessMap.lookup_address(read_int_from_memory(addr.value))
                val_sym = Symbol.get_symbol_string(val.value)
                gef_print("{:45s} {!s} [{!s}] (+{:#010x}){:s}{:s}{:s}".format(
                    sym, addr, perm, addr.value - base, RIGHT_ARROW, val.long_fmt(), val_sym,
                ))
        except Exception:
            gef_print("{:45s} {:>{:d}s}".format(sym, "Not found", width))
        return

    def resolve_and_print_fj(self, sym, base):
        self.resolve_and_print(sym, base)

        if not self.should_be_print(sym):
            return

        if not self.print_file_jumps:
            return

        try:
            vtable = int(gdb.parse_and_eval(f"&{sym}"))
        except Exception:
            return

        gdb.execute("dereference {:#x} 22 --no-pager".format(vtable))
        return

    def magic(self):
        codebase = ProcessMap.get_section_base_address(Path.get_filepath(append_proc_root_prefix=False))
        libc = ProcessMap.get_section_base_address_by_list(("libc-2.", "libc.so.6"))
        ld = ProcessMap.get_section_base_address_by_list(("ld-2.", "ld-linux-", "ld-linux.so.2"))
        if libc is None or ld is None:
            gef_print("libc/ld not found")
            return

        gef_print(titlify("Legend"))
        fmt = "{:45s} {:{:d}s} {:5s} (+{:10s}){:s}{:{:d}s}"
        width = AddressUtil.get_format_address_width()
        legend = ["symbol", "addr", width, "perm", "offset", RIGHT_ARROW, "val", width]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        gef_print(titlify("Heap"))
        self.resolve_and_print("main_arena", libc)
        self.resolve_and_print("mp_", libc)
        self.resolve_and_print("__malloc_hook", libc)
        self.resolve_and_print("__free_hook", libc)
        self.resolve_and_print("__realloc_hook", libc)
        self.resolve_and_print("__memalign_hook", libc)
        self.resolve_and_print("__after_morecore_hook", libc)
        self.resolve_and_print("_dl_open_hook", libc)
        self.resolve_and_print("global_max_fast", libc)
        self.resolve_and_print("malloc", libc)
        self.resolve_and_print("free", libc)
        self.resolve_and_print("calloc", libc)
        self.resolve_and_print("realloc", libc)
        gef_print(titlify("I/O"))
        self.resolve_and_print("*stdin", libc)
        self.resolve_and_print("*stdout", libc)
        self.resolve_and_print("*stderr", libc)
        self.resolve_and_print("_IO_list_all", libc)
        if get_libc_version() < (2, 38):
            self.resolve_and_print_fj("_IO_file_jumps", libc)
            self.resolve_and_print_fj("_IO_file_jumps_mmap", libc)
            self.resolve_and_print_fj("_IO_file_jumps_maybe_mmap", libc)
            self.resolve_and_print_fj("_IO_wfile_jumps", libc)
            self.resolve_and_print_fj("_IO_wfile_jumps_mmap", libc)
            self.resolve_and_print_fj("_IO_wfile_jumps_maybe_mmap", libc)
            self.resolve_and_print_fj("_IO_old_file_jumps", libc)
            self.resolve_and_print_fj("_IO_mem_jumps", libc)
            self.resolve_and_print_fj("_IO_wmem_jumps", libc)
            self.resolve_and_print_fj("_IO_str_jumps", libc)
            self.resolve_and_print_fj("_IO_strn_jumps", libc)
            self.resolve_and_print_fj("_IO_str_chk_jumps", libc)
            self.resolve_and_print_fj("_IO_wstr_jumps", libc)
            self.resolve_and_print_fj("_IO_wstrn_jumps", libc)
            self.resolve_and_print_fj("_IO_streambuf_jumps", libc)
            self.resolve_and_print_fj("_IO_proc_jumps", libc)
            self.resolve_and_print_fj("_IO_old_proc_jumps", libc)
            self.resolve_and_print_fj("_IO_helper_jumps", libc)
            self.resolve_and_print_fj("_IO_cookie_jumps", libc)
            self.resolve_and_print_fj("_IO_obstack_jumps", libc)
        else:
            self.resolve_and_print_fj("__io_vtables[IO_STR_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_WSTR_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_FILE_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_FILE_JUMPS_MMAP]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_FILE_JUMPS_MAYBE_MMAP]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_WFILE_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_WFILE_JUMPS_MMAP]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_WFILE_JUMPS_MAYBE_MMAP]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_COOKIE_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_PROC_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_MEM_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_WMEM_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_PRINTF_BUFFER_AS_FILE_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_WPRINTF_BUFFER_AS_FILE_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_OLD_FILE_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_OLD_PROC_JUMPS]", libc)
            self.resolve_and_print_fj("__io_vtables[IO_OLD_COOKIED_JUMPS]", libc)
        self.resolve_and_print("open", libc)
        self.resolve_and_print("read", libc)
        self.resolve_and_print("write", libc)
        self.resolve_and_print("dup", libc)
        self.resolve_and_print("dup2", libc)
        self.resolve_and_print("dup3", libc)
        self.resolve_and_print("puts", libc)
        self.resolve_and_print("gets", libc)
        self.resolve_and_print("fputs", libc)
        self.resolve_and_print("fgets", libc)
        self.resolve_and_print("printf", libc)
        self.resolve_and_print("fprintf", libc)
        self.resolve_and_print("dprintf", libc)
        self.resolve_and_print("sprintf", libc)
        self.resolve_and_print("snprintf", libc)
        self.resolve_and_print("__printf_chk", libc)
        self.resolve_and_print("__fprintf_chk", libc)
        self.resolve_and_print("__dprintf_chk", libc)
        self.resolve_and_print("__sprintf_chk", libc)
        self.resolve_and_print("__snprintf_chk", libc)
        self.resolve_and_print("__printf_function_table", libc)
        self.resolve_and_print("__printf_arginfo_table", libc)
        self.resolve_and_print("scanf", libc)
        self.resolve_and_print("fscanf", libc)
        self.resolve_and_print("sscanf", libc)
        gef_print(titlify("Process"))
        self.resolve_and_print("system", libc)
        self.resolve_and_print("do_system", libc)
        self.resolve_and_print("execve", libc)
        self.resolve_and_print("setcontext", libc)
        self.resolve_and_print("__libc_start_main", libc)
        self.resolve_and_print("syscall", libc)
        self.resolve_and_print("ptrace", libc)
        self.resolve_and_print("prctl", libc)
        gef_print(titlify("Memory"))
        self.resolve_and_print("mmap", libc)
        self.resolve_and_print("munmap", libc)
        self.resolve_and_print("mremap", libc)
        self.resolve_and_print("mprotect", libc)
        gef_print(titlify("Stack"))
        self.resolve_and_print("__libc_argv", libc)
        self.resolve_and_print("__environ", libc)
        gef_print(titlify("Destructor"))
        self.resolve_and_print("_rtld_global->_dl_rtld_lock_recursive", ld)
        self.resolve_and_print("_rtld_global->_dl_rtld_unlock_recursive", ld)
        self.resolve_and_print("error_print_progname", libc)
        gef_print(titlify("Unwind"))
        self.resolve_and_print("'DW.ref.__gxx_personality_v0'", codebase)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("wine", "kgdb"))
    def do_invoke(self, args):
        self.print_file_jumps = args.fj
        self.filter = args.filter

        if is_qemu_system() or is_vmware():
            info("Redirect to kmagic")
            gdb.execute("kmagic {:s}".format(" ".join(args.filter)))
            return

        self.magic()
        return


@register_command
class KernelMagicCommand(GenericCommand):
    """Display useful kernel addresses and offsets."""
    _cmdline_ = "kmagic"
    _category_ = "08-b. Qemu-system Cooperation - Linux Basic"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("filter", metavar="FILTER", nargs="*", help="filter string.")
    _syntax_ = parser.format_help()

    def should_be_print(self, sym):
        if not self.filter:
            return True

        for filt in self.filter:
            if filt in sym:
                return True
        return False

    def resolve_and_print_kernel(self, sym, base, maps, external_func=None, to_string=False):
        def get_permission(addr, maps):
            for vaddr, size, perm in maps:
                if vaddr <= addr and addr < vaddr + size:
                    return perm
            return "???"

        if not self.should_be_print(sym):
            return

        width = AddressUtil.get_format_address_width()
        if external_func:
            addr = external_func()
            if addr is None:
                gef_print("{:42s} {:>{:d}s}".format(sym, "Not found", width))
                return
        else:
            if isinstance(sym, str):
                addr = Symbol.get_ksymaddr(sym)
                if addr is None:
                    gef_print("{:42s} {:>{:d}s}".format(sym, "Not found", width))
                    return
            elif isinstance(sym, list):
                for s in sym:
                    addr = Symbol.get_ksymaddr(s)
                    if addr:
                        sym = s
                        break
                else:
                    sym = sym[0]
                    gef_print("{:42s} {:>{:d}s}".format(sym, "Not found", width))
                    return

        if not is_valid_addr(addr):
            gef_print("{:42s} {:#0{:d}x} [---]              {:s}Inaccessible".format(
                sym, addr, width, RIGHT_ARROW,
            ))
            return

        perm = get_permission(addr, maps)
        if base is None:
            val = read_int_from_memory(addr)
            gef_print("{:42s} {:#0{:d}x} [{:3s}]              {:s}{:#0{:d}x}".format(
                sym, addr, width, perm, RIGHT_ARROW, val, width,
            ))
        elif to_string:
            val = read_cstring_from_memory(addr) or "???"
            gef_print("{:42s} {:#0{:d}x} [{:3s}] (+{:#010x}){:s}{:s}".format(
                sym, addr, width, perm, addr - base, RIGHT_ARROW, val,
            ))
        else:
            val = read_int_from_memory(addr)
            gef_print("{:42s} {:#0{:d}x} [{:3s}] (+{:#010x}){:s}{:#0{:d}x}".format(
                sym, addr, width, perm, addr - base, RIGHT_ARROW, val, width,
            ))
        return

    def magic_kernel(self):
        info("Wait for memory scan")
        kversion = Kernel.kernel_version()

        kinfo = Kernel.get_kernel_base()
        maps = kinfo.maps
        text_base = kinfo.text_base
        text_size = kinfo.text_size
        if maps is None or text_base is None or text_size is None:
            return
        gef_print("{:42s} {:#x} ({:#x} bytes)".format("kernel_base", text_base, text_size))

        gef_print(titlify("Legend"))
        fmt = "{:42s} {:{:d}s} {:5s} (+{:10s}){:s}{:{:d}s}"
        width = AddressUtil.get_format_address_width()
        legend = ["symbol", "addr", width, "perm", "offset", RIGHT_ARROW, "val", width]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        gef_print(titlify("Credential"))
        self.resolve_and_print_kernel("commit_creds", text_base, maps)
        self.resolve_and_print_kernel("prepare_kernel_cred", text_base, maps)
        self.resolve_and_print_kernel("init_cred", text_base, maps, KernelAddressHeuristicFinder.get_init_cred)
        self.resolve_and_print_kernel(["sys_setuid", "__sys_setuid"], text_base, maps)
        self.resolve_and_print_kernel("init_task", text_base, maps, KernelAddressHeuristicFinder.get_init_task)
        gef_print(titlify("Usermode helper"))
        self.resolve_and_print_kernel("call_usermodehelper", text_base, maps)
        self.resolve_and_print_kernel("run_cmd", text_base, maps)
        self.resolve_and_print_kernel("modprobe_path", text_base, maps, KernelAddressHeuristicFinder.get_modprobe_path, to_string=True)
        self.resolve_and_print_kernel("orderly_poweroff", text_base, maps)
        self.resolve_and_print_kernel("poweroff_cmd", text_base, maps, KernelAddressHeuristicFinder.get_poweroff_cmd, to_string=True)
        self.resolve_and_print_kernel("core_pattern", text_base, maps, KernelAddressHeuristicFinder.get_core_pattern, to_string=True)
        gef_print(titlify("ROP finalizer"))
        if is_x86_64():
            self.resolve_and_print_kernel("swapgs_restore_regs_and_return_to_usermode", text_base, maps)
        self.resolve_and_print_kernel("msleep", text_base, maps)
        gef_print(titlify("Memory protection modifier"))
        if is_x86():
            self.resolve_and_print_kernel("native_write_cr0", text_base, maps)
            self.resolve_and_print_kernel("native_write_cr4", text_base, maps)
        self.resolve_and_print_kernel("set_memory_rw", text_base, maps)
        self.resolve_and_print_kernel("set_memory_x", text_base, maps)
        gef_print(titlify("Memory patcher"))
        if is_x86():
            self.resolve_and_print_kernel("text_poke", text_base, maps)
        self.resolve_and_print_kernel("memcpy", text_base, maps)
        if is_x86():
            self.resolve_and_print_kernel(["_copy_to_user", "copy_to_user"], text_base, maps)
            self.resolve_and_print_kernel(["_copy_from_user", "copy_from_user"], text_base, maps)
        elif is_arm32():
            self.resolve_and_print_kernel(["arm_copy_to_user", "__copy_to_user"], text_base, maps)
            self.resolve_and_print_kernel(["arm_copy_from_user", "__copy_from_user"], text_base, maps)
        elif is_arm64():
            self.resolve_and_print_kernel("__arch_copy_to_user", text_base, maps)
            self.resolve_and_print_kernel("__arch_copy_from_user", text_base, maps)
        gef_print(titlify("Memory remapper"))
        self.resolve_and_print_kernel(["ioremap", "__ioremap", "ioremap_cache"], text_base, maps)
        self.resolve_and_print_kernel(["iounmap", "__iounmap"], text_base, maps)
        if is_x86():
            gef_print(titlify("Automatically called function pointer"))
            self.resolve_and_print_kernel("kvm_clock", text_base, maps)
            self.resolve_and_print_kernel("clocksource_tsc", text_base, maps, KernelAddressHeuristicFinder.get_clocksource_tsc)
        gef_print(titlify("Function pointer table"))
        self.resolve_and_print_kernel("capability_hooks", text_base, maps, KernelAddressHeuristicFinder.get_capability_hooks)
        self.resolve_and_print_kernel("n_tty_ops", text_base, maps, KernelAddressHeuristicFinder.get_n_tty_ops)
        gef_print(titlify("Function pointer table array"))
        self.resolve_and_print_kernel("tty_ldiscs", text_base, maps, KernelAddressHeuristicFinder.get_tty_ldiscs)
        gef_print(titlify("Allocator"))
        self.resolve_and_print_kernel("__kmalloc", text_base, maps)
        self.resolve_and_print_kernel(["kzalloc", "kzalloc.constprop.0"], text_base, maps)
        self.resolve_and_print_kernel("kfree", text_base, maps)
        self.resolve_and_print_kernel(["kzfree", "kfree_sensitive"], text_base, maps)
        self.resolve_and_print_kernel("slab_caches", text_base, maps, KernelAddressHeuristicFinder.get_slab_caches)
        gef_print(titlify("Dynamic resolver"))
        self.resolve_and_print_kernel("kallsyms_lookup_name", text_base, maps)
        if is_x86_64():
            if kversion >= "3.16":
                gef_print(titlify("vDSO"))
                self.resolve_and_print_kernel("vdso_image_64", text_base, maps, KernelAddressHeuristicFinder.get_vdso_image_64)
                self.resolve_and_print_kernel("vdso_image_32", text_base, maps, KernelAddressHeuristicFinder.get_vdso_image_32)
                self.resolve_and_print_kernel("vdso_image_x32", text_base, maps, KernelAddressHeuristicFinder.get_vdso_image_x32)
        elif is_x86_32():
            if kversion >= "3.16":
                gef_print(titlify("vDSO"))
                self.resolve_and_print_kernel("vdso_image_32", text_base, maps, KernelAddressHeuristicFinder.get_vdso_image_32)
        elif is_arm64():
            if kversion >= "5.8":
                gef_print(titlify("vDSO"))
                self.resolve_and_print_kernel("vdso_info", text_base, maps, KernelAddressHeuristicFinder.get_vdso_info)
                self.resolve_and_print_kernel("vdso_start", text_base, maps, KernelAddressHeuristicFinder.get_vdso_start)
                self.resolve_and_print_kernel("vdso32_start", text_base, maps, KernelAddressHeuristicFinder.get_vdso32_start)
            elif kversion >= "5.3":
                gef_print(titlify("vDSO"))
                self.resolve_and_print_kernel("vdso_lookup", text_base, maps, KernelAddressHeuristicFinder.get_vdso_lookup)
                self.resolve_and_print_kernel("vdso_start", text_base, maps, KernelAddressHeuristicFinder.get_vdso_start)
                self.resolve_and_print_kernel("vdso32_start", text_base, maps, KernelAddressHeuristicFinder.get_vdso32_start)
            elif kversion >= "3.7":
                gef_print(titlify("vDSO"))
                self.resolve_and_print_kernel("vdso_start", text_base, maps, KernelAddressHeuristicFinder.get_vdso_start)
        elif is_arm32():
            if kversion >= "4.1":
                gef_print(titlify("vDSO"))
                self.resolve_and_print_kernel("vdso_start", text_base, maps, KernelAddressHeuristicFinder.get_vdso_start)
        gef_print(titlify("Others"))
        self.resolve_and_print_kernel(["do_fchmodat", "sys_fchmodat"], text_base, maps)
        self.resolve_and_print_kernel("mmap_min_addr", text_base, maps, KernelAddressHeuristicFinder.get_mmap_min_addr)
        self.resolve_and_print_kernel("__per_cpu_offset", text_base, maps, KernelAddressHeuristicFinder.get_per_cpu_offset)
        if is_x86():
            gef_print(titlify("Descriptor Table"))
            self.resolve_and_print_kernel("IDT base (fixed address?)", None, maps, KernelAddressHeuristicFinder.get_idt_base)
            self.resolve_and_print_kernel("GDT base (fixed address?)", None, maps, KernelAddressHeuristicFinder.get_gdt_base)
            self.resolve_and_print_kernel("LDT base (fixed address?)", None, maps, KernelAddressHeuristicFinder.get_ldt_base)
            self.resolve_and_print_kernel("TSS base (fixed address?)", None, maps, KernelAddressHeuristicFinder.get_tss_base)
        if is_x86_64():
            gef_print(titlify("Memory base"))
            self.resolve_and_print_kernel("PAGE_OFFSET (physmem direct map)", None, maps, KernelAddressHeuristicFinder.get_page_offset)
            self.resolve_and_print_kernel("VMALLOC_START", None, maps, KernelAddressHeuristicFinder.get_vmalloc_start)
            self.resolve_and_print_kernel("VMEMMAP_START (struct page[])", None, maps, KernelAddressHeuristicFinder.get_vmemmap)
            self.resolve_and_print_kernel("phys_base (for page<->phys)", text_base, maps, KernelAddressHeuristicFinder.get_phys_base)
        if is_x86_32() or is_arm32():
            gef_print(titlify("Memory base"))
            self.resolve_and_print_kernel("mem_map (struct page[])", None, maps, KernelAddressHeuristicFinder.get_mem_map)
        if is_x86_32():
            self.resolve_and_print_kernel("mem_section", None, maps, KernelAddressHeuristicFinder.get_mem_section)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.filter = args.filter
        self.magic_kernel()
        return


@register_command
class OneGadgetCommand(GenericCommand):
    """Invoke `one_gadget`."""
    _cmdline_ = "onegadget"
    _category_ = "07-b. External Command - Exploit Development"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_gdb_target_local
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        libc = ProcessMap.process_lookup_path(("libc-2.", "libc.so.6"))
        if libc is None:
            err("libc is not found")
            return

        try:
            one_gadget = GefUtil.which("one_gadget")
            gef_print(titlify(f"{one_gadget} '{libc.path}' -l 1"))
            os.system(f"{one_gadget} '{libc.path}' -l 1")
        except Exception:
            err("Missing `one_gadget`, install with: `gem install one_gadget`.")
        return


@register_command
class SeccompCommand(GenericCommand):
    """Invoke `seccomp-tools`."""
    _cmdline_ = "seccomp"
    _category_ = "07-b. External Command - Exploit Development"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_gdb_target_local
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        path = Path.get_filepath()
        try:
            seccomp = GefUtil.which("seccomp-tools")
            gef_print(titlify(f"{seccomp} dump '{path}'"))
            os.system(f"{seccomp} dump '{path}'")
        except Exception:
            err("Missing `seccomp-tools`, install with: `gem install seccomp-tools`.")
        return


@register_command
class SysregCommand(GenericCommand):
    """Pretty-print system registers (not general parpose) from `info register`."""
    _cmdline_ = "sysreg"
    _category_ = "04-a. Register - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("filter", metavar="FILTER", nargs="*", help="filter string.")
    parser.add_argument("--exact", action="store_true", help="use exact match.")
    _syntax_ = parser.format_help()

    def get_non_generic_regs(self):
        res = gdb.execute("info registers", to_string=True)
        res = res.strip()
        regs = {}
        for line in res.splitlines():
            m = re.match(r"(\S+)\s*(0x\S+)\s+(0x\S+|\[.+\])", line)
            if not m:
                continue
            regname, regvalue = m.group(1), m.group(2)
            if self.filter:
                if self.exact:
                    if not any(f.lower() == regname.lower() for f in self.filter):
                        continue
                else:
                    if not any(f.lower() in regname.lower() for f in self.filter):
                        continue
            regs[regname] = int(regvalue, 16)
        regs = list(filter(lambda x: "$" + x[0] not in current_arch.all_registers, sorted(regs.items())))
        return regs # [[regname, regvalue], ...]

    def print_sysreg_compact(self):
        regs = self.get_non_generic_regs()
        if regs:
            gef_print(titlify("System registers"))
        else:
            gef_print("Not found non generic regs")
            return
        COLUMN = 3
        length = len(regs)
        length_of_each_bank = (length + COLUMN - 1) // COLUMN
        for i in range(length_of_each_bank):
            out = []
            for j in range(COLUMN):
                if len(regs) > i + j * length_of_each_bank:
                    if is_32bit():
                        msg = "{:16s} = {:#18x}".format(*regs[i + j * length_of_each_bank])
                    else:
                        msg = "{:25s} = {:#18x}".format(*regs[i + j * length_of_each_bank])
                    if regs[i + j * length_of_each_bank][1] > 0:
                        msg = Color.boldify(msg)
                    out.append(msg)
                else:
                    out.append("")
            gef_print("  |  ".join(out))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("kgdb",))
    def do_invoke(self, args):
        self.filter = args.filter
        self.exact = args.exact
        self.print_sysreg_compact()
        return


@register_command
class MmxSetCommand(GenericCommand):
    """Simply set the value to mm register."""
    _cmdline_ = "mmxset"
    _category_ = "04-b. Register - Modify"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("reg_and_value", metavar="REG=VALUE", help="MMX register and value to set.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $mm0=0x1122334455667788".format(_cmdline_)

    _note_ = "Disable `-enable-kvm` option for qemu-system."

    def execute_movq_mm(self, value, reg):
        REG_CODE = {
            "$mm0": b"\x0f\x6f\x00", # movq  mm0, qword ptr [rax]
            "$mm1": b"\x0f\x6f\x08", # movq  mm1, qword ptr [rax]
            "$mm2": b"\x0f\x6f\x10", # movq  mm2, qword ptr [rax]
            "$mm3": b"\x0f\x6f\x08", # movq  mm3, qword ptr [rax]
            "$mm4": b"\x0f\x6f\x20", # movq  mm4, qword ptr [rax]
            "$mm5": b"\x0f\x6f\x28", # movq  mm5, qword ptr [rax]
            "$mm6": b"\x0f\x6f\x30", # movq  mm6, qword ptr [rax]
            "$mm7": b"\x0f\x6f\x38", # movq  mm7, qword ptr [rax]
        }
        codes = [REG_CODE[reg] + p64(value)] # movq mm0, [rax]; db value

        if is_x86_64():
            regs = {"$rax": current_arch.pc + 5} # points to value
        else:
            regs = {"$eax": current_arch.pc + 5} # points to value

        ExecAsm(codes, regs=regs).exec_code()
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr", "kgdb"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    @only_if_kvm_disabled
    def do_invoke(self, args):
        # arg parse
        try:
            reg, value = args.reg_and_value.split("=")
            value = int(value, 0)
        except ValueError:
            self.usage()
            return

        # check register is valid or not
        if reg not in ["$mm{:d}".format(i) for i in range(8)]:
            err("Invalid register name")
            return

        # modify
        self.execute_movq_mm(value, reg)
        return


@register_command
class MmxCommand(GenericCommand):
    """Display MMX registers."""
    _cmdline_ = "mmx"
    _category_ = "04-a. Register - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    def print_mmx(self):
        gef_print(titlify("MMX Register (from fpu register)"))
        regs = []

        for i in range(8):
            regname = "$st{:d}".format(i)
            result = gdb.execute(f"info registers $st{i}", to_string=True)
            r = re.findall(r"\(raw (0x[0-9a-f]+)\)", result)
            if r:
                reg = int(r[0], 16) & 0xffffffffffffffff
                regs.append(reg)

        fstat = get_register("$fstat")
        top_of_stack = (fstat >> 11) & 0b111
        regs = regs[-top_of_stack:] + regs[:-top_of_stack] # need rotate. because mmx0 != st(0)

        fmt = "{:5s}: {:s}"
        legend = ["Name", "64-bit hex"]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
        red = lambda x: Color.colorify("{:4s}".format(x), "bold red")
        for i in range(len(regs)):
            regname = "$mm{:d}".format(i)
            reghex = ""
            for j in range(8):
                c = (regs[i] >> (8 * j)) & 0xff
                reghex += chr(c) if 0x20 <= c < 0x7f else "."
            gef_print("{:s} : {:#018x}  |  {:s}  |".format(red(regname), regs[i], reghex))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("kgdb",))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        self.print_mmx()
        return


@register_command
class XmmSetCommand(GenericCommand):
    """Simply set the value to xmm or ymm register."""
    _cmdline_ = "xmmset"
    _category_ = "04-b. Register - Modify"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("reg_and_value", metavar="REG=VALUE", help="XMM/YMM register and value to set.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} $ymm0=0x11223344556677889900aabbccddeeff9876543210".format(_cmdline_)

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr", "kgdb"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        # arg parse
        try:
            reg, value = args.reg_and_value.split("=")
            value = int(value, 0)
        except Exception:
            self.usage()
            return

        # check register is valid or not
        try:
            gdb.execute(f"info registers {reg}", to_string=True)
        except Exception:
            err("Invalid register name")
            return

        # modify
        if "$xmm" in reg:
            for i in range(2):
                v = (value >> (64 * i)) & ((1 << 64) - 1)
                gdb.execute(f"set {reg}.v2_int64[{i}]={v:#x}", to_string=True)
        elif "$ymm" in reg:
            for i in range(4):
                v = (value >> (64 * i)) & ((1 << 64) - 1)
                gdb.execute(f"set {reg}.v4_int64[{i}]={v:#x}", to_string=True)
        else:
            err("Unsupported")
        return


@register_command
class SseCommand(GenericCommand):
    """Display SSE registers."""
    _cmdline_ = "sse"
    _category_ = "04-a. Register - View"
    _aliases_ = ["xmm"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="also display bit information of mxcsr registers.")
    _syntax_ = parser.format_help()

    def print_sse(self):
        gef_print(titlify("SSE Data Register"))

        # xmm0-15
        regs = []
        for i in range(16 if is_x86_64() else 8):
            result = gdb.execute(f"info registers $xmm{i}", to_string=True)
            r = re.findall(r"uint128 = (0x[0-9a-f]+)", result)
            if r:
                reg = int(r[0], 16)
                regs.append(reg)
        fmt = "{:7s}: {:s}"
        legend = ["Name", "128-bit hex"]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
        red = lambda x: Color.colorify("{:4s}".format(x), "bold red")
        for i in range(len(regs)):
            if i == 8:
                gef_print("* xmm8-15 are introduced by AVX")
            reghex = ""
            for j in range(16):
                c = (regs[i] >> (8 * j)) & 0xff
                reghex += chr(c) if 0x20 <= c < 0x7f else "."
            regname = "$xmm{:<2d}".format(i)
            gef_print("{:s} : {:#034x}  |  {:s}  |".format(red(regname), regs[i], reghex))
        return

    def print_sse_other(self):
        # mxcsr
        gef_print(titlify("MXCSR (MXCSR Control and Status Register)"))
        bit_info = [
            [15, "FZ", "Flush To Zero"],
            [[13, 14], "RC", "Rounding Control", "00: Round To Nearest, 01: Round Negative, 10: Round Positive, 11: Round To Zero"],
            [12, "PM", "Precision Exception Mask"],
            [11, "UM", "Underflow Exception Mask"],
            [10, "OM", "Overflow Exception Mask"],
            [9, "ZM", "Zero Divide Exception Mask"],
            [8, "DM", "Denormalized Opernad Exception Mask"],
            [7, "IM", "Invalid Operation Exception Mask"],
            [6, "DAZ", "Use as 0.0 if input data is denormalized"],
            [5, "PE", "Precision Exception"],
            [4, "UE", "Underflow Exception"],
            [3, "OE", "Overflow Exception"],
            [2, "ZE", "Zero Divide Exception"],
            [1, "DE", "Denormalized Operand Exception"],
            [0, "IE", "Invalid Operation Exception"],
        ]
        reg = int(gdb.execute("info registers $mxcsr", to_string=True).split()[1], 16)
        BitInfo("$mxcsr", 32, bit_info).print(reg)
        return

    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("kgdb",))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, argv):
        if "-h" in argv:
            self.usage()
            return

        self.print_sse()
        if "-v" in argv:
            self.print_sse_other()
        else:
            info("for $mxcsr flags description, use `-v`")
        return


@register_command
class AvxCommand(GenericCommand):
    """Display AVX registers."""
    _cmdline_ = "avx"
    _category_ = "04-a. Register - View"
    _aliases_ = ["ymm"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    def print_avx(self):
        regs = []
        for i in range(16 if is_x86_64() else 8):
            try:
                result = gdb.execute(f"info registers $ymm{i}", to_string=True)
            except Exception:
                continue
            result = result.replace("\n", "")
            r = re.findall(r"v2_int128 = \{.*?\[0x0\] = (0x[0-9a-f]+),.*?\[0x1\] = (0x[0-9a-f]+).*?\}", result)
            if r:
                reg = (int(r[0][1], 16) << 128) + int(r[0][0], 16)
                regs.append(reg)
        if regs:
            gef_print(titlify("AVX Register"))
            fmt = "{:7s}: {:s}"
            legend = ["Name", "256-bit hex"]
            gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
            red = lambda x: Color.colorify("{:4s}".format(x), "bold red")
            for i in range(len(regs)):
                regname = "$ymm{:<2d}".format(i)
                reghex = ""
                for j in range(32):
                    c = (regs[i] >> (8 * j)) & 0xff
                    reghex += chr(c) if 0x20 <= c < 0x7f else "."
                gef_print("{:s} : {:#066x}  |  {:s}  |".format(red(regname), regs[i], reghex))
        else:
            err("Not found avx registers")
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("kgdb",))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        self.print_avx()
        return


@register_command
class FpuCommand(GenericCommand):
    """Display fpu registers (x86/x64:x87-fpu, ARM/ARM64:vfp-d16)."""
    _cmdline_ = "fpu"
    _category_ = "04-a. Register - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="also display bit information of fpu control registers.")
    _syntax_ = parser.format_help()

    def f2u(self, a):
        u = lambda a: struct.unpack("<I", a)[0]
        pf = lambda a: struct.pack("<f", a)
        return u(pf(a))

    def u2f(self, a):
        p = lambda a: struct.pack("<I", a & 0xffffffff)
        uf = lambda a: struct.unpack("<f", a)[0]
        return uf(p(a))

    def d2u(self, a):
        uQ = lambda a: struct.unpack("<Q", a)[0]
        pd = lambda a: struct.pack("<d", a)
        return uQ(pd(a))

    def u2d(self, a):
        pQ = lambda a: struct.pack("<Q", a & 0xffffffffffffffff)
        ud = lambda a: struct.unpack("<d", a)[0]
        return ud(pQ(a))

    def d2u80(self, a):
        value = ctypes.c_longdouble(a)
        BYTES = ctypes.POINTER(ctypes.c_byte * 10)
        ptr = ctypes.cast(ctypes.addressof(value), BYTES)
        x = ["{:02x}".format(int(x) & 0xff) for x in ptr[0][::-1]]
        return int("".join(x), 16)

    def print_fpu_arm(self):
        red = lambda x: Color.colorify("{:4s}".format(x), "bold red")

        # s0-s31, d0-d31, q0-q15
        gef_print(titlify("FPU/NEON Data Register"))
        fmt = "{:4s}: {:15s} {:10s} | {:4s}: {:28s} {:18s} | {:4s}: {:34s}"
        legend = ["Name", "Value", "32-bit hex", "Name", "Value", "64-bit hex", "Name", "128-bit hex"]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
        for i in range(32):
            regname1 = "$s{:d}".format(i)
            regname2 = "$d{:d}".format(i)
            regname3 = "$q{:d}".format(i)
            if is_32bit():
                reg1 = self.f2u(float(gdb.execute("p {}".format(regname1), to_string=True).split()[2]))
                reg2 = int(gdb.execute("p {}.u64".format(regname2), to_string=True).split()[2], 16)
                try:
                    reg3h = int(gdb.execute("p {}.u64[0]".format(regname3), to_string=True).split()[2], 16)
                    reg3l = int(gdb.execute("p {}.u64[1]".format(regname3), to_string=True).split()[2], 16)
                    reg3 = (reg3h << 64) + reg3l
                except Exception:
                    reg3 = None
            else:
                reg1 = int(gdb.execute("p {}.u".format(regname1), to_string=True).split()[2], 16)
                reg2 = int(gdb.execute("p {}.u".format(regname2), to_string=True).split()[2], 16)
                try:
                    reg3 = int(gdb.execute("p {}.u".format(regname3), to_string=True).split()[2], 16)
                except Exception:
                    reg3 = None

            fmt1 = "{:s}: {:15s} {:<#10x}".format(red(regname1), "{:<+.8e}".format(self.u2f(reg1)), reg1)
            fmt2 = "{:s}: {:28s} {:<#18x}".format(red(regname2), "{:<+.20e}".format(self.u2d(reg2)), reg2)
            if reg3 is None:
                fmt3 = "{:s}: {:s}".format(red(regname3), "Access denied")
            else:
                fmt3 = "{:s}: {:<#34x}".format(red(regname3), reg3)
            gef_print("{:s} | {:s} | {:s}".format(fmt1, fmt2, fmt3))
        return

    def print_fpu_x86(self):
        red = lambda x: Color.colorify("{:4s}".format(x), "bold red")

        # st0-7
        gef_print(titlify("FPU Data Register"))
        fmt = "{:9s} : {:27s}\t{:24s} {:18s} {:10s}"
        legend = ["Name", "Value", "80-bit hex(TWORD/XWORD)", "64-bit hex(QWORD)", "32-bit Hex(DWORD)"]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        fstat = get_register("$fstat")
        top_of_stack = (fstat >> 11) & 0b111
        regs = ["mm{:d}".format(i) for i in range(8)]
        regs = regs[top_of_stack:] + regs[:top_of_stack] # need rotate. because mmx0 != st(0)

        for i in range(8):
            regname = "$st{:d}".format(i)
            result = gdb.execute("info registers {}".format(regname), to_string=True)
            if "invalid" in result:
                r = re.findall(r"\(raw (0x[0-9a-f]+)\)", result)
                u80 = int(r[0], 16)
                u64 = 0xfff8000000000000 # nan
                u32 = 0xffc00000 # nan
                gef_print("{:4s}({:3s}) : {:<27s}\t{:<#24x} {:<#18x} {:<#10x}".format(red(regname), regs[i], "<invalid>", u80, u64, u32))
            else:
                reg = float(result.split()[1])
                u80 = self.d2u80(reg)
                u64 = self.d2u(reg)
                u32 = self.f2u(reg)
                gef_print("{:4s}({:3s}) : {:<+.20e}\t{:<#24x} {:<#18x} {:<#10x}".format(red(regname), regs[i], reg, u80, u64, u32))
        info('XWORD: Real register value; Used at "fstp xword ptr [rax]".')
        info('QWORD: Used at "fst/fstp qword ptr [rax]".')
        info('DWORD: Used at "fst/fstp dword ptr [rax]".')
        return

    def print_fpu_arm_other(self):
        # fpscr
        gef_print(titlify("FPSCR (Floating-Point Status and Control Register)"))
        bit_info = [
            [31, "N", "Negative condition flag"],
            [30, "Z", "Zero condition flag"],
            [29, "C", "Carry condition flag"],
            [28, "V", "Overflow condition flag"],
            [27, "QC", "Cumulative saturation bit"],
            [26, "AHP", "Alternative Half-Precision Control"],
            [25, "DN", "Default NaN mode Control"],
            [24, "FZ", "Flush-to-zero mode Control"],
            [[22, 23], "RMode", "Rounding Control", "00: Round To Nearest, 01: Round Positive, 10: Round Negative, 11: Round To Zero"],
            [[20, 21], "Stride", "", "IMPLEMENTATION DEFINED"],
            [19, "FZ16", "Flush-to-zero mode Control", "When FEAT_FP16 is implemented"],
            [[16, 17, 18], "Len", "", "IMPLEMENTATION DEFINED"],
            [15, "IDE", "Input Denormal floating-point Exception trap enable"],
            [12, "IXE", "Inexact floating-point Exception trap enable"],
            [11, "UFE", "Underflow floating-point Exception trap enable"],
            [10, "OFE", "Overflow floating-point Exception trap enable"],
            [9, "DZE", "Divide by Zero floating-point Exception trap enable"],
            [8, "IOE", "Invalid Operation floating-point Exception trap enable"],
            [7, "IDC", "Input Denormal Cumulative floating-point exception bit"],
            [4, "IXC", "Inexact Cumulative floating-point exception bit"],
            [3, "UFC", "Underflow Cumulative floating-point exception bit"],
            [2, "OFC", "Overflow Cumulative floating-point exception bit"],
            [1, "DZC", "Divide by Zero Cumulative floating-point exception bit"],
            [0, "IOC", "Invalid Operation Cumulative floating-point exception bit"],
        ]
        reg = get_register("$fpscr")
        if reg is not None:
            BitInfo("$fpscr", 32, bit_info).print(reg)
        else:
            warn("Failed to get the value")

        # fpsid
        gef_print(titlify("FPSID (Floating-Point System ID Register)"))
        bit_info = [
            [range(24, 32), "Implementer", "Implementer code"],
            [23, "SW", "Software bit", "Implementation of floating point instructions, 0:HW, 1:SW"],
            [range(16, 23), "Subarchitecture", "Subarchitecture version number"],
            [range(8, 16), "PartNum", "Part number", "IMPLEMENTATION DEFINED"],
            [[4, 5, 6, 7], "Variant", "Variant number", "IMPLEMENTATION DEFINED"],
            [[0, 1, 2, 3], "Revision", "Revisino number", "IMPLEMENTATION DEFINED"],
        ]
        impl = {
            0x00: "Reserved for software use",
            0xc0: "Ampere Computing",
            0x41: "Arm Limited",
            0x42: "Broadcom Corporation",
            0x43: "Cavium Inc.",
            0x44: "Digital Equipment Corporation",
            0x46: "Fujitsu Ltd.",
            0x49: "Infineon Technologies AG",
            0x4d: "Motorola or Freescale Semiconductor Inc.",
            0x4e: "NVIDIA Corporation",
            0x50: "Applied Micro Circuits Corporation",
            0x51: "Qualcomm Inc.",
            0x56: "Marvell International Ltd.",
            0x69: "Intel Corporation",
        }
        reg = get_register("$fpsid")
        if reg is not None:
            BitInfo("$fpsid", 32, bit_info).print(reg)
            gef_print("Implementer code")
            for k, v in impl.items():
                gef_print("  {:#02x}: {:s}".format(k, v))
        else:
            warn("Failed to get the value")

        # fpexc
        gef_print(titlify("FPEXC (Floating-Point Exception Control Register)"))
        bit_info = [
            [31, "EX", "Exception bit"],
            [30, "EN", "Enables access to the Advanced SIMD and floating-point functionality from all Exception levels"],
            [29, "DEX", "Defined synchronous exception on floating-point execution"],
            [28, "FP2V", "FPINST2 instruction valid bit"],
            [27, "VV", "VECITR valid bit"],
            [26, "TFV", "Trapped Fault Valid bit"],
            [[8, 9, 10], "VECITR", "Vector iteration count"],
            [7, "IDF", "Input Denormal trapped exception bit"],
            [4, "IXF", "Inexact trapped exception bit"],
            [3, "UFF", "Underflow trapped exception bit"],
            [2, "OFF", "Overflow trapped exception bit"],
            [1, "DZF", "Divide by Zero trapped exception bit"],
            [0, "IOF", "Invalid Operation trapped exception bit"],
        ]
        reg = get_register("$fpexc")
        if reg is not None:
            BitInfo("$fpexc", 32, bit_info).print(reg)
        else:
            warn("Failed to get the value")
        return

    def print_fpu_arm64_other(self):
        # fpcr
        gef_print(titlify("FPCR (Floating-Point Control Register)"))
        bit_info = [
            [26, "AHP", "Alternative Half-Precision Control"],
            [25, "DN", "Default NaN mode Control"],
            [24, "FZ", "Flush-to-zero mode Control"],
            [[22, 23], "RMode", "Rounding Control", "00: Round To Nearest, 01: Round Positive, 10: Round Negative, 11: Round To Zero"],
            [[20, 21], "Stride", "", "Unused"],
            [19, "FZ16", "Flush-to-zero mode Control", "When FEAT_FP16 is implemented"],
            [[16, 17, 18], "Len", "", "Unused"],
            [15, "IDE", "Input Denormal floating-point Exception trap enable"],
            [12, "IXE", "Inexact floating-point Exception trap enable"],
            [11, "UFE", "Underflow floating-point Exception trap enable"],
            [10, "OFE", "Overflow floating-point Exception trap enable"],
            [9, "DZE", "Divide by Zero floating-point Exception trap enable"],
            [8, "IOE", "Invalid Operation floating-point Exception trap enable"],
        ]
        reg = get_register("$fpcr")
        if reg is not None:
            BitInfo("$fpcr", 32, bit_info).print(reg)

        # fpsr
        gef_print(titlify("FPCR (Floating-Point Status Register)"))
        bit_info = [
            [31, "N", "", "Unused, see $cpsr"],
            [30, "Z", "", "Unused, see $cpsr"],
            [29, "C", "", "Unused, see $cpsr"],
            [28, "V", "", "Unused, see $cpsr"],
            [27, "QC", "Cumulative saturation bit"],
            [7, "IDC", "Input Denormal Cumulative floating-point exception bit"],
            [4, "IXC", "Inexact Cumulative floating-point exception bit"],
            [3, "UFC", "Underflow Cumulative floating-point exception bit"],
            [2, "OFC", "Overflow Cumulative floating-point exception bit"],
            [1, "DZC", "Divide by Zero Cumulative floating-point exception bit"],
            [0, "IOC", "Invalid Operation Cumulative floating-point exception bit"],
        ]
        reg = get_register("$fpsr")
        if reg is not None:
            BitInfo("$fpsr", 32, bit_info).print(reg)
        return

    def print_fpu_x86_other(self):
        # fctrl
        gef_print(titlify("FCTRL (x87 FPU Control Word)"))
        bit_info = [
            [12, "X", "Infinity Control"],
            [[10, 11], "RC", "Rounding Control", "00: Round To Nearest, 01: Round Negative, 10: Round Positive, 11: Round To Zero"],
            [[8, 9], "PC", "Precision Control", "00: Single Precision, 01: Reserved, 10: Double Precision, 11: Double-Extended Precision"],
            [5, "PM", "Precision Exception Mask"],
            [4, "UM", "Underflow Exception Mask"],
            [3, "OM", "Overflow Exception Mask"],
            [2, "ZM", "Zero Divide Exception Mask"],
            [1, "DM", "Denormalized Opernd Exception Mask"],
            [0, "IM", "Invalid Operation Exception Mask"],
        ]
        reg = get_register("$fctrl")
        BitInfo("$fctrl", 16, bit_info).print(reg)

        # fstat
        gef_print(titlify("FSTAT (x87 FPU Status Word)"))
        bit_info = [
            [15, "B", "FPU Busy"],
            [14, "C3", "Condition Code"],
            [[11, 12, 13], "TOP", "Top of Stack Pointer"],
            [10, "C2", "Condition Code"],
            [9, "C1", "Condition Code"],
            [8, "C0", "Condition Code"],
            [7, "ES", "Exception Summary Status"],
            [6, "SF", "Stack Fault"],
            [5, "PE", "Precision Exception"],
            [4, "UE", "Underflow Exception"],
            [3, "OE", "Overflow Exception"],
            [2, "ZE", "Zero Divide Exception"],
            [1, "DE", "Denormalized Operand Exception"],
            [0, "IE", "Invalid Operation Exception"],
        ]
        reg = get_register("$fstat")
        BitInfo("$fstat", 16, bit_info).print(reg)

        # ftag
        gef_print(titlify("FTAG (x87 FPU Tag Word)"))
        bit_info = [
            [[14, 15], "TAG(7)", "Reg7 Tag", "00: Valid, 01: Zero, 10: Invalid/Nan/Inf/Denormal, 11: Blank"],
            [[12, 13], "TAG(6)", "Reg6 Tag", "00: Valid, 01: Zero, 10: Invalid/Nan/Inf/Denormal, 11: Blank"],
            [[10, 11], "TAG(5)", "Reg5 Tag", "00: Valid, 01: Zero, 10: Invalid/Nan/Inf/Denormal, 11: Blank"],
            [[8, 9], "TAG(4)", "Reg4 Tag", "00: Valid, 01: Zero, 10: Invalid/Nan/Inf/Denormal, 11: Blank"],
            [[6, 7], "TAG(3)", "Reg3 Tag", "00: Valid, 01: Zero, 10: Invalid/Nan/Inf/Denormal, 11: Blank"],
            [[4, 5], "TAG(2)", "Reg2 Tag", "00: Valid, 01: Zero, 10: Invalid/Nan/Inf/Denormal, 11: Blank"],
            [[2, 3], "TAG(1)", "Reg1 Tag", "00: Valid, 01: Zero, 10: Invalid/Nan/Inf/Denormal, 11: Blank"],
            [[0, 1], "TAG(0)", "Reg0 Tag", "00: Valid, 01: Zero, 10: Invalid/Nan/Inf/Denormal, 11: Blank"],
        ]
        reg = get_register("$ftag")
        BitInfo("$ftag", 16, bit_info).print(reg)

        # $fiseg, $fioff
        gef_print(titlify("FCS:FIP (x87 FPU Last Instruction Pointer)"))
        reg = get_register("$fiseg")
        BitInfo("$fiseg(FCS)", 16).print(reg)
        reg = get_register("$fioff")
        BitInfo("$fioff(FIP)", 32).print(reg)

        # $foseg, $fooff
        gef_print(titlify("FDS:FDP (x87 FPU Last Data(Operand) Pointer)"))
        reg = get_register("$foseg")
        BitInfo("$foseg(FDS)", 16).print(reg)
        reg = get_register("$fooff")
        BitInfo("$fooff(FDP)", 32).print(reg)

        # $fop
        gef_print(titlify("FOP (x87 FPU Last Instruction Opcode)"))
        reg = get_register("$fop")
        BitInfo("$fop", 11).print(reg)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("kgdb",))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    def do_invoke(self, args):
        if is_x86():
            self.print_fpu_x86()
        elif is_arm32() or is_arm64():
            self.print_fpu_arm()

        if args.verbose:
            if is_x86():
                self.print_fpu_x86_other()
            elif is_arm32():
                self.print_fpu_arm_other()
            elif is_arm64():
                self.print_fpu_arm64_other()
        else:
            info("for fpu other register's flags description, use `-v`")
        return


@register_command
class ErrnoCommand(GenericCommand):
    """Convert errno (or argument) to its string representation."""
    _cmdline_ = "errno"
    _category_ = "02-d. Process Information - Trivial Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("errno", metavar="ERRNO", nargs="?", type=lambda x: int(x, 0),
                        help="show specific errno definitions.")
    parser.add_argument("--all", action="store_true", help="show all errno definitions.")
    _syntax_ = parser.format_help()

    # /usr/include/asm-generic/errno.h
    ERRNO_DICT = {
        0   : ["-",               "No error"],
        1   : ["EPERM",           "Operation not permitted"],
        2   : ["ENOENT",          "No such file or directory"],
        3   : ["ESRCH",           "No such process"],
        4   : ["EINTR",           "Interrupted system call"],
        5   : ["EIO",             "I/O error"],
        6   : ["ENXIO",           "No such device or address"],
        7   : ["E2BIG",           "Argument list too long"],
        8   : ["ENOEXEC",         "Exec format error"],
        9   : ["EBADF",           "Bad file number"],
        10  : ["ECHILD",          "No child processes"],
        11  : ["EAGAIN",          "Try again"],
        12  : ["ENOMEM",          "Out of memory"],
        13  : ["EACCES",          "Permission denied"],
        14  : ["EFAULT",          "Bad address"],
        15  : ["ENOTBLK",         "Block device required"],
        16  : ["EBUSY",           "Device or resource busy"],
        17  : ["EEXIST",          "File exists"],
        18  : ["EXDEV",           "Cross-device link"],
        19  : ["ENODEV",          "No such device"],
        20  : ["ENOTDIR",         "Not a directory"],
        21  : ["EISDIR",          "Is a directory"],
        22  : ["EINVAL",          "Invalid argument"],
        23  : ["ENFILE",          "File table overflow"],
        24  : ["EMFILE",          "Too many open files"],
        25  : ["ENOTTY",          "Not a typewriter"],
        26  : ["ETXTBSY",         "Text file busy"],
        27  : ["EFBIG",           "File too large"],
        28  : ["ENOSPC",          "No space left on device"],
        29  : ["ESPIPE",          "Illegal seek"],
        30  : ["EROFS",           "Read-only file system"],
        31  : ["EMLINK",          "Too many links"],
        32  : ["EPIPE",           "Broken pipe"],
        33  : ["EDOM",            "Math argument out of domain of func"],
        34  : ["ERANGE",          "Math result not representable"],
        35  : ["EDEADLK",         "Resource deadlock would occur"],
        36  : ["ENAMETOOLONG",    "File name too long"],
        37  : ["ENOLCK",          "No record locks available"],
        38  : ["ENOSYS",          "Invalid system call number"],
        39  : ["ENOTEMPTY",       "Directory not empty"],
        40  : ["ELOOP",           "Too many symbolic links encountered"],
        42  : ["ENOMSG",          "No message of desired type"],
        43  : ["EIDRM",           "Identifier removed"],
        44  : ["ECHRNG",          "Channel number out of range"],
        45  : ["EL2NSYNC",        "Level 2 not synchronized"],
        46  : ["EL3HLT",          "Level 3 halted"],
        47  : ["EL3RST",          "Level 3 reset"],
        48  : ["ELNRNG",          "Link number out of range"],
        49  : ["EUNATCH",         "Protocol driver not attached"],
        50  : ["ENOCSI",          "No CSI structure available"],
        51  : ["EL2HLT",          "Level 2 halted"],
        52  : ["EBADE",           "Invalid exchange"],
        53  : ["EBADR",           "Invalid request descriptor"],
        54  : ["EXFULL",          "Exchange full"],
        55  : ["ENOANO",          "No anode"],
        56  : ["EBADRQC",         "Invalid request code"],
        57  : ["EBADSLT",         "Invalid slot"],
        59  : ["EBFONT",          "Bad font file format"],
        60  : ["ENOSTR",          "Device not a stream"],
        61  : ["ENODATA",         "No data available"],
        62  : ["ETIME",           "Timer expired"],
        63  : ["ENOSR",           "Out of streams resources"],
        64  : ["ENONET",          "Machine is not on the network"],
        65  : ["ENOPKG",          "Package not installed"],
        66  : ["EREMOTE",         "Object is remote"],
        67  : ["ENOLINK",         "Link has been severed"],
        68  : ["EADV",            "Advertise error"],
        69  : ["ESRMNT",          "Srmount error"],
        70  : ["ECOMM",           "Communication error on send"],
        71  : ["EPROTO",          "Protocol error"],
        72  : ["EMULTIHOP",       "Multihop attempted"],
        73  : ["EDOTDOT",         "RFS specific error"],
        74  : ["EBADMSG",         "Not a data message"],
        75  : ["EOVERFLOW",       "Value too large for defined data type"],
        76  : ["ENOTUNIQ",        "Name not unique on network"],
        77  : ["EBADFD",          "File descriptor in bad state"],
        78  : ["EREMCHG",         "Remote address changed"],
        79  : ["ELIBACC",         "Can not access a needed shared library"],
        80  : ["ELIBBAD",         "Accessing a corrupted shared library"],
        81  : ["ELIBSCN",         ".lib section in a.out corrupted"],
        82  : ["ELIBMAX",         "Attempting to link in too many shared libraries"],
        83  : ["ELIBEXEC",        "Cannot exec a shared library directly"],
        84  : ["EILSEQ",          "Illegal byte sequence"],
        85  : ["ERESTART",        "Interrupted system call should be restarted"],
        86  : ["ESTRPIPE",        "Streams pipe error"],
        87  : ["EUSERS",          "Too many users"],
        88  : ["ENOTSOCK",        "Socket operation on non-socket"],
        89  : ["EDESTADDRREQ",    "Destination address required"],
        90  : ["EMSGSIZE",        "Message too long"],
        91  : ["EPROTOTYPE",      "Protocol wrong type for socket"],
        92  : ["ENOPROTOOPT",     "Protocol not available"],
        93  : ["EPROTONOSUPPORT", "Protocol not supported"],
        94  : ["ESOCKTNOSUPPORT", "Socket type not supported"],
        95  : ["EOPNOTSUPP",      "Operation not supported on transport endpoint"],
        96  : ["EPFNOSUPPORT",    "Protocol family not supported"],
        97  : ["EAFNOSUPPORT",    "Address family not supported by protocol"],
        98  : ["EADDRINUSE",      "Address already in use"],
        99  : ["EADDRNOTAVAIL",   "Cannot assign requested address"],
        100 : ["ENETDOWN",        "Network is down"],
        101 : ["ENETUNREACH",     "Network is unreachable"],
        102 : ["ENETRESET",       "Network dropped connection because of reset"],
        103 : ["ECONNABORTED",    "Software caused connection abort"],
        104 : ["ECONNRESET",      "Connection reset by peer"],
        105 : ["ENOBUFS",         "No buffer space available"],
        106 : ["EISCONN",         "Transport endpoint is already connected"],
        107 : ["ENOTCONN",        "Transport endpoint is not connected"],
        108 : ["ESHUTDOWN",       "Cannot send after transport endpoint shutdown"],
        109 : ["ETOOMANYREFS",    "Too many references: cannot splice"],
        110 : ["ETIMEDOUT",       "Connection timed out"],
        111 : ["ECONNREFUSED",    "Connection refused"],
        112 : ["EHOSTDOWN",       "Host is down"],
        113 : ["EHOSTUNREACH",    "No route to host"],
        114 : ["EALREADY",        "Operation already in progress"],
        115 : ["EINPROGRESS",     "Operation now in progress"],
        116 : ["ESTALE",          "Stale file handle"],
        117 : ["EUCLEAN",         "Structure needs cleaning"],
        118 : ["ENOTNAM",         "Not a XENIX named type file"],
        119 : ["ENAVAIL",         "No XENIX semaphores available"],
        120 : ["EISNAM",          "Is a named type file"],
        121 : ["EREMOTEIO",       "Remote I/O error"],
        122 : ["EDQUOT",          "Quota exceeded"],
        123 : ["ENOMEDIUM",       "No medium found"],
        124 : ["EMEDIUMTYPE",     "Wrong medium type"],
        125 : ["ECANCELED",       "Operation Canceled"],
        126 : ["ENOKEY",          "Required key not available"],
        127 : ["EKEYEXPIRED",     "Key has expired"],
        128 : ["EKEYREVOKED",     "Key has been revoked"],
        129 : ["EKEYREJECTED",    "Key was rejected by service"],
        130 : ["EOWNERDEAD",      "Owner died"],
        131 : ["ENOTRECOVERABLE", "State not recoverable"],
        132 : ["ERFKILL",         "Operation not possible due to RF-kill"],
        133 : ["EHWPOISON",       "Memory page has hardware error"],
    }

    @parse_args
    @exclude_specific_gdb_mode(mode=("wine",))
    def do_invoke(self, args):
        if args.all:
            for val, es in sorted(self.ERRNO_DICT.items()):
                gef_print('{:3d} (={:#4x}): {:<15s}: "{:s}"'.format(val, val, es[0], es[1]))
            return

        if args.errno is None:
            if not is_alive():
                warn("No debugging session active")
                return
            try:
                val = AddressUtil.parse_address("*__errno_location()")
            except Exception:
                err("Failed to get *__errno_location()")
                return
        else:
            val = args.errno

        if val > 0xffff:
            if current_arch and current_arch.ptrsize == 4:
                val = struct.unpack("<i", struct.pack("<I", val))[0]
            elif current_arch and current_arch.ptrsize == 8:
                val = struct.unpack("<q", struct.pack("<Q", val))[0]
            elif current_arch is None:
                val = struct.unpack("<q", struct.pack("<Q", val))[0]
            else:
                err("not support this pointer size.")
                return

        if val < 0:
            val = -val

        if val in self.ERRNO_DICT:
            es = self.ERRNO_DICT[val]
            gef_print('{:3d} (={:#4x}): {:<15s}: "{:s}"'.format(val, val, es[0], es[1]))
        else:
            err("Not found value in ERRNO_DICT (1~{:d})".format(len(self.ERRNO_DICT)))
        return


@register_command
class ExtractHeapAddrCommand(GenericCommand):
    """Extract heap address from protected `fd` pointer of single linked-list (introduced from glibc 2.32)."""
    _cmdline_ = "extract-heap-addr"
    _category_ = "06-a. Heap - Glibc"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("value", metavar="VALUE", nargs="?", type=lambda x: int(x, 0),
                       help="the value to extract.")
    group.add_argument("--source", action="store_true",
                       help="shows the source instead of displaying extractedd value.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0x000055500000C7F9".format(_cmdline_)

    def reveal(self, fd):
        # https://smallkirby.hatenablog.com/entry/safeunlinking
        L = fd >> 36
        for i in range(3):
            temp = (fd >> (36 - (i + 1) * 8)) & 0xff
            element = ((L >> 4) ^ temp) & 0xff
            L = (L << 8) + element
        return L << 12

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        if args.source:
            s = GefUtil.get_source(ExtractHeapAddrCommand.reveal)
            gef_print(s)
            return

        ptr = args.value
        extracted_ptr = self.reveal(ptr)
        colored_extracted_ptr = str(ProcessMap.lookup_address(extracted_ptr))
        gef_print("Protected fd pointer: {:#x}".format(ptr))
        gef_print("{:s}Extracted heap address: {:s} (=fd & ~0xfff)".format(RIGHT_ARROW, colored_extracted_ptr))
        return


@register_command
class FindFakeFastCommand(GenericCommand, BufferingOutput):
    """Find candidate fake fast chunks from RW memory."""
    _cmdline_ = "find-fake-fast"
    _category_ = "06-a. Heap - Glibc"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--include-heap", action="store_true", help="heap is also included in the search target.")
    parser.add_argument("--aligned", action="store_true", help="search only aligned chunks.")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address, help="search target size.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def print_result(self, m, pos, size_candidate):
        path = "unknown" if m.path == "" else m.path
        address = ProcessMap.lookup_address(m.page_start + pos)
        self.info("Found at {!s} in {!r} [{!s}]".format(address, path, m.permission))

        if is_32bit():
            res = gdb.execute("x/6xw {:#x}".format(address.value), to_string=True)
        else:
            res = gdb.execute("x/6xg {:#x}".format(address.value), to_string=True)

        flag = []
        if size_candidate & 0b100:
            flag += [Color.colorify("NON_MAIN_ARENA", Config.get_gef_setting("theme.heap_chunk_flag_non_main_arena"))]
        else:
            flag += ["NON_MAIN_ARENA"]

        if size_candidate & 0b10:
            flag += [Color.colorify("IS_MMAPED", Config.get_gef_setting("theme.heap_chunk_flag_is_mmapped"))]
        else:
            flag += ["IS_MMAPED"]

        if size_candidate & 0b1:
            flag += [Color.colorify("PREV_INUSE", Config.get_gef_setting("theme.heap_chunk_flag_prev_inuse"))]
        else:
            flag += ["PREV_INUSED"]

        self.out.append("    [{:s}]".format(" ".join(flag)))
        for line in res.splitlines():
            self.out.append("    {:s}".format(line))
        return

    def find_fake_fast(self, target_size):
        mask = ~0x7 if current_arch.ptrsize == 4 else ~0xf
        target_size &= mask
        vmmap = ProcessMap.get_process_maps()
        unpack = u32 if current_arch.ptrsize == 4 else u64
        for m in vmmap:
            if not (m.permission & Permission.READ) or not (m.permission & Permission.WRITE):
                continue
            if m.path in ["[vvar]", "[vsyscall]", "[vectors]", "[sigpage]"]:
                continue
            if not self.include_heap and m.path.startswith("[heap]"):
                continue
            data = read_memory(m.page_start, m.size)
            # Scanning page-by-page
            for pos in range(0, m.size, gef_getpagesize()):
                # fast check for all zero, because there may be huge mmap-ed memory
                if b"\0" * gef_getpagesize() == data[pos:pos + gef_getpagesize()]:
                    continue
                # this page has some data
                unit = 0x10 if self.aligned else 1
                for posb in range(pos, pos + gef_getpagesize(), unit):
                    size_candidate = data[posb + current_arch.ptrsize:posb + current_arch.ptrsize * 2]
                    if len(size_candidate) != current_arch.ptrsize:
                        break
                    size_candidate = unpack(size_candidate)
                    if (size_candidate & mask) != target_size:
                        continue
                    self.print_result(m, posb, size_candidate)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        if is_64bit():
            MIN_SIZE = 0x20
        else:
            MIN_SIZE = 0x10

        if args.size < MIN_SIZE:
            err("Wrong size")
            return

        self.include_heap = args.include_heap
        self.aligned = args.aligned

        self.out = []
        self.find_fake_fast(args.size)
        self.print_output(args, term=True)
        return


@register_command
class VisualHeapCommand(GenericCommand):
    """Visualize chunks on a heap."""
    _cmdline_ = "visual-heap"
    _category_ = "06-a. Heap - Glibc"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the address interpreted as the beginning of a contiguous chunk. (default: arena.heap_base)")
    parser.add_argument("-a", dest="arena_addr", type=AddressUtil.parse_address,
                        help="the address or number to interpret as an arena. (default: main_arena)")
    parser.add_argument("-c", dest="max_count", type=AddressUtil.parse_address,
                        help="Maximum count to parse. It is used when there is a very large amount of chunks.")
    parser.add_argument("-f", "--full", action="store_true",
                        help="display the same line without omitting.")
    parser.add_argument("-d", "--dark-color", action="store_true",
                        help="use the dark color if chunk is allocated.")
    parser.add_argument("-s", "--safe-linking-decode", action="store_true",
                        help="decode safe-linking encoded pointer if tcache or fastbins.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    color = [
        Color.redify,
        Color.greenify,
        Color.blueify,
        Color.yellowify
    ]
    dark_color = [
        lambda x: Color.colorify(x, "bright_black"),
        lambda x: Color.colorify(x, "graphite"),
    ]

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def generate_visual_chunk(self, arena, chunk, idx):
        unpack = u32 if current_arch.ptrsize == 4 else u64
        data = slicer(chunk.data, current_arch.ptrsize * 2)
        group_line_threshold = 8

        addr = chunk.chunk_base_address
        width = current_arch.ptrsize * 2 + 2
        exceed_top = False
        has_subinfo = False

        out_tmp = []
        # Group rows to display rows with the same value together.
        for blk, blks in itertools.groupby(data):
            repeat_count = len(list(blks))
            d1, d2 = unpack(blk[:current_arch.ptrsize]), unpack(blk[current_arch.ptrsize:])
            dascii = "".join([chr(x) if 0x20 <= x < 0x7f else "." for x in blk])

            fmt = "{:#x}|{:+#08x}|{:+#08x}: {:#0{:d}x} {:#0{:d}x} | {:s} | {:s}"
            if self.full or repeat_count < group_line_threshold:
                # non-collapsed line
                for _ in range(repeat_count):
                    sub_info = arena.make_bins_info(addr)
                    if sub_info:
                        sub_info = "{:s} {:s}".format(LEFT_ARROW, ", ".join(sub_info))
                        has_subinfo = True
                    else:
                        sub_info = ""

                    if self.safe_linking_decode:
                        if chunk.address == addr and ("tcache" in sub_info or "fastbins" in sub_info):
                            d1 = chunk.get_fwd_ptr(True)

                    offset1 = addr - chunk.chunk_base_address
                    offset2 = addr - arena.heap_base
                    out_tmp.append(fmt.format(addr, offset1, offset2, d1, width, d2, width, dascii, sub_info))
                    addr += current_arch.ptrsize * 2

                    if addr > arena.top + current_arch.ptrsize * 4:
                        exceed_top = True
                        break
            else:
                # collapsed line
                sub_info = arena.make_bins_info(addr)
                if sub_info:
                    sub_info = "{:s} {:s}".format(LEFT_ARROW, ", ".join(sub_info))
                    has_subinfo = True
                else:
                    sub_info = ""

                offset1 = addr - chunk.chunk_base_address
                offset2 = addr - arena.heap_base
                out_tmp.append(fmt.format(addr, offset1, offset2, d1, width, d2, width, dascii, sub_info))
                addr += current_arch.ptrsize * 2 * repeat_count
                out_tmp.append("* {:#d} lines, {:#x} bytes".format(repeat_count - 1, (repeat_count - 1) * current_arch.ptrsize * 2))

            if exceed_top:
                break

        # coloring
        if self.use_dark_color and not has_subinfo:
            color_func = self.dark_color[idx % len(self.dark_color)]
        else:
            color_func = self.color[idx % len(self.color)]
        self.out.append("\n".join(map(color_func, out_tmp)))

        # corrupted case
        if exceed_top:
            self.out.append(Color.boldify("..."))
        return

    def generate_visual_heap(self, arena, dump_start, max_count):
        sect = ProcessMap.process_lookup_address(dump_start)
        if sect:
            end = sect.page_end
        else:
            # If qemu-user 8.1 or higher, the `process_lookup_address` to obtain the section list
            # uses `info proc mappings` internally.
            # This is fast, but does not return an accurate list in some cases.
            # For example, sparc64 may not include the heap area.
            # So it detects the end of the page from arena.top.
            end = arena.top + GlibcHeap.GlibcChunk(arena.top, from_base=True).size

        try:
            from tqdm import tqdm
        except ImportError:
            tqdm = None
        if tqdm:
            pbar = tqdm(total=end - dump_start, leave=False)

        addr = dump_start
        i = 0
        while addr < end:
            chunk = GlibcHeap.GlibcChunk(addr + current_arch.ptrsize * 2)
            # corrupt check
            if chunk.size == 0:
                msg = "{} Corrupted (chunk.size == 0)".format(Color.colorify("[!]", "bold red"))
                self.out.append(msg)
                chunk.data = read_memory(addr, arena.top - addr + 0x10)
                self.generate_visual_chunk(arena, chunk, i)
                break
            elif addr != arena.top and addr + chunk.size > arena.top:
                msg = "{} Corrupted (addr + chunk.size > arena.top)".format(Color.colorify("[!]", "bold red"))
                self.out.append(msg)
                chunk.data = read_memory(addr, arena.top - addr + 0x10)
                self.generate_visual_chunk(arena, chunk, i)
                break
            elif addr + chunk.size > end:
                msg = "{} Corrupted (addr + chunk.size > sect.page_end)".format(Color.colorify("[!]", "bold red"))
                self.out.append(msg)
                chunk.data = read_memory(addr, arena.top - addr + 0x10)
                self.generate_visual_chunk(arena, chunk, i)
                break
            # maybe not corrupted
            try:
                chunk.data = read_memory(addr, chunk.size)
            except gdb.MemoryError:
                break
            self.generate_visual_chunk(arena, chunk, i)
            addr += chunk.size
            i += 1

            if tqdm:
                pbar.update(chunk.size)

            if max_count and max_count <= i:
                break

        if tqdm:
            pbar.close()
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        self.full = args.full
        self.use_dark_color = args.dark_color
        self.safe_linking_decode = args.safe_linking_decode

        # parse arena
        arena = GlibcHeap.get_arena(args.arena_addr)

        if arena is None:
            err("No valid arena")
            return

        if arena.heap_base is None or not is_valid_addr(arena.heap_base):
            err("Heap is not initialized")
            return

        if args.location is None:
            dump_start = arena.heap_base
            # specific pattern
            if arena.is_main_arena:
                if (is_x86_32() or is_riscv32() or is_ppc32()) and get_libc_version() >= (2, 26):
                    dump_start += 8
        else:
            dump_start = args.location

        self.out = []
        Cache.reset_gef_caches(all=True)
        arena.reset_bins_info()
        self.generate_visual_heap(arena, dump_start, args.max_count)
        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class DistanceCommand(GenericCommand):
    """Calculate the offset from its base address."""
    _cmdline_ = "distance"
    _category_ = "09-f. Misc - Calculation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("address_a", metavar="ADDRESS_A", type=AddressUtil.parse_address,
                        help="the address to calculate the offset as (A - base_addr_of(A)).")
    parser.add_argument("address_b", metavar="ADDRESS_B", type=AddressUtil.parse_address, nargs="?",
                        help="the address to calculate the offset as abs(A - B).")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        if args.address_b is not None:
            offset = abs(args.address_a - args.address_b)
            gef_print("Offset:  {:#x}".format(offset))
            return

        addr_a = ProcessMap.lookup_address(args.address_a)
        if addr_a.section is None:
            err("Not found the base address")
            return

        if addr_a.section.path:
            base_address = ProcessMap.get_section_base_address(addr_a.section.path)
        else:
            base_address = addr_a.section.page_start

        offset = args.address_a - base_address
        gef_print("Address: {:#x}".format(args.address_a))
        gef_print("Base:    {:#x}".format(base_address))
        gef_print("Offset:  {:#x}".format(offset))
        return


@register_command
class U2dCommand(GenericCommand):
    """Convert type (unsigned long <-> double/float)."""
    _cmdline_ = "u2d"
    _category_ = "09-a. Misc - Conversion"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("value", metavar="VALUE", help="the hex value or double value.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0xdeadbeef\n".format(_cmdline_)
    _example_ += "{:s} 0.12345\n".format(_cmdline_)
    _example_ += "{:s} 1.2345e-1".format(_cmdline_)

    _note_ = "Only ~64bit supported (Unsupported 80bit, 128bit)"

    def f2u(self, x):
        u = lambda a: struct.unpack("<I", a)[0]
        pf = lambda a: struct.pack("<f", a)
        return u(pf(x))

    def u2f(self, x):
        p = lambda a: struct.pack("<I", a & 0xffffffff)
        uf = lambda a: struct.unpack("<f", a)[0]
        return uf(p(x))

    def d2u(self, x):
        uQ = lambda a: struct.unpack("<Q", a)[0]
        pd = lambda a: struct.pack("<d", a)
        return uQ(pd(x))

    def u2d(self, x):
        pQ = lambda a: struct.pack("<Q", a & 0xffffffffffffffff)
        ud = lambda a: struct.unpack("<d", a)[0]
        return ud(pQ(x))

    def convert_from_float(self, n):
        gef_print(titlify("double -> unsigned long long"))
        gef_print(Color.cyanify("double -> ull (reinterpret_cast)"))
        gef_print("  {:.20e} ---> {:#018x}".format(n, self.d2u(n)))
        gef_print(titlify("float -> float"))
        gef_print(Color.cyanify("float -> uint (reinterpret_cast)"))
        gef_print("  {:.20e} ---> {:#010x}".format(n, self.f2u(n)))
        return

    def convert_from_int(self, n):
        n &= 0xffffffffffffffff
        gef_print(titlify("unsigned long long <-> double"))
        gef_print(Color.cyanify("ull -> double (reinterpret_cast)"))
        gef_print("  {:#018x} ---> {:.20e}".format(n, self.u2d(n)))
        gef_print(Color.cyanify("ull -> double -> ull (static_cast)"))
        gef_print("  {:#018x} ---> {:#018x} ---> {:#018x}".format(n, self.d2u(float(n)), int(self.u2d(self.d2u(float(n))))))
        gef_print(Color.cyanify("double -> ull (reinterpret_cast)"))
        try:
            gef_print("  {:#018x} ---> {:#018x}".format(n, int(self.u2d(n))))
        except ValueError:
            gef_print("  {:18s} ---> ???".format("nan"))

        n &= 0xffffffff
        gef_print(titlify("unsigned int <-> float"))
        gef_print(Color.cyanify("uint -> float (reinterpret_cast)"))
        gef_print("  {:#010x} ---> {:.20e}".format(n, self.u2f(n)))
        gef_print(Color.cyanify("uint -> float -> uint (static_cast)"))
        gef_print("  {:#010x} ---> {:#010x} ---> {:#010x}".format(n, self.f2u(float(n)), int(self.u2f(self.f2u(float(n))))))
        gef_print(Color.cyanify("float -> uint (reinterpret_cast)"))
        try:
            gef_print("  {:#010x} ---> {:#010x}".format(n, int(self.u2f(n))))
        except ValueError:
            gef_print("  {:10s} ---> ???".format("nan"))
        return

    @parse_args
    def do_invoke(self, args):
        try:
            if "." in args.value:
                n = float(args.value)
                self.convert_from_float(n)
            else:
                n = int(args.value, 0)
                self.convert_from_int(n)
        except Exception:
            self.usage()
        return


@register_command
class UnsignedCommand(GenericCommand):
    """Convert the negative number to unsigned."""
    _cmdline_ = "unsigned"
    _category_ = "09-a. Misc - Conversion"
    _aliases_ = ["us", "signed"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("value", metavar="VALUE", type=AddressUtil.parse_address,
                        help="the value to convert.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -- -0xa0".format(_cmdline_)

    @parse_args
    def do_invoke(self, args):
        gef_print("input: {:#x}".format(args.value))

        for i in range(4):
            shift = (2 ** i) * 8

            msb_mask = 1 << (shift - 1)
            if (1 << shift) > args.value and args.value & msb_mask == 0:
                value = args.value * -1
            else:
                value = args.value

            mask = (1 << shift) - 1
            unsigned = value & mask
            if i == 0:
                signed = struct.unpack("<b", struct.pack("<B", unsigned))[0]
            elif i == 1:
                signed = struct.unpack("<h", struct.pack("<H", unsigned))[0]
            elif i == 2:
                signed = struct.unpack("<i", struct.pack("<I", unsigned))[0]
            elif i == 3:
                signed = struct.unpack("<q", struct.pack("<Q", unsigned))[0]
            gef_print("{:d} byte unsigned: {:#x} ({:#x})".format(2 ** i, unsigned, signed))
        return


@register_command
class ConvertCommand(GenericCommand):
    """Convert values to various (pack, pack-hex, unpack, tohex, unhex, byteswap, etc.)."""
    _cmdline_ = "convert"
    _category_ = "09-a. Misc - Conversion"
    _aliases_ = ["transform", "trans"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("value", metavar="VALUE", help="the value or string to convert.")
    parser.add_argument("--hex", action="store_true", help="interpret VALUE as hex. invalid character is ignored.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="enable verbose mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0xdeadbeef\n".format(_cmdline_)
    _example_ += '{:s} "\\\\x41\\\\x42\\\\x43\\\\x44" -v\n'.format(_cmdline_)
    _example_ += '{:s} --hex "41 42 43 44" -v'.format(_cmdline_)

    def pack(self, value):
        try:
            value = int(value, 0)
            self.out.append(titlify("pack"))
            self.out.append("pack8:          {}".format(p8(value & 0xff)))
            self.out.append("pack16:         {}".format(p16(value & 0xffff)))
            self.out.append("pack32:         {}".format(p32(value & 0xffffffff)))
            self.out.append("pack64:         {}".format(p64(value & 0xffffffffffffffff)))
            low = value & 0xffffffffffffffff
            high = (value >> 64) & 0xffffffffffffffff
            val128 = p64(low) + p64(high)
            self.out.append("pack128:        {}".format(val128))

            self.out.append(titlify("pack-hex"))
            self.out.append("pack8-hex:      {}".format(p8(value & 0xff).hex()))
            self.out.append("pack16-hex:     {}".format(p16(value & 0xffff).hex()))
            self.out.append("pack32-hex:     {}".format(p32(value & 0xffffffff).hex()))
            self.out.append("pack64-hex:     {}".format(p64(value & 0xffffffffffffffff).hex()))
            self.out.append("pack128-hex:    {}".format(val128.hex()))
        except ValueError:
            pass
        return

    def unpack(self, value):
        try:
            value = codecs.escape_decode(value)[0] + b"\0" * 16
            self.out.append(titlify("unpack"))
            self.out.append("unpack8:        {:#04x}".format(u8(value[:1])))
            self.out.append("unpack16:       {:#06x}".format(u16(value[:2])))
            self.out.append("unpack32:       {:#010x}".format(u32(value[:4])))
            self.out.append("unpack64:       {:#018x}".format(u64(value[:8])))
            low, high = value[:8], value[8:16]
            self.out.append("unpack128:      {:#034x}".format((u64(high) << 64) | u64(low)))
        except binascii.Error:
            pass
        return

    def tohex(self, value):
        try:
            value = codecs.escape_decode(value)[0]
            self.out.append(titlify("tohex"))
            hexed = binascii.hexlify(value)
            self.out.append("tohex:          {}".format(hexed))
            hexed_null = b"00".join(slicer(hexed, 2)) + b"00"
            self.out.append("tohex w/NULL:   {}".format(hexed_null))
        except binascii.Error:
            pass
        return

    def unhex(self, value):
        try:
            if value.startswith("0x"):
                value = binascii.unhexlify(value[2:])
            else:
                value = binascii.unhexlify(value)
            self.out.append(titlify("unhex"))
            self.out.append("unhex:          {}".format(value))
            value_null = b"\x00".join(slicer(value, 1)) + b"\x00"
            self.out.append("unhex w/NULL:   {}".format(value_null))
        except binascii.Error:
            pass
        return

    def byteswap(self, value):
        try:
            value = int(value, 0)
            converted32 = byteswap(value, 4)
            converted64 = byteswap(value, 8)
            self.out.append(titlify("byteswap"))
            self.out.append("byteswap-64:    {:#018x}".format(converted64))
            self.out.append("byteswap-32:    {:#010x}".format(converted32))
        except ValueError:
            pass
        return

    def integer(self, value):
        try:
            value = int(value, 0)
            self.out.append(titlify("integer"))
            self.out.append("hex:            {:#x}".format(value))
            self.out.append("dec:            {:d}".format(value))
            self.out.append("oct:            {:#o}".format(value))
            self.out.append("bin:            {:#b}".format(value))
            out = ""
            x = value
            while x:
                if x & 1:
                    out = "1" + out
                else:
                    out = "0" + out
                if (len(out) + 1) % 5 == 0:
                    out = "_" + out
                x >>= 1
            splitted_value = "0b" + out.lstrip("_")
            self.out.append("bin w/sep:      {:s}".format(splitted_value))
        except ValueError:
            pass
        return

    def signed(self, value):
        pQ = lambda a: struct.pack("<Q", a & 0xffffffffffffffff)
        uq = lambda a: struct.unpack("<q", a)[0]
        p = lambda a: struct.pack("<I", a & 0xffffffff)
        ui = lambda a: struct.unpack("<i", a)[0]
        try:
            value = int(value, 0)
            self.out.append(titlify("signed"))
            self.out.append("u2i-64:         {:#018x}".format(uq(pQ(value))))
            self.out.append("u2i-32:         {:#010x}".format(ui(p(value))))
        except ValueError:
            pass
        return

    def string(self, value):
        try:
            value = codecs.escape_decode(value)[0]
            self.out.append(titlify("string"))
            self.out.append("str:            {}".format(value))
            value_null = b"\x00".join(slicer(value, 1)) + b"\x00"
            self.out.append("str w/NULL:     {}".format(value_null))
        except ValueError:
            pass
        return

    def unhex_xor(self, value):
        try:
            if value.startswith("0x"):
                value = binascii.unhexlify(value[2:])
            else:
                value = binascii.unhexlify(value)
            self.out.append(titlify("unhex - XOR"))
            for i in range(0x100):
                xored = b"".join(bytes([x ^ i]) for x in value)
                if 0x20 <= i < 0x7f:
                    self.out.append("xor-{:02X}({:s}):      {!s}".format(i, chr(i), xored))
                else:
                    self.out.append("xor-{:02X}:         {!s}".format(i, xored))
        except binascii.Error:
            pass
        return

    def unhex_add(self, value):
        try:
            if value.startswith("0x"):
                value = binascii.unhexlify(value[2:])
            else:
                value = binascii.unhexlify(value)
            self.out.append(titlify("unhex - ADD"))
            for i in range(0x100):
                added = b"".join(bytes([(x + i) & 0xff]) for x in value)
                if 0x20 <= i < 0x7f:
                    self.out.append("add-{:02X}({:s}):      {!s}".format(i, chr(i), added))
                else:
                    self.out.append("add-{:02X}:         {!s}".format(i, added))
        except binascii.Error:
            pass
        return

    def unhex_rol_for_each_byte(self, value):
        try:
            if value.startswith("0x"):
                value = binascii.unhexlify(value[2:])
            else:
                value = binascii.unhexlify(value)
            self.out.append(titlify("unhex - ROL (for each byte)"))
            for i in range(9):
                rored = b"".join(bytes([((x << i) | x >> (8 - i)) & 0xff]) for x in value)
                self.out.append("rol-{:02X}:         {!s}".format(i, rored))
        except binascii.Error:
            pass
        return

    def unhex_rol_whole(self, value):
        try:
            if value.startswith("0x"):
                value = binascii.unhexlify(value[2:])
            else:
                value = binascii.unhexlify(value)
            self.out.append(titlify("unhex - ROL (whole)"))
            bits = []
            for v in value:
                for i in range(8):
                    bits.append(str((v >> (7 - i)) & 1))
            for i in range(9):
                rored = bits[i:] + bits[:i]
                rored = [int("".join(x), 2) for x in slicer(rored, 8)]
                rored = bytes(rored)
                self.out.append("rol-{:02X}:         {!s}".format(i, rored))
        except ValueError:
            pass
        return

    def unhex_caesar(self, value):
        try:
            if value.startswith("0x"):
                value = binascii.unhexlify(value[2:])
            else:
                value = binascii.unhexlify(value)
            self.out.append(titlify("unhex - caesar"))
            for i in range(26):
                slided = []
                for x in value:
                    if ord("A") <= x <= ord("Z"):
                        x += i
                        if x > ord("Z"):
                            x -= ord("Z")
                            x += ord("A") - 1
                    elif ord("a") <= x <= ord("z"):
                        x += i
                        if x > ord("z"):
                            x -= ord("z")
                            x += ord("a") - 1
                    slided.append(x)
                self.out.append("caesar-{:02d}:      {}".format(i, bytes(slided)))
        except binascii.Error:
            pass
        return

    def string_xor(self, value):
        try:
            value = codecs.escape_decode(value)[0]
            self.out.append(titlify("str - XOR"))
            for i in range(0x100):
                xored = b"".join(bytes([x ^ i]) for x in value)
                if 0x20 <= i < 0x7f:
                    self.out.append("xor-{:02X}({:s}):      {!s}".format(i, chr(i), xored))
                else:
                    self.out.append("xor-{:02X}:         {!s}".format(i, xored))
        except ValueError:
            pass
        return

    def string_add(self, value):
        try:
            value = codecs.escape_decode(value)[0]
            self.out.append(titlify("str - ADD"))
            for i in range(0x100):
                added = b"".join(bytes([(x + i) & 0xff]) for x in value)
                if 0x20 <= i < 0x7f:
                    self.out.append("add-{:02X}({:s}):      {!s}".format(i, chr(i), added))
                else:
                    self.out.append("add-{:02X}:         {!s}".format(i, added))
        except ValueError:
            pass
        return

    def string_rol_for_each_byte(self, value):
        try:
            value = codecs.escape_decode(value)[0]
            self.out.append(titlify("str - ROL (for each byte)"))
            for i in range(9):
                rored = b"".join(bytes([((x << i) | x >> (8 - i)) & 0xff]) for x in value)
                self.out.append("rol-{:02X}:         {!s}".format(i, rored))
        except ValueError:
            pass
        return

    def string_rol_whole(self, value):
        try:
            value = codecs.escape_decode(value)[0]
            self.out.append(titlify("str - ROL (whole)"))
            bits = []
            for v in value:
                for i in range(8):
                    bits.append(str((v >> (7 - i)) & 1))
            for i in range(9):
                rored = bits[i:] + bits[:i]
                rored = [int("".join(x), 2) for x in slicer(rored, 8)]
                rored = bytes(rored)
                self.out.append("rol-{:02X}:         {!s}".format(i, rored))
        except ValueError:
            pass
        return

    def string_caesar(self, value):
        try:
            value = codecs.escape_decode(value)[0]
            self.out.append(titlify("str - caesar"))
            for i in range(26):
                slided = []
                for x in value:
                    if ord("A") <= x <= ord("Z"):
                        x += i
                        if x > ord("Z"):
                            x -= ord("Z")
                            x += ord("A") - 1
                    elif ord("a") <= x <= ord("z"):
                        x += i
                        if x > ord("z"):
                            x -= ord("z")
                            x += ord("a") - 1
                    slided.append(x)
                self.out.append("caesar-{:02d}:      {}".format(i, bytes(slided)))
        except ValueError:
            pass
        return

    def morse(self, value):
        MORSE_CODE_DICT = {
            b".-"     : b"A",
            b"-..."   : b"B",
            b"-.-."   : b"C",
            b"-.."    : b"D",
            b"."      : b"E",
            b"..-."   : b"F",
            b"--."    : b"G",
            b"...."   : b"H",
            b".."     : b"I",
            b".---"   : b"J",
            b"-.-"    : b"K",
            b".-.."   : b"L",
            b"--"     : b"M",
            b"-."     : b"N",
            b"---"    : b"O",
            b".--."   : b"P",
            b"--.-"   : b"Q",
            b".-."    : b"R",
            b"..."    : b"S",
            b"-"      : b"T",
            b"..-"    : b"U",
            b"...-"   : b"V",
            b".--"    : b"W",
            b"-..-"   : b"X",
            b"-.--"   : b"Y",
            b"--.."   : b"Z",
            b".----"  : b"1",
            b"..---"  : b"2",
            b"...--"  : b"3",
            b"....-"  : b"4",
            b"....."  : b"5",
            b"-...."  : b"6",
            b"--..."  : b"7",
            b"---.."  : b"8",
            b"----."  : b"9",
            b"-----"  : b"0",
            b"--..--" : b",",
            b".-.-.-" : b".",
            b"..--.." : b"?",
            b"-..-."  : b"/",
            b"-....-" : b"-",
            b"-.--."  : b"(",
            b"-.--.-" : b")",
        }
        try:
            encoded = codecs.escape_decode(value)[0]
            decoded = b""
            for elem in encoded.split():
                if elem.replace(b".", b"").replace(b"-", b"") != b"":
                    decoded += elem
                    continue
                decoded += MORSE_CODE_DICT.get(elem, elem)

            if encoded != decoded:
                self.out.append(titlify("str - morse"))
                self.out.append("morse-decode:   {}".format(decoded))
        except ValueError:
            pass
        return

    @parse_args
    def do_invoke(self, args):
        value = args.value

        if args.hex: # "41414141" -> "\x41\x41\x41\x41"
            _value = ""
            for c in args.value.lower():
                if c in "0123456789abcdef":
                    _value += c
            if len(_value) % 2 != 0:
                err("hex value length is odd")
                return
            value = "".join(["\\x" + _value[i:i + 2] for i in range(0, len(_value), 2)])

        self.out = []
        self.pack(value)
        self.unpack(value)
        self.tohex(value)
        self.unhex(value)
        self.byteswap(value)
        self.integer(value)
        self.signed(value)
        self.string(value)

        if args.verbose:
            self.unhex_xor(value)
            self.unhex_add(value)
            self.unhex_rol_for_each_byte(value)
            self.unhex_rol_whole(value)
            self.unhex_caesar(value)
            self.string_xor(value)
            self.string_add(value)
            self.string_rol_for_each_byte(value)
            self.string_rol_whole(value)
            self.string_caesar(value)
            self.morse(value)

        gef_print("\n".join(self.out), less=not args.no_pager)
        return


class KernelAddressHeuristicFinderUtil:
    """A class that has utility for KernelAddressHeuristicFinder."""

    @staticmethod
    def common_addr_gen(res, regexp, skip, skip_msb_check, read_valid):
        for line in res.splitlines():
            m = re.search(regexp, line)
            if not m:
                continue
            v = AddressUtil.align_address(int(m.group(1), 16))
            if not skip_msb_check and not AddressUtil.is_msb_on(v):
                continue
            if read_valid and not is_valid_addr_addr(v): # not is_valid_addr, but is_valid_addr_addr
                continue
            if skip > 0:
                skip -= 1
                continue
            yield v

    @staticmethod
    def x64_x86_any_const(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"(?:# |,)(0x\w{8,})"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x64_x86_mov_reg_const(res, reg=r"\w+", skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"mov\s+" + reg + r"\s*,\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x64_lea_reg_const(res, reg=r"\w+", skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"lea\s+" + reg + r"\s*,\s*\[.*([+-]0x\w+)\]"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x64_x86_cmp_const(res, reg=r"\w+", skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"cmp\s+" + reg + r"\s*,\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x64_byte_ptr(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"BYTE PTR \[.*([+-]0x\w+)\]"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x64_dword_ptr(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"DWORD PTR \[rip\+0x\w+\].*#\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x64_qword_ptr(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"QWORD PTR \[rip\+0x\w+\].*#\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x64_qword_ptr_array_base(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"QWORD PTR \[.*\*8([-+]0x\w+)\]"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x64_qword_ptr_ds(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"QWORD PTR ds:\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x64_qword_ptr_gs(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"QWORD PTR gs:\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x86_dword_ptr_ds(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"DWORD PTR ds:\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x86_dword_ptr_fs(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"DWORD PTR fs:\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x86_noptr_ds(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"ds:\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x86_mov_noptr_ds(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"mov.*ds:\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x86_dword_ptr(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r",\s*DWORD PTR \[.*([+-]0x\w+)\]"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def x86_dword_ptr_array_base(res, skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"DWORD PTR \[.*\*4([+-]0x\w+)\]"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def aarch64_adrp_ldr(res, skip=0, skip_msb_check=False, read_valid=False):
        bases = {}
        for line in res.splitlines():
            m = re.search(r"adrp\s+(\w+),\s*(0x\w+)", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 16)
                bases[reg] = v
                continue
            m = re.search(r"ldr\s+\w+,\s*\[(\w+),\s*#(\d+)\]", line)
            if m:
                srcreg = m.group(1)
                v = int(m.group(2), 0)
                if srcreg in bases:
                    w = AddressUtil.align_address(bases[srcreg] + v)
                    if not skip_msb_check and not AddressUtil.is_msb_on(w):
                        continue
                    if read_valid and not is_valid_addr_addr(w):
                        continue
                    if skip > 0:
                        skip -= 1
                        continue
                    yield w

    @staticmethod
    def aarch64_adrp_add(res, skip=0, skip_msb_check=False, read_valid=False):
        bases = {}
        for line in res.splitlines():
            m = re.search(r"adrp\s+(\w+),\s*(0x\w+)", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 16)
                bases[reg] = v
                continue
            m = re.search(r"add\s+(\w+),\s*(\w+),\s*#(0x\w+)", line)
            if m:
                srcreg = m.group(2)
                v = int(m.group(3), 16)
                if srcreg in bases:
                    w = AddressUtil.align_address(bases[srcreg] + v)
                    if not skip_msb_check and not AddressUtil.is_msb_on(w):
                        continue
                    if read_valid and not is_valid_addr_addr(w):
                        continue
                    if skip > 0:
                        skip -= 1
                        continue
                    yield w

    @staticmethod
    def aarch64_adrp_add_add(res, skip=0, skip_msb_check=False, read_valid=False):
        bases = {}
        add1time = {}
        for line in res.splitlines():
            m = re.search(r"adrp\s+(\w+),\s*(0x\w+)", line)
            if m:
                reg = m.group(1)
                base = int(m.group(2), 16)
                bases[reg] = base
                continue
            m = re.search(r"add\s+(\w+),\s*(\w+),\s*#(0x\w+)", line)
            if m:
                dstreg = m.group(1)
                srcreg = m.group(2)
                v = int(m.group(3), 16)
                if srcreg in add1time:
                    w = AddressUtil.align_address(add1time[srcreg] + v)
                    if not skip_msb_check or AddressUtil.is_msb_on(w):
                        if not read_valid or is_valid_addr_addr(w):
                            if skip <= 0:
                                yield w
                            skip -= 1
                if srcreg in bases:
                    add1time[dstreg] = bases[srcreg] + v
                    continue

    @staticmethod
    def aarch64_adrp_add_ldr(res, skip=0, skip_msb_check=False, read_valid=False):
        bases = {}
        add1time = {}
        for line in res.splitlines():
            m = re.search(r"adrp\s+(\w+),\s*(0x\w+)", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 16)
                bases[reg] = v
                continue
            m = re.search(r"add\s+(\w+),\s*(\w+),\s*#(0x\w+)", line)
            if m:
                dstreg = m.group(1)
                srcreg = m.group(2)
                v = int(m.group(3), 16)
                if srcreg in bases:
                    add1time[dstreg] = bases[srcreg] + v
                    continue
            m = re.search(r"ldr\s+\w+,\s*\[(\w+),\s*#(\d+)\]", line)
            if m:
                srcreg = m.group(1)
                v = int(m.group(2), 0)
                if srcreg in add1time:
                    w = AddressUtil.align_address(add1time[srcreg] + v)
                    if not skip_msb_check and not AddressUtil.is_msb_on(w):
                        continue
                    if read_valid and not is_valid_addr_addr(w):
                        continue
                    if skip > 0:
                        skip -= 1
                        continue
                    yield w

    @staticmethod
    def arm32_movw_movt(res, skip=0, skip_msb_check=False, read_valid=False):
        bases = {}
        for line in res.splitlines():
            m = re.search(r"movw\s+(\w+),.+[;@]\s*(0x\w+)", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 16)
                bases[reg] = v
                continue
            m = re.search(r"movt\s+(\w+),.+[;@]\s*(0x\w+)", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 16) << 16
                if reg in bases:
                    w = AddressUtil.align_address(bases[reg] + v)
                    if not skip_msb_check and not AddressUtil.is_msb_on(w):
                        continue
                    if read_valid and not is_valid_addr_addr(w):
                        continue
                    if skip > 0:
                        skip -= 1
                        continue
                    yield w

    @staticmethod
    def arm32_movw_movt_ldr(res, skip=0, skip_msb_check=False, read_valid=False):
        bases = {}
        add1time = {}
        for line in res.splitlines():
            m = re.search(r"movw\s+(\w+),.+[;@]\s*(0x\w+)", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 16)
                bases[reg] = v
                continue
            m = re.search(r"movt\s+(\w+),.+[;@]\s*(0x\w+)", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 16) << 16
                if reg in bases:
                    add1time[reg] = bases[reg] + v
                    continue
            m = re.search(r"ldr\s+\w+,\s*\[(\w+),\s*#(\d+)\]", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 0)
                if reg in add1time:
                    w = AddressUtil.align_address(add1time[reg] + v)
                    if not skip_msb_check and not AddressUtil.is_msb_on(w):
                        continue
                    if read_valid and not is_valid_addr_addr(w):
                        continue
                    if skip > 0:
                        skip -= 1
                        continue
                    yield w

    @staticmethod
    def arm32_movw_movt_add(res, skip=0, skip_msb_check=False, read_valid=False):
        bases = {}
        add1time = {}
        for line in res.splitlines():
            m = re.search(r"movw\s+(\w+),.+[;@]\s*(0x\w+)", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 16)
                bases[reg] = v
                continue
            m = re.search(r"movt\s+(\w+),.+[;@]\s*(0x\w+)", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 16) << 16
                if reg in bases:
                    add1time[reg] = bases[reg] + v
                    continue
            m = re.search(r"add\s+\w+,\s*(\w+),\s*#(\d+)", line)
            if m:
                reg = m.group(1)
                v = int(m.group(2), 0)
                if reg in add1time:
                    w = AddressUtil.align_address(add1time[reg] + v)
                    if not skip_msb_check and not AddressUtil.is_msb_on(w):
                        continue
                    if read_valid and not is_valid_addr_addr(w):
                        continue
                    if skip > 0:
                        skip -= 1
                        continue
                    yield w

    @staticmethod
    def arm32_ldr_reg_const(res, reg=r"\w+", skip=0, skip_msb_check=False, read_valid=False):
        regexp = r"ldr\s+" + reg + r",.*[;@]\s*(0x\w+)"
        return KernelAddressHeuristicFinderUtil.common_addr_gen(res, regexp, skip, skip_msb_check, read_valid)

    @staticmethod
    def arm32_ldr_pc_relative(res, skip=0, read_valid=False):
        for line in res.splitlines():
            m = re.search(r"ldr\s+\w+,\s*\[pc,\s*#(\d+)\]", line)
            if m:
                ofs = AddressUtil.align_address(int(m.group(1), 0))
                pos = AddressUtil.align_address(int(line.split()[0].replace(":", ""), 16))
                v = read_int_from_memory(pos + 4 * 2 + ofs)
                if is_valid_addr(v):
                    if skip <= 0:
                        yield v
                    skip -= 1
                    continue
            m = re.search(r"ldr\s+\w+,\s*\[pc\]", line)
            if m:
                pos = AddressUtil.align_address(int(line.split()[0].replace(":", ""), 16))
                v = read_int_from_memory(pos + 4 * 2)
                if is_valid_addr(v):
                    if read_valid and not is_valid_addr_addr(v):
                        continue
                    if skip <= 0:
                        yield v
                    skip -= 1
                    continue

    @staticmethod
    def arm32_ldr_pc_relative_ldr(res, skip=0, read_valid=False):
        bases = {}
        for line in res.splitlines():
            m = re.search(r"ldr\s+(\w+),\s*\[pc,\s*#(\d+)\]", line)
            if m:
                reg = m.group(1)
                ofs = AddressUtil.align_address(int(m.group(2), 0))
                pos = AddressUtil.align_address(int(line.split()[0].replace(":", ""), 16))
                v = read_int_from_memory(pos + 4 * 2 + ofs)
                bases[reg] = v
                continue
            m = re.search(r"ldr\s+\w+,\s*\[(\w+),\s*#(\d*)\]", line)
            if m:
                reg = m.group(1)
                ofs = AddressUtil.align_address(int(m.group(2), 0))
                if reg in bases:
                    w = AddressUtil.align_address(bases[reg] + ofs)
                    if skip <= 0:
                        yield w
                    skip -= 1
                    continue
            m = re.search(r"ldr\s+\w+,\s*\[(\w+)\]", line)
            if m:
                reg = m.group(1)
                if reg in bases:
                    w = AddressUtil.align_address(bases[reg])
                    if read_valid and not is_valid_addr_addr(w):
                        continue
                    if skip <= 0:
                        yield w
                    skip -= 1
                    continue


class KernelAddressHeuristicFinder:
    """A class that heuristically finds a specific symbol in the kernel."""

    USE_DIRECTLY = True # for debug
    USE_KSYSCTL = True # for debug

    @staticmethod
    @switch_to_intel_syntax
    def get_saved_command_line():
        # Do not use Symbol.get_ksymaddr as this function is used to discover KPTI.
        # This is because Symbol.get_ksymaddr uses a cache.

        kversion = Kernel.kernel_version()

        # plan 1 (available v2.6.28 or later)
        if kversion and kversion >= "2.6.28":
            addr = Symbol.get_ksymaddr("cmdline_proc_show")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_dword_ptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res),
                    )
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_current_task():
        if not is_x86():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("current_task")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.1 or later)
        if kversion and kversion >= "4.1":
            addr = Symbol.get_ksymaddr("common_cpu_up")
            if addr:
                res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, skip_msb_check=True)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, skip_msb_check=True)
                for x in g:
                    if x < 0x100:
                        continue
                    return x

        # plan 3 (available v2.5.33 or later)
        if kversion and kversion >= "2.5.33":
            addr = Symbol.get_ksymaddr("setup_arg_pages")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.x64_qword_ptr_ds(res),
                        KernelAddressHeuristicFinderUtil.x64_qword_ptr_gs(res, skip_msb_check=True),
                    )
                elif is_x86_32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.x86_dword_ptr_ds(res),
                        KernelAddressHeuristicFinderUtil.x86_dword_ptr_fs(res, skip_msb_check=True)
                    )
                for x in g:
                    if x < 0x100:
                        continue
                    return x
        return None

    @staticmethod
    def get_current_task_for_current_thread():
        if is_arm32():
            # plan 1 (from special register)
            r = get_register("$TPIDRURO")
            if r and is_valid_addr(r):
                return r
            r = get_register("$TPIDRURO_S")
            if r and is_valid_addr(r):
                return r

            # plan 2 (from stack top)
            # We need to consider the case where Linux and RTOS are running on different CPUs at the same time.
            # If the stack is not the address the kernel expects to use, it should not be interpreted as a task.
            maps = Kernel.get_maps()
            if not maps:
                return None
            kern_min = maps[0][0]
            if kern_min < 0x80000000:
                PAGE_OFFSET = 0x40000000 # VMSPLIT_1G
            elif kern_min < 0xB0000000:
                PAGE_OFFSET = 0x80000000 # VMSPLIT_2G
            elif kern_min < 0xBF000000: # 0xBF000000-0xC0000000 is kernel module area. Even if it is VMSPLIT_3G, this is used.
                PAGE_OFFSET = 0xB0000000 # VMSPLIT_3G_OPT
            else:
                PAGE_OFFSET = 0xC0000000 # VMSPLIT_3G

            # check if valid kernel address or not
            current_thread_info = current_arch.sp & ~0x1fff
            if current_thread_info < PAGE_OFFSET:
                return None

            kversion = Kernel.kernel_version()

            try:
                """
                struct thread_info {
                    unsigned long flags;
                    int preempt_count;
                    mm_segment_t addr_limit; // ~v5.14
                    struct task_struct *task; // ~v5.17
                    ...
                }
                """
                if kversion < "5.15":
                    v = read_int_from_memory(current_thread_info + current_arch.ptrsize * 3)
                    if v and is_valid_addr(v):
                        return v
                elif kversion < "5.18":
                    v = read_int_from_memory(current_thread_info + current_arch.ptrsize * 2)
                    if v and is_valid_addr(v):
                        return v
            except gdb.MemoryError:
                # In some threads, $sp points to an invalid address.
                return None
        elif is_arm64():
            # plan 1 (from special register)
            return get_register("$SP_EL0")
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_init_task():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("init_task")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # Detecting `init_task` is very difficult.
        # This is because `init_task` itself is rarely used, and `init_task.tasks` is most often used.
        # On x86/x64 I've found the only case where it can be detected stably.
        # However, there seem to be cases where it is not found.

        # plan 2 (available v3.4 or later)
        if kversion and kversion >= "3.4":
            if is_x86_64() or is_x86_32():
                addr = Symbol.get_ksymaddr("do_exit")
                if addr:
                    res = gdb.execute("x/600i {:#x}".format(addr), to_string=True)
                    if is_x86_64():
                        g = KernelAddressHeuristicFinderUtil.x64_x86_cmp_const(res)
                    elif is_x86_32():
                        g = KernelAddressHeuristicFinderUtil.x64_x86_cmp_const(res)
                    for x in g:
                        # There are cases where init_pid_ns is falsely detected as init_task.
                        # The initial value of kref is 2, so exclude this.
                        if read_int_from_memory(x) == 2:
                            continue
                        return x

        # On arm32/arm64, I couldn't find that pattern.
        # But there is a method that find `current_task` with 100% stability on arm32/arm64 (from spectial register).
        # Additionally, `init_task` is always in kernel .data area.
        # So I have implemented a method following.
        # 1. Find the linked list `current_task.tasks` from `current_task`, and gathering all address of task.
        # 2. Just choose the one with the smallest distance from kernel .data.
        # This method can also be applied to x86/x64 as long as the `current_task` is got.

        def get_offset_tasks(current_task):
            # search init_task->tasks
            for i in range(0x200):
                offset_tasks = current_arch.ptrsize * i
                if not is_double_link_list(current_task + offset_tasks):
                    continue
                if len(get_task_list(current_task, offset_tasks)) > 5: # process count
                    return offset_tasks
            return None

        def get_task_list(task, offset_tasks):
            pos = task + offset_tasks
            task_list = [pos]
            # validating candidate offset
            while True:
                pos = read_int_from_memory(pos)
                if pos in task_list:
                    break
                task_list.append(pos)
            return [x - offset_tasks for x in task_list]

        # plan 3 (from current)
        if is_arm64() or is_arm32():
            current = KernelAddressHeuristicFinder.get_current_task_for_current_thread()
        elif is_x86_64() or is_x86_32():
            current_task = KernelAddressHeuristicFinder.get_current_task()
            if current_task and AddressUtil.is_msb_on(current_task):
                # no __per_cpu_offset
                current = read_int_from_memory(current_task)
            else:
                # use __per_cpu_offset
                p = KernelAddressHeuristicFinder.get_per_cpu_offset()
                if p and is_valid_addr(p):
                    cpu_base = read_int_from_memory(p)
                    current = read_int_from_memory(cpu_base + current_task)
                else:
                    current = None
        if current:
            offset_tasks = get_offset_tasks(current)
            if offset_tasks:
                task_list = get_task_list(current, offset_tasks)
                kinfo = Kernel.get_kernel_base()
                min_distance_task = (None, 0xffffffffffffffff)
                for task in task_list:
                    distance = abs((kinfo.rw_base or kinfo.text_base) - task)
                    if min_distance_task[1] > distance:
                        min_distance_task = (task, distance)
                if min_distance_task[0] is not None:
                    return min_distance_task[0]
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_init_cred():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("init_cred")
            if x:
                return x

        # plan2 (from ktask)
        res = gdb.execute("ktask --filter swapper/0 --no-pager", to_string=True)
        m = re.search(r"offsetof\(task_struct, cred\): (0x\w+)", res)
        if m:
            cred_offset = int(m.group(1), 16)
            line = res.strip().splitlines()[-1]
            addr, _, _, name, *_ = line.split()
            if name == "swapper/0":
                task = int(addr, 16)
                return read_int_from_memory(task + cred_offset)

        # plan3 (from ktask, not swapper/0, just swapper)
        res = gdb.execute("ktask --filter swapper --no-pager", to_string=True)
        m = re.search(r"offsetof\(task_struct, cred\): (0x\w+)", res)
        if m:
            cred_offset = int(m.group(1), 16)
            line = res.strip().splitlines()[-1]
            addr, _, _, name, *_ = line.split()
            if name == "swapper":
                task = int(addr, 16)
                return read_int_from_memory(task + cred_offset)
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_init_net():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("init_net")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.6.35 or later)
        if kversion and kversion >= "2.6.35":
            addr = Symbol.get_ksymaddr("net_initial_ns")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x

        # plan 3 (available v2.6.24 or later)
        if kversion and kversion >= "2.6.24":
            addr = Symbol.get_ksymaddr("netdev_boot_base")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    if not is_valid_addr(x):
                        continue
                    if read_cstring_from_memory(x) == "%s%d":
                        continue
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_init_user_ns():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("init_user_ns")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.6.39 or later)
        if kversion and kversion >= "2.6.39":
            addr = Symbol.get_ksymaddr("has_capability")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_modules():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("modules")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v3.7.5 or later)
        if kversion and kversion >= "3.7.5":
            addr = Symbol.get_ksymaddr("find_module_all")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_ldr(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt_ldr(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative_ldr(res),
                    )
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_chrdevs():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("chrdevs")
            if x:
                return x

        kversion = Kernel.kernel_version()

        def is_single_link_list(x):
            seen = []
            while True:
                if x == 0:
                    return True
                if x in seen:
                    return False
                seen.append(x)
                if not is_valid_addr(x):
                    return False
                x = read_int_from_memory(x)

        # plan 2 (available v2.6.16.12 or later)
        if kversion and kversion >= "2.6.17":
            addr = Symbol.get_ksymaddr("chrdev_show")
            if addr:
                res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr_array_base(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_dword_ptr_array_base(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt_ldr(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res),
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt(res),
                    )
                for x in g:
                    if not is_valid_addr(x):
                        continue
                    for i in range(255):
                        v = read_int_from_memory(x + current_arch.ptrsize * i)
                        if not is_single_link_list(v):
                            break
                    else:
                        # Case where all 255 entries meet the conditions
                        return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_cdev_map():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("cdev_map")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.5.70 or later)
        if kversion and kversion >= "2.5.70":
            addr = Symbol.get_ksymaddr("cdev_del")
            if addr:
                res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt_ldr(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative_ldr(res),
                    )
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_sys_call_table_x64():
        if not is_x86_64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("sys_call_table")
            if x:
                return x

        kversion = Kernel.kernel_version()

        if kversion and kversion >= "6.6.26":
            # On x64, each entry is embedded in `x64_sys_call` as call instruction.
            # So sys_call_table is no longer in use, but it still remains.
            # We won't return yet because we may be able to detect this in plan 5.
            pass

        # plan 2 (available v4.6 ~ v6.6.26)
        if kversion and kversion >= "4.6" and kversion < "6.6.26":
            addr = Symbol.get_ksymaddr("do_syscall_64")
            if addr:
                res = gdb.execute("x/40i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.x64_qword_ptr_array_base(res)
                for x in g:
                    return x

        # plan 3 (available v4.2 ~ v4.13)
        if kversion and kversion >= "4.2" and kversion < "4.14":
            addr = Symbol.get_ksymaddr("entry_SYSCALL_64_fastpath")
            if addr:
                res = gdb.execute("x/10i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.x64_qword_ptr_array_base(res)
                for x in g:
                    return x

        # plan 4 (available v2.6.27 ~ v4.1)
        if kversion and kversion >= "2.6.27" and kversion < "4.2":
            addr = Symbol.get_ksymaddr("system_call_fastpath")
            if addr:
                res = gdb.execute("x/10i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.x64_qword_ptr_array_base(res)
                for x in g:
                    return x

        # plan 5 (search memory)
        sys_read = Symbol.get_ksymaddr("__x64_sys_read")
        sys_write = Symbol.get_ksymaddr("__x64_sys_write")
        sys_open = Symbol.get_ksymaddr("__x64_sys_open")
        sys_close = Symbol.get_ksymaddr("__x64_sys_close")
        seq_to_find = p64(sys_read) + p64(sys_write) + p64(sys_open) + p64(sys_close)
        kinfo = Kernel.get_kernel_base()
        if kinfo and kinfo.ro_base:
            ro_data = read_memory(kinfo.ro_base, kinfo.ro_size)
            sys_call_table_offset = ro_data.find(seq_to_find)
            if sys_call_table_offset >= 0:
                return kinfo.ro_base + sys_call_table_offset
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_sys_call_table_x32():
        if not is_x86_64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("x32_sys_call_table")
            if x:
                return x

        kversion = Kernel.kernel_version()

        if kversion and kversion < "5.4":
            # Not introduced
            return None

        if kversion and kversion >= "6.6.26":
            # On x64, each entry is embedded in `x32_sys_call` as call instruction.
            # So x32_sys_call_table is no longer in use, and removed from 6.6.26.
            return None

        # plan 2 (available v5.4 or later)
        if kversion and kversion >= "5.4":
            addr = Symbol.get_ksymaddr("do_syscall_64")
            if addr:
                res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.x64_qword_ptr_array_base(res, skip=1)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_sys_call_table_x86():
        if not is_x86():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            if is_x86_64():
                x = Symbol.get_ksymaddr("ia32_sys_call_table")
            elif is_x86_32():
                x = Symbol.get_ksymaddr("sys_call_table")
            if x:
                return x

        kversion = Kernel.kernel_version()

        if kversion and kversion >= "6.6.26":
            if is_x86_64():
                # On x64, ia32_sys_call_table is removed from 6.6.26.
                return None
            else:
                # On i386, each entry is embedded in `ia32_sys_call` as call instruction.
                # So sys_call_table is no longer in use, but it still remains.
                # We won't return yet because we may be able to detect this in plan 3.
                pass

        # plan 2 (available v2.6.24 ~ v6.6.26)
        if kversion and kversion >= "6.6.7" and kversion < "6.6.26":
            if is_x86_64():
                # ia32_sys_call_table is still used, but no detection logic.
                addr = None
            else:
                addr = Symbol.get_ksymaddr("do_int80_syscall_32")
        elif kversion and kversion >= "4.6" and kversion < "6.6.7":
            addr = Symbol.get_ksymaddr("do_int80_syscall_32")
        elif kversion and kversion >= "4.4" and kversion < "4.6":
            if is_x86_64():
                addr = Symbol.get_ksymaddr("do_syscall_32_irqs_off")
            else:
                addr = Symbol.get_ksymaddr("do_syscall_32_irqs_on")
        elif kversion and kversion >= "2.6.24" and kversion < "4.4":
            addr = Symbol.get_ksymaddr("syscall_call")
        else:
            addr = None
        if addr:
            res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
            if is_x86_64():
                g = KernelAddressHeuristicFinderUtil.x64_qword_ptr_array_base(res)
            elif is_x86_32():
                g = KernelAddressHeuristicFinderUtil.x86_dword_ptr_array_base(res)
            for x in g:
                return x

        # plan 3 (search memory)
        sys_restart_syscall = Symbol.get_ksymaddr("sys_restart_syscall")
        sys_exit = Symbol.get_ksymaddr("sys_exit")
        sys_fork = Symbol.get_ksymaddr("sys_fork")
        sys_read = Symbol.get_ksymaddr("sys_read")
        seq_to_find = p32(sys_restart_syscall) + p32(sys_exit) + p32(sys_fork) + p32(sys_read)
        kinfo = Kernel.get_kernel_base()
        if kinfo and kinfo.ro_base:
            ro_data = read_memory(kinfo.ro_base, kinfo.ro_size)
            sys_call_table_offset = ro_data.find(seq_to_find)
            if sys_call_table_offset >= 0:
                return kinfo.ro_base + sys_call_table_offset
        return None

    @staticmethod
    def get_sys_call_table_arm32():
        if not is_arm32():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("sys_call_table")
            if x:
                return x

        # plan 2 (search memory)
        sys_restart_syscall = Symbol.get_ksymaddr("sys_restart_syscall")
        sys_exit = Symbol.get_ksymaddr("sys_exit")
        sys_fork = Symbol.get_ksymaddr("sys_fork")
        sys_read = Symbol.get_ksymaddr("sys_read")
        seq_to_find = p32(sys_restart_syscall) + p32(sys_exit) + p32(sys_fork) + p32(sys_read)
        kinfo = Kernel.get_kernel_base()
        # `sys_call_table` is embedded in the .text area even if `CONFIG_KALLSYMS_ALL=n`
        if kinfo and kinfo.text_base:
            text_data = read_memory(kinfo.text_base, kinfo.text_size)
            sys_call_table_offset = text_data.find(seq_to_find)
            if sys_call_table_offset >= 0:
                return kinfo.text_base + sys_call_table_offset
        return None

    @staticmethod
    def get_sys_call_table_arm64():
        if not is_arm64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("sys_call_table")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v3.7 or later)
        if kversion and kversion >= "5.6":
            addr = Symbol.get_ksymaddr("do_el0_svc")
        elif kversion and kversion >= "4.18" and kversion < "5.6":
            addr = Symbol.get_ksymaddr("el0_svc_handler")
        elif kversion and kversion >= "3.7" and kversion < "4.18":
            addr = Symbol.get_ksymaddr("el0_svc")
        else:
            addr = None
        if addr:
            res = gdb.execute("x/100i {:#x}".format(addr), to_string=True)
            g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res, read_valid=True)
            for x in g:
                return x

        # plan 3 (search memory)
        sys_io_setup = Symbol.get_ksymaddr("__arm64_sys_io_setup")
        sys_io_destroy = Symbol.get_ksymaddr("__arm64_sys_io_destroy")
        sys_io_submit = Symbol.get_ksymaddr("__arm64_sys_io_submit")
        sys_io_cancel = Symbol.get_ksymaddr("__arm64_sys_io_cancel")
        seq_to_find = p64(sys_io_setup) + p64(sys_io_destroy) + p64(sys_io_submit) + p64(sys_io_cancel)
        kinfo = Kernel.get_kernel_base()
        if kinfo and kinfo.ro_base:
            ro_data = read_memory(kinfo.ro_base, kinfo.ro_size)
            sys_call_table_offset = ro_data.find(seq_to_find)
            if sys_call_table_offset >= 0:
                return kinfo.ro_base + sys_call_table_offset
        return None

    @staticmethod
    def get_sys_call_table_arm64_compat():
        if not is_arm64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("compat_sys_call_table")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v3.7 or later)
        if kversion and kversion >= "5.6":
            addr = Symbol.get_ksymaddr("do_el0_svc_compat")
        elif kversion and kversion >= "4.18" and kversion < "5.6":
            addr = Symbol.get_ksymaddr("el0_svc_compat_handler")
        elif kversion and kversion >= "3.7" and kversion < "4.18":
            addr = Symbol.get_ksymaddr("el0_svc_compat")
        else:
            addr = None
        if addr:
            res = gdb.execute("x/100i {:#x}".format(addr), to_string=True)
            g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res, read_valid=True)
            for x in g:
                return x

        # plan 3 (search memory)
        sys_restart_syscall = Symbol.get_ksymaddr("__arm64_sys_restart_syscall")
        sys_exit = Symbol.get_ksymaddr("__arm64_sys_exit")
        sys_fork = Symbol.get_ksymaddr("__arm64_sys_fork")
        sys_read = Symbol.get_ksymaddr("__arm64_sys_read")
        sys_write = Symbol.get_ksymaddr("__arm64_sys_write")
        sys_open = Symbol.get_ksymaddr("__arm64_compat_sys_open")
        if sys_open:
            seq_to_find = p64(sys_restart_syscall) + p64(sys_exit) + p64(sys_fork) + p64(sys_read) + p64(sys_write) + p64(sys_open)
            kinfo = Kernel.get_kernel_base()
            if kinfo and kinfo.ro_base:
                ro_data = read_memory(kinfo.ro_base, kinfo.ro_size)
                sys_call_table_offset = ro_data.find(seq_to_find)
                if sys_call_table_offset >= 0:
                    return kinfo.ro_base + sys_call_table_offset
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_per_cpu_offset():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("__per_cpu_offset")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v3.3 or later)
        if kversion and kversion >= "3.3":
            addr = Symbol.get_ksymaddr("nr_iowait_cpu")
            if addr:
                res = gdb.execute("x/10i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.x64_qword_ptr_array_base(res),
                        KernelAddressHeuristicFinderUtil.x64_dword_ptr(res),
                    )
                elif is_x86_32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.x86_dword_ptr_array_base(res),
                        KernelAddressHeuristicFinderUtil.x86_dword_ptr(res)
                    )
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    cpu0 = read_int_from_memory(x)
                    if cpu0 and (cpu0 & 0xfff) == 0:
                        return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_slab_caches():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("slab_caches")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.9 or later)
        if kversion and kversion >= "4.9":
            addr = Symbol.get_ksymaddr("slub_cpu_dead")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_any_const(res, skip=1)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_any_const(res, skip=1)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res, skip=1)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x

        # plan 3 (available v5.9 or later)
        if kversion and kversion >= "5.9":
            addr = Symbol.get_ksymaddr("find_mergeable")
            if addr:
                res = gdb.execute("x/50i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_cmp_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_cmp_const(res)
                elif is_arm64():
                    # TODO
                    g = []
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt_add(res)
                for x in g:
                    return x

        # plan 4 (available v4.10 or before and CONFIG_MEMCG=y)
        if kversion and kversion < "4.11":
            addr = Symbol.get_ksymaddr("memcg_update_all_caches")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_any_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x

        # plan 5 (available v3.11 ~ v4.10 and CONFIG_SLABINFO=y)
        if kversion and kversion >= "3.11" and kversion < "4.11":
            addr = Symbol.get_ksymaddr("slab_next")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_any_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_any_const(res)
                elif is_arm64():
                    # TODO
                    g = []
                elif is_arm32():
                    # TODO
                    g = []
                for x in g:
                    return x

        # plan 6 (available if CONFIG_SLAB=y)
        addr = Symbol.get_ksymaddr("cache_reap")
        if addr:
            res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
            if is_x86_64():
                g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
            elif is_x86_32():
                # TODO
                g = []
            elif is_arm64():
                # TODO
                g = []
            elif is_arm32():
                g = KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res, skip=1)
            for x in g:
                return x

        # plan 7 (available v2.6.24 ~ v3.10 and CONFIG_SLABINFO=y)
        if kversion and kversion >= "2.6.24" and kversion < "3.11":
            addrs = Symbol.get_ksymaddr_multiple("s_next")
            if addrs:
                for s_next in addrs:
                    res = gdb.execute("x/20i {:#x}".format(s_next), to_string=True)
                    if is_x86_64():
                        g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, read_valid=True)
                    elif is_x86_32():
                        g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, read_valid=True)
                    elif is_arm64():
                        # TODO
                        g = []
                    elif is_arm32():
                        # TODO
                        g = []
                    for x in g:
                        v1 = read_int_from_memory(x)
                        v2 = read_int_from_memory(x + current_arch.ptrsize)
                        if is_valid_addr(v1) and is_valid_addr(v2):
                            return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_modprobe_path():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("modprobe_path")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("kernel.modprobe")
            if x:
                return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_poweroff_cmd():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("poweroff_cmd")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("kernel.poweroff_cmd")
            if x:
                return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_core_pattern():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("core_pattern")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("kernel.core_pattern")
            if x:
                return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_phys_base():
        if not is_x86_64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("phys_base")
            if x:
                return read_int_from_memory(x)

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.6.24 or later)
        if kversion and kversion >= "2.6.24":
            addr = Symbol.get_ksymaddr("secondary_startup_64")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                for x in g:
                    return read_int_from_memory(x)

        # plan 3 (available v2.6.25 ~ v5.5)
        if kversion and kversion >= "2.6.25" and kversion < "5.5":
            addr = Symbol.get_ksymaddr("arch_crash_save_vmcoreinfo")
            if addr:
                res = gdb.execute("x/10i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                for x in g:
                    s = read_cstring_from_memory(x)
                    if not s:
                        return read_int_from_memory(x)

        # plan 4 (available v3.9 or later)
        if kversion and kversion >= "3.9":
            addr = Symbol.get_ksymaddr("__virt_addr_valid")
            if addr:
                res = gdb.execute("x/50i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                for x in g:
                    return read_int_from_memory(x)
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_page_offset_base():
        if not is_x86_64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("page_offset_base")
            if x:
                return x

        # plan 2 (from pagewalk)
        kinfo = Kernel.get_kernel_base()
        page_offset_base_raw = kinfo.maps[0][0]
        ro_data = read_memory(kinfo.ro_base, kinfo.ro_size)
        ro_data = slice_unpack(ro_data, current_arch.ptrsize)
        try:
            index = ro_data.index(page_offset_base_raw)
            return kinfo.ro_base + index * current_arch.ptrsize
        except ValueError:
            pass
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_page_offset():
        if not is_x86_64():
            return None

        # plan 1 (fixed address)
        kversion = Kernel.kernel_version()
        if kversion and kversion < "4.8":
            # kASLR and Level5 pagetable is unsupported, so fixed address
            return 0xffff880000000000

        # plan 2 (from get_page_offset_base)
        page_offset_base = KernelAddressHeuristicFinder.get_page_offset_base()
        if page_offset_base:
            return read_int_from_memory(page_offset_base)

        # plan 3 (from pagewalk)
        kinfo = Kernel.get_kernel_base()
        if kinfo.maps and len(kinfo.maps) > 0:
            page_offset_base_raw = kinfo.maps[0][0]
            return page_offset_base_raw
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_vmalloc_start():
        if not is_x86_64():
            return None

        # plan 1 (fixed address)
        kversion = Kernel.kernel_version()
        if kversion and kversion < "4.8":
            # kASLR and Level5 pagetable is unsupported, so fixed address
            return 0xffffc90000000000

        # plan 2 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            vmalloc_base = Symbol.get_ksymaddr("vmalloc_base")
            if vmalloc_base:
                return read_int_from_memory(vmalloc_base)

        # plan 3 (from get_page_offset_base)
        page_offset_base = KernelAddressHeuristicFinder.get_page_offset_base()
        if page_offset_base:
            vmalloc_base = page_offset_base - current_arch.ptrsize
            return read_int_from_memory(vmalloc_base)

        # plan 4 (from vmalloc-dump)
        if kversion and kversion >= "5.2":
            res = gdb.execute("vmalloc-dump --quiet --no-pager --only-freed", to_string=True)
            """
            #    state  virtual address                       size               flags
            0    freed  0x0000000000000001-0xffffc90000000000 0xffffc8ffffffffff
            """
            if res:
                res = Color.remove_color(res)
                lines = res.splitlines()
                if len(lines) >= 2:
                    _, _, vrange, _, *_ = lines[1].split()
                    s, e = vrange.split("-")
                    s = int(s, 16)
                    e = int(e, 16)
                    if s == 1:
                        return e

        # plan 5 (from vmalloc-dump and pagewalk)
        res = gdb.execute("vmalloc-dump --quiet --no-pager --only-used", to_string=True)
        """
        [vmalloc-dump]
        #    state  virtual address                       size               flags
        0    in-use 0xffffa1c040000000-0xffffa1c040002000 0x2000             VM_IOREMAP

        [pagewalk]
        0xffff9927bfe00000-0xffff9927bffe0000 0x1e0000 0x1000 480 [RW- KERN ACCESSED DIRTY]
        0xffffa1c040000000-0xffffa1c040001000 0x1000   0x1000 1   [RW- KERN ACCESSED DIRTY]
        """
        if res:
            res = Color.remove_color(res)
            lines = res.splitlines()
            if len(lines) >= 2:
                _, _, vrange, _, *_ = lines[1].split()
                s, _ = vrange.split("-")
                s = int(s, 16)

                kinfo = Kernel.get_kernel_base()
                prev = None
                for vstart, _, _ in kinfo.maps:
                    if vstart == s:
                        break
                    prev = vstart

                if prev is not None:
                    mask = 0xffff_ff00_0000_0000
                    if (prev & mask) != (s & mask):
                        if (s & 0xfff_ffff) == 0:
                            return s
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_vmemmap():
        if not is_x86_64():
            return None

        # plan 1 (fixed address)
        kversion = Kernel.kernel_version()
        if kversion and kversion < "4.8":
            # kASLR and Level5 pagetable is unsupported, so fixed address
            return 0xffffea0000000000

        # plan 2 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            vmemmap_base = Symbol.get_ksymaddr("vmemmap_base")
            if vmemmap_base:
                return read_int_from_memory(vmemmap_base)

        def get_min_page(r):
            if r is None:
                return None
            min_page = None
            for x in r:
                x = int(x, 16)
                if not is_valid_addr(x):
                    continue
                if min_page is None or x < min_page:
                    min_page = x
            return min_page

        # plan 3 (from slub-dump / slub-tiny-dump)
        allocator = KernelChecksecCommand.get_slab_type()
        if allocator in ["SLUB", "SLUB_TINY"]:
            command = {"SLUB": "slub-dump --node", "SLUB_TINY": "slub-tiny-dump"}[allocator]
            for n in [8, 16, 32, 64, 96, 128, 192, 256, 512]:
                ret = gdb.execute("{:s} --simple --no-pager --quiet --skip-page2virt kmalloc-{:d}".format(command, n), to_string=True)
                r = re.findall(r"(?:active|partial|node) page: (0x\S\S+)", Color.remove_color(ret))
                min_page = get_min_page(r)
                if min_page is not None:
                    return min_page & 0xffff_ffff_c000_0000 # ~((1 << PUD_SHIFT) - 1)

        # plan 4 (from slab-dump)
        if allocator == "SLAB":
            ret = gdb.execute("slab-dump --simple --no-pager --quiet kmalloc-256", to_string=True)
            r = re.findall(r"node\[\d+\]\.slabs_(?:partial|full): (0x\S+)", Color.remove_color(ret))
            min_page = get_min_page(r)
            if min_page is not None:
                return min_page & 0xffff_ffff_c000_0000 # ~((1 << PUD_SHIFT) - 1)

        # plan 5 (from slob-dump)
        if allocator == "SLOB":
            ret = gdb.execute("slob-dump --simple --large --no-pager --quiet", to_string=True)
            r = re.findall(r"page: (0x\S+)", Color.remove_color(ret))
            min_page = get_min_page(r)
            if min_page is not None:
                return min_page & 0xffff_ffff_c000_0000 # ~((1 << PUD_SHIFT) - 1)
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_VMEMMAP_START():
        if not is_arm64():
            return None

        PAGE_SHIFT = 12
        T1SZ = (get_register("$TCR_EL1") >> 16) & 0b111111
        region_end = 2 ** 64
        region_start = region_end - (2 ** (64 - T1SZ))
        region_bits = GefUtil.log2(region_end - region_start)

        ID_AA64MMFR2_EL1 = get_register("$ID_AA64MMFR2_EL1")
        if ID_AA64MMFR2_EL1 is not None:
            FEAT_LVA = ((ID_AA64MMFR2_EL1 >> 16) & 0b1111) == 0b0001
        else:
            FEAT_LVA = False
        if FEAT_LVA:
            CONFIG_ARM64_VA_BITS = min(52, region_bits)
        else:
            CONFIG_ARM64_VA_BITS = region_bits

        VA_BITS = CONFIG_ARM64_VA_BITS
        if VA_BITS > 48:
            VA_BITS_MIN = 48
        else:
            VA_BITS_MIN = VA_BITS

        STRUCT_PAGE_MAX_SHIFT = 6

        # calc VMEMMAP_START
        kversion = Kernel.kernel_version()
        if kversion < "5.4":
            PAGE_OFFSET = AddressUtil.align_address(0xffffffffffffffff - (1 << (VA_BITS - 1)) + 1)
            VMEMMAP_SIZE = 1 << (VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT)
            VMEMMAP_START = PAGE_OFFSET - VMEMMAP_SIZE
        elif kversion < "5.12":
            PAGE_OFFSET = AddressUtil.align_address(-(1 << VA_BITS))
            PAGE_END = lambda va: -(1 << ((va) - 1))
            VMEMMAP_SIZE = ((PAGE_END(VA_BITS_MIN) - PAGE_OFFSET) >> (PAGE_SHIFT - STRUCT_PAGE_MAX_SHIFT))
            VMEMMAP_START = (-VMEMMAP_SIZE - 0x00200000) & 0xffffffffffffffff
        else: # v5.12~
            PAGE_OFFSET = AddressUtil.align_address(-(1 << VA_BITS))
            VMEMMAP_SHIFT = PAGE_SHIFT - STRUCT_PAGE_MAX_SHIFT
            VMEMMAP_START = -(1 << (VA_BITS - VMEMMAP_SHIFT)) & 0xffffffffffffffff
        return VMEMMAP_START, PAGE_OFFSET

    @staticmethod
    @switch_to_intel_syntax
    def get_mem_section():
        if not is_x86_32():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            addr = Symbol.get_ksymaddr("mem_section")
            if addr:
                return addr

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.8 ~ v5.15)
        if kversion and kversion >= "4.8" and kversion < "5.15":
            addr = Symbol.get_ksymaddr("__section_nr")
            if addr:
                res = gdb.execute("x/10i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.x64_x86_any_const(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_mem_map():
        if not is_x86_32() and not is_arm32():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            addr = Symbol.get_ksymaddr("mem_map")
            if addr:
                return read_int_from_memory(addr)

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.4.0 or later)
        if kversion and kversion >= "2.4":
            addr = Symbol.get_ksymaddr("free_pages")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.x86_dword_ptr_ds(res),
                        KernelAddressHeuristicFinderUtil.x86_noptr_ds(res),
                    )
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res),
                    )
                for x in g:
                    return read_int_from_memory(x)
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_clocksource_tsc():
        if not is_x86():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("clocksource_tsc")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.16.8 or later)
        if kversion and kversion >= "4.16.8":
            addr = Symbol.get_ksymaddr("mark_tsc_unstable.part.0") or Symbol.get_ksymaddr("mark_tsc_unstable.cold")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "rdi", skip=2)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "eax", skip=1)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_clocksource_list():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("clocksource_list")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.6.21 or later / v2.6.32 or later)
        if kversion and kversion >= "2.6.21":
            addr = Symbol.get_ksymaddr("clocksource_enqueue") or Symbol.get_ksymaddr("clocksource_resume")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res),
                    )
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_capability_hooks():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("capability_hooks")
            if x:
                return x

        # plan 2 nothing
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_n_tty_ops():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("n_tty_ops")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.6 or later)
        if kversion and kversion >= "4.6":
            addr = Symbol.get_ksymaddr("n_tty_inherit_ops")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.x86_dword_ptr(res),
                        KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res),
                    )
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_tty_ldiscs():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("tty_ldiscs")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.6.37 or later)
        if kversion and kversion >= "2.6.37":
            addr = Symbol.get_ksymaddr("tty_register_ldisc")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr_array_base(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_dword_ptr_array_base(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res),
                    )
                for x in g:
                    for i in range(2):
                        v = read_int_from_memory(x + current_arch.ptrsize * i)
                        if not is_valid_addr(v):
                            continue
                        if kversion < "5.13":
                            w = u32(read_memory(v, 4))
                            if w == 0x00005403: # magic
                                return x
                        else:
                            w = read_int_from_memory(v)
                            if not is_valid_addr(w):
                                continue
                            s = read_cstring_from_memory(w) # name
                            if s and len(s) > 2:
                                return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_sysctl_table_root():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("sysctl_table_root")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v3.4 or later)
        if kversion and kversion >= "3.4":
            addr = Symbol.get_ksymaddr("register_sysctl") or Symbol.get_ksymaddr("register_sysctl_sz")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, reg="rdi")
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "e[a-d]x")
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res),
                    )
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_selinux_state():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("selinux_state")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v5.0 ~ v6.3)
        if kversion and kversion >= "5.0" and kversion < "6.4":
            addr = Symbol.get_ksymaddr("show_sid")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, reg="rdi")
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "e[a-d]x")
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_ldr_reg_const(res, "r0")
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_apparmor_enabled():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("apparmor_enabled")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.12 or later)
        if kversion and kversion >= "4.12":
            addr = Symbol.get_ksymaddr("param_get_aauint")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt_ldr(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_apparmor_initialized():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("apparmor_initialized")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.12 or later)
        if kversion and kversion >= "4.12":
            addr = Symbol.get_ksymaddr("param_get_aauint")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_dword_ptr(res, skip=1)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res, skip=1)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res, skip=1)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res, skip=1)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_tomoyo_enabled():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("tomoyo_enabled")
            if x:
                return x

        # plan 2 nothing
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_mmap_min_addr():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("mmap_min_addr")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("vm.mmap_min_addr")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 3 (available v4.19.27 or later)
        if kversion and kversion >= "4.19.27":
            addr = Symbol.get_ksymaddr("expand_downwards")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_sysctl_unprivileged_userfaultfd():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("sysctl_unprivileged_userfaultfd")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("vm.unprivileged_userfaultfd")
            if x:
                return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_sysctl_unprivileged_bpf_disabled():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("sysctl_unprivileged_bpf_disabled")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("kernel.unprivileged_bpf_disabled")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 3 (available v4.9.91 ~ v5.18.19)
        if kversion and kversion >= "4.9.91" and kversion < "5.19":
            addr = Symbol.get_ksymaddr("__do_sys_bpf")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_dword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_kptr_restrict():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("kptr_restrict")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("kernel.kptr_restrict")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 3 (available v4.15 or later)
        if kversion and kversion >= "4.15":
            addr = Symbol.get_ksymaddr("kallsyms_show_value")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_dword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_sysctl_perf_event_paranoid():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("sysctl_perf_event_paranoid")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("kernel.perf_event_paranoid")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 3 (available v4.15 or later)
        if kversion and kversion >= "4.15":
            addr = Symbol.get_ksymaddr("kallsyms_show_value")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_dword_ptr(res, skip=1)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res, skip=1)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res, skip=1)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res, skip=1)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_dmesg_restrict():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("dmesg_restrict")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("kernel.dmesg_restrict")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 3 (available v3.11 or later)
        if kversion and kversion >= "3.11":
            addr = Symbol.get_ksymaddr("check_syslog_permissions")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_dword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt_ldr(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_kexec_load_disabled():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("kexec_load_disabled")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("kernel.kexec_load_disabled")
            if x:
                return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_loadpin_enabled():
        # plan 1 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("kernel.loadpin.enabled")
            if x:
                return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_ptrace_scope():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("ptrace_scope")
            if x:
                return x

        # plan 2 (from ksysctl)
        if KernelAddressHeuristicFinder.USE_KSYSCTL:
            x = Kernel.get_ksysctl("kernel.yama.ptrace_scope")
            if x:
                return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_vdso_image_64():
        if not is_x86_64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("vdso_image_64")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.2 or later)
        if kversion and kversion >= "4.2":
            addr = Symbol.get_ksymaddr("arch_setup_additional_pages")
            if addr:
                res = gdb.execute("x/40i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "rdi", read_valid=True)
                for x in g:
                    v = read_int_from_memory(x)
                    if read_memory(v, 4) == b"\x7fELF":
                        return x

                # another pattern
                # gef> |x/40i arch_setup_additional_pages | grep mov
                # 0xffffffff82401030 <arch_setup_additional_pages>:    mov eax,DWORD PTR [rip+0x43738a] # 0xffffffff828383c0 <vdso64_enabled>
                # 0xffffffff8240103e <arch_setup_additional_pages+14>: mov edx,DWORD PTR [rip+0x1ffb24] # 0xffffffff82600b68 <vdso_image_64+8>
                g = KernelAddressHeuristicFinderUtil.x64_dword_ptr(res)
                for x in g:
                    if not is_valid_addr(x):
                        continue
                    for i in range(10):
                        v = read_int_from_memory(x - current_arch.ptrsize * i)
                        if not is_valid_addr(v):
                            continue
                        if read_memory(v, 4) == b"\x7fELF":
                            return x - current_arch.ptrsize * i
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_vdso_image_x32():
        if not is_x86_64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("vdso_image_x32")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.2 or later)
        if kversion and kversion >= "4.2":
            addr = Symbol.get_ksymaddr("compat_arch_setup_additional_pages")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "rdi", read_valid=True)
                for x in g:
                    v = read_int_from_memory(x)
                    if read_memory(v, 4) == b"\x7fELF" and read_memory(v + 0x12, 1) == b"\x3e": # Elf.Machine
                        return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_vdso_image_32():
        if not is_x86():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("vdso_image_32")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.2 or later)
        if kversion and kversion >= "4.2":
            if is_x86_64():
                addr = Symbol.get_ksymaddr("compat_arch_setup_additional_pages")
                if addr:
                    res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "rdi", read_valid=True)
                    for x in g:
                        v = read_int_from_memory(x)
                        if read_memory(v, 4) == b"\x7fELF" and read_memory(v + 0x12, 1) == b"\x03": # Elf.Machine
                            return x
            elif is_x86_32():
                addr = Symbol.get_ksymaddr("arch_setup_additional_pages")
                if addr:
                    # pattern 1
                    res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "eax", read_valid=True)
                    for x in g:
                        v = read_int_from_memory(x)
                        if read_memory(v, 4) == b"\x7fELF":
                            return x
                    # pattern 2
                    res = gdb.execute("x/40i {:#x}".format(addr), to_string=True)
                    g2 = KernelAddressHeuristicFinderUtil.x86_dword_ptr_ds(res)
                    for x in g2:
                        if read_int_from_memory(x) == 0x1000:
                            v = read_int_from_memory(x - 4)
                            if read_memory(v, 4) == b"\x7fELF":
                                return x - 4
        return None

    @staticmethod
    def get_vdso_info():
        if not is_arm64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("vdso_info")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # vdso_info is introduced from v5.8
        if kversion < "5.8":
            return None

        # plan 2 (available v5.8 or later)
        if kversion and kversion >= "5.8":
            addr = Symbol.get_ksymaddr("__vdso_init")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                for x in g:
                    return x

        # plan 3 (from .rodata)
        """
        static struct vdso_abi_info vdso_info[] __ro_after_init = {
            [VDSO_ABI_AA64] = {
                .name = "vdso",
                .vdso_code_start = vdso_start,
                .vdso_code_end = vdso_end,
            },
        """
        kinfo = Kernel.get_kernel_base()
        if kinfo.ro_base and kinfo.ro_size:
            ro_data = read_memory(kinfo.ro_base, kinfo.ro_size)
            pos = -1
            while True:
                # search aligned ELF header from .rodata
                pos = ro_data.find(b"\x7fELF", pos + 1)
                if pos == -1:
                    break
                if pos % gef_getpagesize() != 0:
                    continue

                # calc address of ELF header
                if is_32bit():
                    vdso_addr_byteseq = p32(kinfo.ro_base + pos)
                else:
                    vdso_addr_byteseq = p64(kinfo.ro_base + pos)

                # search it from .rodata again
                pos2 = -1
                while True:
                    pos2 = ro_data.find(vdso_addr_byteseq, pos2 + 1)
                    if pos2 == -1:
                        break
                    if pos2 % current_arch.ptrsize != 0:
                        continue
                    maybe_vdso_info = kinfo.ro_base + pos2
                    maybe_vdso_info -= current_arch.ptrsize
                    name = read_int_from_memory(maybe_vdso_info)
                    if not is_valid_addr(name):
                        continue
                    if read_cstring_from_memory(name) == "vdso":
                        return maybe_vdso_info
        return None

    @staticmethod
    def get_vdso_lookup():
        if not is_arm64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("vdso_lookup")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # vdso_info is introduced until v5.8
        if kversion and (kversion >= "5.8" or kversion < "5.3"):
            return None

        # plan 2 (available v5.3 or later)
        if kversion and kversion >= "5.3":
            addr = Symbol.get_ksymaddr("__vdso_init")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                for x in g:
                    return x

        # plan 3 (from .rodata)
        """
        static struct __vdso_abi vdso_lookup[VDSO_TYPES] __ro_after_init = {
            {
                .name = "vdso",
                .vdso_code_start = vdso_start,
                .vdso_code_end = vdso_end,
            },
        """
        kinfo = Kernel.get_kernel_base()
        if kinfo.ro_base and kinfo.ro_size:
            ro_data = read_memory(kinfo.ro_base, kinfo.ro_size)
            pos = -1
            while True:
                # search aligned ELF header from .rodata
                pos = ro_data.find(b"\x7fELF", pos + 1)
                if pos == -1:
                    break
                if pos % gef_getpagesize() != 0:
                    continue

                # calc address of ELF header
                if is_32bit():
                    vdso_addr_byteseq = p32(kinfo.ro_base + pos)
                else:
                    vdso_addr_byteseq = p64(kinfo.ro_base + pos)

                # search it from .rodata again
                pos2 = -1
                while True:
                    pos2 = ro_data.find(vdso_addr_byteseq, pos2 + 1)
                    if pos2 == -1:
                        break
                    if pos2 % current_arch.ptrsize != 0:
                        continue
                    maybe_vdso_lookup = kinfo.ro_base + pos2
                    maybe_vdso_lookup -= current_arch.ptrsize
                    name = read_int_from_memory(maybe_vdso_lookup)
                    if not is_valid_addr(name):
                        continue
                    if read_cstring_from_memory(name) == "vdso":
                        return maybe_vdso_lookup
        return None

    @staticmethod
    def get_vdso_start():
        if not is_arm32() and not is_arm64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("vdso_start")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (from vdso_info or vdso_lookup)
        if kversion and is_arm64():
            if kversion >= "5.8":
                vdso_info = KernelAddressHeuristicFinder.get_vdso_info()
            else:
                vdso_info = KernelAddressHeuristicFinder.get_vdso_lookup()
            if vdso_info and is_valid_addr(vdso_info):
                vdso_name = read_int_from_memory(vdso_info)
                if is_valid_addr(vdso_name):
                    if "vdso" == read_cstring_from_memory(vdso_name):
                        x = read_int_from_memory(vdso_info + current_arch.ptrsize)
                        return x

        # plan 3 (from .rodata)
        kinfo = Kernel.get_kernel_base()
        if kinfo.ro_base and kinfo.ro_size:
            ro_data = read_memory(kinfo.ro_base, kinfo.ro_size)
            pos = -1
            while True:
                # search aligned ELF header from .rodata
                pos = ro_data.find(b"\x7fELF", pos + 1)
                if pos == -1:
                    break
                if pos % gef_getpagesize() == 0:
                    return kinfo.ro_base + pos
        return None

    @staticmethod
    def get_vdso32_start():
        if not is_arm64():
            return None

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("vdso32_start")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (from vdso_info or vdso_lookup)
        if kversion:
            if kversion >= "5.8":
                vdso_info = KernelAddressHeuristicFinder.get_vdso_info()
            else:
                vdso_info = KernelAddressHeuristicFinder.get_vdso_lookup()
            if vdso_info:
                vdso_info_2 = vdso_info + current_arch.ptrsize * 6
                if vdso_info_2 and is_valid_addr(vdso_info_2):
                    vdso_name = read_int_from_memory(vdso_info_2)
                    if is_valid_addr(vdso_name):
                        if "vdso32" == read_cstring_from_memory(vdso_name):
                            x = read_int_from_memory(vdso_info_2 + current_arch.ptrsize)
                            return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_file_systems():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("file_systems")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.5.7 or later)
        if kversion and kversion >= "2.5.7":
            addr = Symbol.get_ksymaddr("unregister_filesystem")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res, read_valid=True)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res, read_valid=True)
                elif is_arm64():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res, read_valid=True),
                        KernelAddressHeuristicFinderUtil.aarch64_adrp_add_ldr(res, read_valid=True),
                    )
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt(res, read_valid=True),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res, read_valid=True),
                    )
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_printk_rb_static():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("printk_rb_static")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v5.13 or later)
        if kversion and kversion >= "5.13":
            addr = Symbol.get_ksymaddr("kmsg_dump_rewind")
            if addr:
                res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res, read_valid=True)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res, read_valid=True)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res, read_valid=True)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt_ldr(res, read_valid=True)
                for x in g:
                    return read_int_from_memory(x)

        # plan 3 (available v5.10 or later)
        if kversion and kversion >= "5.10":
            addr = Symbol.get_ksymaddr("kmsg_dump_rewind_nolock")
            if addr:
                res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res, read_valid=True)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res, read_valid=True)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res, read_valid=True)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt_ldr(res, read_valid=True)
                for x in g:
                    return read_int_from_memory(x)
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_log_first_idx():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("log_first_idx")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # this is old dmesg structure
        if kversion and kversion >= "5.10":
            return False

        # plan 2 (available v3.5 or later)
        if kversion and kversion >= "3.5":
            addr = Symbol.get_ksymaddr("devkmsg_open")
            if addr:
                res = gdb.execute("x/50i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_dword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_mov_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_ldr(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt_ldr(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative_ldr(res),
                    )
                for x in g:
                    v = u32(read_memory(x, 4))
                    if is_valid_addr(v):
                        continue
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_log_next_idx():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("log_next_idx")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # this is old dmesg structure
        if kversion and kversion >= "5.10":
            return False

        # plan 2 (available v3.5 or later)
        if kversion and kversion >= "3.5":
            addr = Symbol.get_ksymaddr("kmsg_dump_rewind_nolock")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_dword_ptr(res, skip=1)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_dword_ptr_ds(res)
                    g = list(g)[::-1]
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_ldr(res, skip=1)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt_ldr(res, skip=1),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative_ldr(res, skip=1),
                    )
                for x in g:
                    v = u32(read_memory(x, 4))
                    if v == 0:
                        continue
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get___log_buf():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("__log_buf")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # this is old dmesg structure
        if kversion and kversion >= "5.10":
            return False

        # plan 2 (available v3.5 or later)
        if kversion and kversion >= "3.5":
            log_buf_len = KernelAddressHeuristicFinder.get_log_buf_len()
            if log_buf_len:
                # static char *log_buf = __log_buf;
                # static u32 log_buf_len = __LOG_BUF_LEN;
                if is_32bit():
                    # pattern1 (x86): log_buf_len -> log_buf
                    # 0xc1ba30b8|+0x0000|+000: 0x00040000
                    # 0xc1ba30bc|+0x0004|+001: 0xc1cf7720  ->  0x00000000
                    # pattern2 (ARM): log_buf -> log_buf_len
                    # 0xc03d26dc|+0x0000|+000: 0xc03ec9f8  ->  0x00000000
                    # 0xc03d26e0|+0x0004|+001: 0x00004000
                    pattern = [4, -4]
                elif is_64bit():
                    # pattern1 (x64): log_buf_len -> log_buf
                    # 0xffffffffaa240720|+0x0000|+000: 0x0000000000020000
                    # 0xffffffffaa240728|+0x0008|+001: 0xffffffffaa2f87dc  ->  0x0000000000000000
                    # pattern1 (ARM64): log_buf_len -> log_buf
                    # 0xffff000011256c68|+0x0000|+000: 0x0000000000020000
                    # 0xffff000011256c70|+0x0008|+001: 0xffff0000113f5350 <__log_buf>  ->  0x0000000000000000
                    # pattern2 (x64): log_buf_len -> log_buf (no-padding)
                    # 0xffffffffa5c476cc|+0x0000|+000: 0xa62e9cf400040000
                    # 0xffffffffa5c476d4|+0x0008|+001: 0x00000000ffffffff (=0xffffffffa62e9cf4)
                    # pattern3 (x64): log_buf -> log_buf_len
                    # 0xffffffff81c1df48|+0x0008|+001: 0xffffffff81d98e20  ->  0x0000000000000000
                    # 0xffffffff81c1df50|+0x0010|+002: 0xffffffff00040000 (=0x00040000)
                    pattern = [8, 4, -8]
                for diff in pattern:
                    log_buf = log_buf_len + diff
                    __log_buf = read_int_from_memory(log_buf)
                    if is_valid_addr(__log_buf):
                        return __log_buf
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_log_buf_len():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("log_buf_len")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # this is old dmesg structure
        if kversion and kversion >= "5.10":
            return False

        # plan 2 (available v3.17 or later)
        if kversion and kversion >= "3.17":
            addr = Symbol.get_ksymaddr("log_buf_len_get")
            if addr:
                res = gdb.execute("x/10i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_dword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative_ldr(res),
                    )
                for x in g:
                    v = u32(read_memory(x, 4))
                    if v and (v & 0xfff) == 0:
                        return x

        # plan 3 (available v3.5 or later)
        if kversion and kversion >= "3.5":
            addr = Symbol.get_ksymaddr("do_syslog")
            if addr:
                res = gdb.execute("x/300i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_dword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    # TODO
                    g = []
                elif is_arm32():
                    # TODO
                    g = []
                for x in g:
                    v = u32(read_memory(x, 4))
                    if v and (v & 0xfff) == 0:
                        return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_idt_base():
        if is_x86():
            if is_qemu_system():
                res = gdb.execute("monitor info registers", to_string=True)
                idtr = re.search(r"IDT\s*=\s*(\w+) (\w+)", res)
                base, _limit = [int(idtr.group(i), 16) for i in range(1, 3)]
                return base
            elif is_vmware():
                res = gdb.execute("monitor r idtr", to_string=True)
                r = re.search(r"idtr base=(\w+) limit=(\w+)", res)
                base = int(r.group(1), 16)
                return base
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_gdt_base():
        if is_x86():
            if is_qemu_system():
                res = gdb.execute("monitor info registers", to_string=True)
                gdtr = re.search(r"GDT\s*=\s*(\w+) (\w+)", res)
                base, _limit = [int(gdtr.group(i), 16) for i in range(1, 3)]
                return base
            elif is_vmware():
                res = gdb.execute("monitor r gdtr", to_string=True)
                r = re.search(r"gdtr base=(\w+) limit=(\w+)", res)
                base = int(r.group(1), 16)
                return base
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_tss_base():
        if is_x86():
            if is_qemu_system():
                res = gdb.execute("monitor info registers", to_string=True)
                tr = re.search(r"TR\s*=\s*(\w+) (\w+) (\w+) (\w+)", res)
                _trseg, base, _limit, _attr = [int(tr.group(i), 16) for i in range(1, 5)]
                return base
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_ldt_base():
        if is_x86():
            if is_qemu_system():
                res = gdb.execute("monitor info registers", to_string=True)
                ldtr = re.search(r"LDT\s*=\s*(\w+) (\w+) (\w+) (\w+)", res)
                _seg, base, _limit, _attr = [int(ldtr.group(i), 16) for i in range(1, 5)]
                return base
            elif is_vmware():
                # `monitor r ldtr` is buggy
                return None
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_node_data():
        # when CONFIG_NUMA=y (maybe)

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("node_data")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.6.17 or later)
        if kversion and kversion >= "2.6.17":
            addr = Symbol.get_ksymaddr("first_online_pgdat")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr_array_base(res)
                elif is_x86_32():
                    # TODO
                    g = []
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    # TODO
                    g = []
                for x in g:
                    v = read_int_from_memory(x)
                    if v and not is_valid_addr(v):
                        continue
                    if x in [v, v + current_arch.ptrsize]:
                        continue
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_node_data0():
        # when CONFIG_NUMA=n
        # This method can only be called when `get_node_data()` fails.

        kversion = Kernel.kernel_version()

        # plan 1 (available v2.6.17 or later)
        if kversion and kversion >= "2.6.17":
            addr = Symbol.get_ksymaddr("first_online_pgdat")
            if addr:
                res = gdb.execute("x/10i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "rax")
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "eax")
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    v = read_int_from_memory(x)
                    if v and is_valid_addr(v):
                        continue
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_prog_idr():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("prog_idr")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.13 or later)
        # In certain cases it may return `prog_idr_lock` instead of `prog_idr`.
        # It was not possible to distinguish them because their structures are very similar.
        # However, `prog_idr` and `prog_idr_lock` are placed consecutively.
        # Even if there is a slight deviation, there is no problem because the member
        # identification logic of the caller (`kbpf` command) works.
        if kversion and kversion >= "4.13":
            addr = Symbol.get_ksymaddr("bpf_prog_free_id.part.0") or Symbol.get_ksymaddr("bpf_prog_free_id")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_map_idr():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("map_idr")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.13 or later)
        # In certain cases it may return `map_idr_lock` instead of `map_idr`.
        # It was not possible to distinguish them because their structures are very similar.
        # However, `map_idr` and `map_idr_lock` are placed consecutively.
        # Even if there is a slight deviation, there is no problem because the member
        # identification logic of the caller (`kbpf` command) works.
        if kversion and kversion >= "4.13":
            addr = Symbol.get_ksymaddr("bpf_map_free_id")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_vmap_area_list():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("vmap_area_list")
            if x:
                return x

        kversion = Kernel.kernel_version()

        def is_looped_link_list(x):
            seen = []
            while True:
                if not is_valid_addr(x):
                    return False
                if len(seen) > 1 and x in seen[1:]:
                    return False
                if len(seen) > 0 and x == seen[0]:
                    return True
                seen.append(x)
                x = read_int_from_memory(x)

        # plan 2 (available v3.10 ~ v6.3: vread, v6.4~: vread_iter)
        if kversion and kversion >= "3.17":
            addr = Symbol.get_ksymaddr("vread") or Symbol.get_ksymaddr("vread_iter")
            if addr:
                res = gdb.execute("x/100i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_cmp_const(res, read_valid=True)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_cmp_const(res, read_valid=True)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_ldr(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res),
                    )
                for x in g:
                    if is_looped_link_list(x):
                        return x

        # plan 3 (available v4.10~)
        if kversion and kversion >= "4.10":
            addrs = Symbol.get_ksymaddr_multiple("s_next")
            if addrs:
                for s_next in addrs:
                    res = gdb.execute("x/20i {:#x}".format(s_next), to_string=True)
                    if is_x86_64():
                        g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "rsi")
                    elif is_x86_32():
                        g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, "e.x")
                    elif is_arm64():
                        g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_add(res, read_valid=True)
                    elif is_arm32():
                        g = KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res)
                    for x in g:
                        if is_looped_link_list(x):
                            return x

        # plan 4 (available v2.6.28 ~ v5.1)
        if kversion and kversion >= "2.6.28" and kversion < "5.2":
            addr = Symbol.get_ksymaddr("__insert_vmap_area")
            if addr:
                res = gdb.execute("x/100i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res, read_valid=True)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_dword_ptr_ds(res, read_valid=True)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_ldr(res)
                elif is_arm32():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.arm32_movw_movt(res),
                        KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res),
                    )
                for x in g:
                    if is_looped_link_list(x):
                        return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_free_vmap_area_list():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("free_vmap_area_list")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (from get_vmap_area_list; v5.2~)
        if kversion and kversion >= "5.2":
            if kversion >= "5.4":
                offset_list = current_arch.ptrsize * 5 # offsetof(struct vmap_area, list)
            elif kversion >= "5.2":
                offset_list = current_arch.ptrsize * 7 # offsetof(struct vmap_area, list)

            bits = AddressUtil.get_memory_alignment(in_bits=True)
            vend = (1 << bits) - 1

            if is_x86():
                direction = -1
            elif is_arm64() or is_arm32():
                direction = 1

            vmap_area_list = KernelAddressHeuristicFinder.get_vmap_area_list()
            if vmap_area_list:
                for i in range(2, 16): # 2: sizeof(list_head) / sizeof(long)
                    x = vmap_area_list + current_arch.ptrsize * i * direction
                    y = read_int_from_memory(x)
                    z = read_int_from_memory(x + current_arch.ptrsize)
                    if not is_valid_addr(y) or not is_valid_addr(z):
                        continue
                    ydata = read_int_from_memory(y - offset_list)
                    zdata = read_int_from_memory(z - offset_list)
                    if ydata == 0 or zdata == 0:
                        continue
                    if ydata != 1 and (ydata & 0xfff) != 0:
                        continue
                    if zdata != vend and (zdata & 0xfff) != 0:
                        continue
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_timer_bases():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("timer_bases")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.8 or later)
        if kversion and kversion >= "4.8":
            addr = Symbol.get_ksymaddr("run_timer_softirq")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, skip_msb_check=True),
                        KernelAddressHeuristicFinderUtil.x64_lea_reg_const(res, skip_msb_check=True),
                    )
                    g2 = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, skip_msb_check=True)
                    g2 = KernelAddressHeuristicFinderUtil.x86_dword_ptr(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res, skip_msb_check=True)
                    g2 = []
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res, skip_msb_check=True)
                    g2 = []
                # pattern1: per_cpu
                #    pattern1-a:
                #        0xffffffff8cf25b05 <run_timer_softirq+5>:    mov    rdi,0x24b40 <-- timer_bases
                #    pattern1-b:
                #        0xffffffffa440831e <run_timer_softirq+46>:   lea    rbx,[rax+0x22400]
                for x in g:
                    if not is_valid_addr(x) and (x & 0x7) == 0:
                        return x
                # pattern2: not per_cpu
                #    0xffffffff8aa6e450 <run_timer_softirq>:      mov    rax,QWORD PTR [rip+0x7cfba9] # 0xffffffff8b23e000 <jiffies_64>
                #    0xffffffff8aa6e457 <run_timer_softirq+7>:    cmp    rax,QWORD PTR [rip+0x7ce92a] # 0xffffffff8b23cd88 <timer_bases+8>
                #    0xffffffff8aa6e474 <run_timer_softirq+36>:   mov    rdx,QWORD PTR [rip+0x7cfb85] # 0xffffffff8b23e000 <jiffies_64>
                #    0xffffffff8aa6e47b <run_timer_softirq+43>:   mov    rax,QWORD PTR [rip+0x7ce906] # 0xffffffff8b23cd88 <timer_bases+8>
                jiffies = KernelAddressHeuristicFinder.get_jiffies()
                addrs = [x for x in g2 if (is_valid_addr(x) and (not jiffies or jiffies != x))]
                if addrs:
                    return min(addrs)
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_hrtimer_bases():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("hrtimer_bases")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v4.8 or later)
        if kversion and kversion >= "4.8":
            addr = Symbol.get_ksymaddr("hrtimer_run_queues")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = itertools.chain(
                        KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, skip_msb_check=True),
                        KernelAddressHeuristicFinderUtil.x64_byte_ptr(res, skip_msb_check=True),
                        KernelAddressHeuristicFinderUtil.x64_lea_reg_const(res, skip_msb_check=True),
                    )
                    g2 = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, skip_msb_check=True)
                    g2 = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res, skip_msb_check=True)
                    g2 = []
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res, skip_msb_check=True)
                    g2 = []
                # pattern1: per_cpu
                #    pattern1-a:
                #        0xffffffff9b127acb:  mov    rbx,0x27040 <-- hrtimer_bases
                #    pattern1-b:
                #        0xffffffffa440b87d <hrtimer_run_queues+13>:  test   BYTE PTR [rax+0x25b90],0x1
                #        The exact value is 0x25b80, but don't worry about a slight deviation.
                #    pattern1-c:
                #        0xffffffff818f57b5 <hrtimer_run_queues+21>:  lea    rbx,[rax+0x1df00]
                for x in g:
                    if not is_valid_addr(x) and (x & 0x7) == 0:
                        return x
                # pattern2: not per_cpu
                #    0xffffffffbb8668bc <hrtimer_run_queues+12>:  mov    rdx,0xffffffffbc046138
                #    0xffffffffbb8668c3 <hrtimer_run_queues+19>:  mov    rcx,0xffffffffbc046178
                #    0xffffffffbb8668ca <hrtimer_run_queues+26>:  mov    rsi,0xffffffffbc0460f8
                #    0xffffffffbb8668d1 <hrtimer_run_queues+33>:  mov    rdi,0xffffffffbc046048 <-- hrtimer_bases+8
                addrs = [x for x in g2 if is_valid_addr(x)]
                if addrs:
                    return min(addrs)
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_jiffies():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("jiffies")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.6.18 or later)
        if kversion and kversion >= "2.6.18":
            addr = Symbol.get_ksymaddr("jiffies_read")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_ldr(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_pci_root_buses():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("pci_root_buses")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v2.5.71 or later)
        if kversion and kversion >= "2.5.71":
            addr = Symbol.get_ksymaddr("pci_find_next_bus")
            if addr:
                res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_qword_ptr(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x86_noptr_ds(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res, read_valid=True)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res, read_valid=True)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_ioport_resource():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("ioport_resource")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v3.3 or later)
        if kversion and kversion >= "3.3":
            addr = Symbol.get_ksymaddr("pci_scan_bus")
            if addr:
                res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, r"r\w+")
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res, r"e\w+")
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    name_ptr = read_int_from_memory(x + 0x8 * 2) # sizeof(resource_size_t) == 8
                    if name_ptr and is_valid_addr(name_ptr):
                        name = read_cstring_from_memory(name_ptr)
                        if name == "PCI IO":
                            return x
                    name_ptr = read_int_from_memory(x + 0x4 * 2) # sizeof(resource_size_t) == 4
                    if name_ptr and is_valid_addr(name_ptr):
                        name = read_cstring_from_memory(name_ptr)
                        if name == "PCI IO":
                            return x

        # plan 3 (from .rodata)
        kinfo = Kernel.get_kernel_base()
        if kinfo.ro_base and kinfo.ro_size:
            ro_data = read_memory(kinfo.ro_base, kinfo.ro_size)
            if kinfo.rw_base and kinfo.rw_size:
                rw_data = read_memory(kinfo.rw_base, min(kinfo.rw_size, 0x1000000))
            else:
                rw_data = ro_data
            pos = -1
            while True:
                # search aligned string from .rodata
                pos = ro_data.find(b"PCI IO\x00", pos + 1)
                if pos == -1:
                    break

                # calc address of ELF header
                if is_32bit():
                    addr_byteseq = p32(kinfo.ro_base + pos)
                else:
                    addr_byteseq = p64(kinfo.ro_base + pos)

                # search it from .data
                pos2 = -1
                while True:
                    pos2 = rw_data.find(addr_byteseq, pos2 + 1)
                    if pos2 == -1:
                        break
                    if pos2 % current_arch.ptrsize != 0:
                        continue
                    # TODO: How to find the exact value of sizeof(resource_size_t)
                    if kinfo.rw_base and kinfo.rw_size:
                        maybe_ioport_resource = kinfo.rw_base + pos2 - current_arch.ptrsize * 2
                    else:
                        maybe_ioport_resource = kinfo.ro_base + pos2 - current_arch.ptrsize * 2
                    return maybe_ioport_resource
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_iomem_resource():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("iomem_resource")
            if x:
                return x

        # plan 2 (from ioport_resource)
        x = KernelAddressHeuristicFinder.get_ioport_resource()
        if x:
            # offsetof(resource, name)
            offset_name = None
            name_ptr = read_int_from_memory(x + 0x8 * 2) # sizeof(resource_size_t) == 8
            if name_ptr and is_valid_addr(name_ptr):
                name = read_cstring_from_memory(name_ptr)
                if name == "PCI IO":
                    offset_name = 0x8 * 2
            if offset_name is None:
                name_ptr = read_int_from_memory(x + 0x4 * 2) # sizeof(resource_size_t) == 4
                if name_ptr and is_valid_addr(name_ptr):
                    name = read_cstring_from_memory(name_ptr)
                    if name == "PCI IO":
                        offset_name = 0x4 * 2

            # find "PCI mem"
            if offset_name is not None:
                for i in range(-30, 30):
                    diff = (current_arch.ptrsize * i)
                    name_ptr = read_int_from_memory(x + diff)
                    if name_ptr and is_valid_addr(name_ptr):
                        name = read_cstring_from_memory(name_ptr)
                        if name == "PCI mem":
                            return x + diff - offset_name
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_db_list():
        # need DMA_SHARED_BUFFER=y

        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("db_list")
            if x:
                return x

        kversion = Kernel.kernel_version()

        # plan 2 (available v5.10 or later)
        if kversion and kversion >= "5.10":
            addr = Symbol.get_ksymaddr("dma_buf_file_release")
            if addr:
                res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res)
                for x in g:
                    # here, x points &db_list.lock
                    return x - current_arch.ptrsize * 2

        # plan 3 (available v3.17 ~ 5.9)
        if kversion and kversion >= "3.17" and kversion < "5.10":
            addr = Symbol.get_ksymaddr("dma_buf_release")
            if addr:
                res = gdb.execute("x/30i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_ldr_pc_relative(res)
                for x in g:
                    # here, x points &db_list.lock
                    return x - current_arch.ptrsize * 2
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_irq_desc_tree():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("irq_desc_tree")
            if x:
                return x

        kversion = Kernel.kernel_version()

        if kversion and kversion >= "6.5":
            return False

        # plan 2 (available v2.6.37 ~ 6.4)
        if kversion and kversion >= "2.6.37" and kversion < "6.5":
            addr = Symbol.get_ksymaddr("irq_to_desc")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x
        return None

    @staticmethod
    @switch_to_intel_syntax
    def get_sparse_irqs():
        # plan 1 (directly)
        if KernelAddressHeuristicFinder.USE_DIRECTLY:
            x = Symbol.get_ksymaddr("sparse_irqs")
            if x:
                return x

        kversion = Kernel.kernel_version()

        if kversion and kversion < "6.5":
            return False

        # plan 2 (available v6.5 or later)
        if kversion and kversion >= "6.5":
            addr = Symbol.get_ksymaddr("irq_to_desc")
            if addr:
                res = gdb.execute("x/20i {:#x}".format(addr), to_string=True)
                if is_x86_64():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_x86_32():
                    g = KernelAddressHeuristicFinderUtil.x64_x86_mov_reg_const(res)
                elif is_arm64():
                    g = KernelAddressHeuristicFinderUtil.aarch64_adrp_add(res)
                elif is_arm32():
                    g = KernelAddressHeuristicFinderUtil.arm32_movw_movt(res)
                for x in g:
                    return x
        return None


KF = KernelAddressHeuristicFinder # for convenience using from python-interactive # noqa: F841
KFU = KernelAddressHeuristicFinderUtil # for convenience using from python-interactive # noqa: F841


class Kernel:
    @staticmethod
    @Cache.cache_until_next
    def get_maps():
        maps = []
        res = PageMap.get_page_maps_by_pagewalk("pagewalk --quiet --no-pager --simple")
        res = sorted(set(res.splitlines()))
        res = list(filter(lambda line: line.endswith("]"), res))
        res = list(filter(lambda line: "[+]" not in line, res))
        res = list(filter(lambda line: "*" not in line, res))

        if is_x86():
            for line in res:
                line = line.split()
                if line[6] != "KERN]":
                    continue
                vaddr = int(line[0].split("-")[0], 16)
                size = int(line[2], 16)
                perm = line[5][1:] # [xxx
                maps.append([vaddr, size, perm])

        elif is_arm32():
            for line in res:
                line = line.split()
                if line[5] != "[PL0/---":
                    continue
                vaddr = int(line[0].split("-")[0], 16)
                size = int(line[2], 16)
                perm = line[6][4:7] # PL1/xxx
                maps.append([vaddr, size, perm])

        elif is_arm64():
            for line in res:
                line = line.split()
                if line[5] != "[EL0/---":
                    continue
                vaddr = int(line[0].split("-")[0], 16)
                size = int(line[2], 16)
                perm = line[6][4:7] # EL1/xxx
                maps.append([vaddr, size, perm])

        if maps == []:
            if is_x86():
                warn("Make sure you are in ring0 (=kernel mode)")
            elif is_arm32():
                warn("Make sure you are in supervisor mode (=kernel mode)")
                warn("Make sure qemu 3.x or higher")
            elif is_arm64():
                warn("Make sure you are in EL1 (=kernel mode)")
                warn("Make sure qemu 3.x or higher")
            return None
        else:
            return maps

    @staticmethod
    @Cache.cache_this_session
    def get_kernel_base():
        dic = {
            "maps": Kernel.get_maps(),
            "text_base": None,
            "text_size": None,
            "text_end": None,
            "ro_base": None,
            "ro_size": None,
            "ro_end": None,
            "rw_base": None,
            "rw_size": None,
            "rw_end": None,
            "rwx": False,
            "has_none": False,
        }
        Kinfo = collections.namedtuple("Kinfo", dic.keys())

        # maps is not found, so fast return
        if dic["maps"] is None:
            dic["has_none"] = None in dic.values()
            return Kinfo(*dic.values())

        # 1. search kernel base exact way for x86, arm64
        if is_x86():
            div0_handler = None

            if is_qemu_system():
                # 0   #DE: Divide-by-zero 0x00000000ffffffffbd008e0000100870 0xe 0x0 0x0 0x1 0x0010:0xffffffffbd000870 <NO_SYMBOL>
                res = gdb.execute("idtinfo --verbose", to_string=True)
                r = re.search(r"Divide-by-zero.+\S+:(\S+)\s+<", res)
                div0_handler = int(r.group(1), 16)
            elif is_vmware():
                res = gdb.execute("monitor r idtr", to_string=True)
                r = re.search(r"idtr base=(\S+) limit=(\S+)", res)
                base = int(r.group(1), 16)
                limit = int(r.group(2), 16)
                idtinfo = slice_unpack(read_memory(base, limit + 1), current_arch.ptrsize * 2)
                idt0 = IdtInfoCommand.idt_unpack(idtinfo[0])
                div0_handler = idt0.offset

            if div0_handler and is_valid_addr(div0_handler):
                for i, (vaddr, size, _perm) in enumerate(dic["maps"]):
                    if vaddr <= div0_handler < vaddr + size:
                        dic["text_base"] = vaddr
                        dic["text_size"] = size
                        dic["text_end"] = vaddr + size
                        text_base_map_index = i
                        break

        elif is_arm64():
            res = gdb.execute("sysreg --exact VBAR", to_string=True)
            res = Color.remove_color(res)
            r = re.search(r"VBAR\s+=\s+(0x\S+)", res)
            vbar = int(r.group(1), 16)
            vbar &= gef_getpagesize_mask_high()

            if vbar and is_valid_addr(vbar):
                for i, (vaddr, size, _perm) in enumerate(dic["maps"]):
                    if vaddr <= vbar < vaddr + size:
                        dic["text_base"] = vaddr
                        dic["text_size"] = size
                        dic["text_end"] = vaddr + size
                        text_base_map_index = i
                        break

        # 1b. search kernel base heuristic way
        if dic["text_base"] is None:
            # .text is usually noticeably larger than other areas.
            # It just determines this size heuristically and detects it, but it works well in most cases.
            TEXT_REGION_MIN_SIZE = 0x100000

            for i, (vaddr, size, perm) in enumerate(dic["maps"]):
                if perm == "R-X" and size >= TEXT_REGION_MIN_SIZE:
                    dic["text_base"] = vaddr
                    dic["text_size"] = size
                    dic["text_end"] = vaddr + size
                    text_base_map_index = i
                    break
            else:
                # not found, maybe old kernel
                for i, (vaddr, size, perm) in enumerate(dic["maps"]):
                    if perm == "RWX" and size >= TEXT_REGION_MIN_SIZE:
                        dic["text_base"] = vaddr
                        dic["text_size"] = size
                        dic["text_end"] = vaddr + size
                        text_base_map_index = i
                        break
                else:
                    # Not found, so fast return
                    dic["has_none"] = None in dic.values()
                    return Kinfo(*dic.values())

        # 2. search kernel RO base
        # If -enable-kvm option of qemu-system is not set, there may be multiple `r-- non-.rodata` between .text and .rodata.
        # In other words, .rodata may not exist immediately after .text. I have seen this on qemu with debian11 x86_64 installed.
        # Therefore, detecting by location will not return correct results.
        # Detecting by size seems well, but this algorithm sometimes failed. This is due to the difficulty of determining the threshold.
        # So I decided to also detect by the existence "Linux version" near the top of the .rodata page.
        RO_REGION_MIN_SIZE = 0x100000
        for i, (vaddr, size, perm) in enumerate(dic["maps"][text_base_map_index + 1:]):
            if perm == "R--":
                if dic["ro_base"] is None:
                    data = read_memory(vaddr, gef_getpagesize())
                    if size >= RO_REGION_MIN_SIZE or b"Linux version" in data:
                        dic["ro_base"] = vaddr
                        dic["ro_size"] = size
                        dic["ro_end"] = vaddr + size
                        ro_base_map_index = text_base_map_index + i
                elif dic["ro_end"] == vaddr:
                    # merge contiguous region.
                    # This is important because .rodata may be split into areas for GLOBAL and non-GLOBAL attributes
                    dic["ro_size"] += size
                    dic["ro_end"] += size
                    ro_base_map_index = text_base_map_index + i
                else:
                    break

        # 2b. search kernel RO base for old kernel
        if dic["ro_base"] is None:
            dic["rwx"] = True
            # If it can not detect .rodata, maybe it is an old kernel (32-bit?).
            # Old kernel is no-NX, so .rodata is RWX.
            # Detected .text range includes .rodata, so use heuristic search and split.
            #   [  .text  ] <- maybe .text is larger than 0x8000 (it fails in certain cases if 0x7000)
            #   [  .text  ]
            #   [  .text  ]
            #   [  .text  ] <- end of this area has [0x00, 0x00, 0x00, ...]
            #   [ .rodata ] <- near the top of this area has "Linux version"
            #   [ .rodata ]
            #   [ .rodata ]
            start = dic["text_base"] + gef_getpagesize() * 8
            end = dic["text_base"] + dic["text_size"]
            block_size = 0x20
            zero_data = b"\0" * block_size
            for addr in range(start, end, gef_getpagesize()):
                data_prev = read_memory(addr - block_size, block_size)
                if data_prev == zero_data:
                    data = read_memory(addr, gef_getpagesize())
                    if b"Linux version" in data:
                        dic["ro_base"] = addr
                        dic["ro_size"] = end - addr
                        dic["ro_end"] = end
                        dic["text_size"] -= dic["ro_size"]
                        # In this case, I chose not to detect rw_base.
                        # Because ksymaddr-remote seems to give better results.
                        dic["rw_base"] = 0
                        dic["rw_size"] = 0
                        dic["rw_end"] = 0
                        break
            else:
                # Not found, so fast return
                dic["has_none"] = None in dic.values()
                return Kinfo(*dic.values())

        else:
            # 3. search kernel RW base
            # If ro_base can be detected, detect the RW area from after ro_base.
            # TODO: I used specified the size, but there may be more good algorithms.
            RW_REGION_MIN_SIZE = 0x20000
            if dic["ro_base"] is not None:
                for vaddr, size, perm in dic["maps"][ro_base_map_index + 1:]:
                    if perm == "RW-":
                        if dic["rw_base"] is None:
                            if size >= RW_REGION_MIN_SIZE:
                                dic["rw_base"] = vaddr
                                dic["rw_size"] = size
                                dic["rw_end"] = vaddr + size
                                break

        dic["has_none"] = None in dic.values()
        return Kinfo(*dic.values())

    class KernelVersion:
        def __init__(self, address, version_string, major, minor, patch):
            self.address = address
            self.version_string = version_string
            self.major = major
            self.minor = minor
            self.patch = patch
            self.version_tuple = (major, minor, patch)
            return

        def to_version_tuple(self, _v):
            v = _v.split(".")
            if len(v) == 2:
                return (int(v[0]), int(v[1]), 0)
            elif len(v) == 3:
                return (int(v[0]), int(v[1]), int(v[2]))
            raise

        def __ge__(self, v):
            return self.to_version_tuple(v) <= self.version_tuple

        def __gt__(self, v):
            return self.to_version_tuple(v) < self.version_tuple

        def __le__(self, v):
            return self.to_version_tuple(v) >= self.version_tuple

        def __lt__(self, v):
            return self.to_version_tuple(v) > self.version_tuple

        def __eq__(self, v):
            return self.to_version_tuple(v) == self.version_tuple

        def __ne__(self, v):
            return self.to_version_tuple(v) != self.version_tuple

        def __str__(self):
            return "{:d}.{:d}.{:d}".format(*self.version_tuple)

    @staticmethod
    @Cache.cache_this_session
    def kernel_version():
        # fast path
        linux_banner = Symbol.get_ksymaddr("linux_banner")
        if linux_banner and is_valid_addr(linux_banner):
            version_string = read_cstring_from_memory(linux_banner, 0x200).rstrip()
            r = re.search(r"Linux version (\d)\.(\d+)\.(\d+)", version_string)
            if r:
                major, minor, patch = int(r.group(1)), int(r.group(2)), int(r.group(3))
                return Kernel.KernelVersion(linux_banner, version_string, major, minor, patch)

        # slow path
        kinfo = Kernel.get_kernel_base()
        if kinfo.has_none:
            return None
        area = []
        for addr in kinfo.maps: # resolve search range
            if addr[0] < kinfo.text_base:
                continue
            if kinfo.rw_base and addr[0] >= kinfo.rw_base:
                continue
            area.append([addr[0], addr[0] + addr[1]])
        if area == []:
            return None
        for start, end in area: # find version string
            try:
                data = read_memory(start, end - start)
            except gdb.MemoryError:
                continue
            data = "".join([chr(x) for x in data])
            r = re.findall(r"(Linux version (?:\d+\.[\d.]*\d)[ -~]+)", data)
            if not r:
                continue

            version_string = r[0]
            address = start + data.find(version_string)

            r = re.search(r"Linux version (\d)\.(\d+)\.(\d+)", version_string)
            major, minor, patch = int(r.group(1)), int(r.group(2)), int(r.group(3))

            return Kernel.KernelVersion(address, version_string, major, minor, patch)
        return None

    @staticmethod
    @Cache.cache_this_session
    def kernel_cmdline():
        saved_command_line = KernelAddressHeuristicFinder.get_saved_command_line()
        if saved_command_line is None:
            return None
        try:
            ptr = read_int_from_memory(saved_command_line)
            cmdline = read_cstring_from_memory(ptr, max_length=0x1000)
            Kcmdline = collections.namedtuple("Kcmdline", ["address", "cmdline"])
            return Kcmdline(ptr, cmdline)
        except Exception:
            return None

    @staticmethod
    @Cache.cache_this_session
    def get_ksysctl(sym):
        try:
            res = gdb.execute("ksysctl --quiet --no-pager --exact --filter {:s}".format(sym), to_string=True)
            return int(res.split()[1], 16)
        except (gdb.error, IndexError, ValueError):
            return None

    @staticmethod
    @Cache.cache_until_next
    def get_slab_contains(addr, allow_unaligned=False, keep_color=False):
        if not is_valid_addr(addr):
            return None
        ret = gdb.execute("slab-contains --quiet {:#x}".format(addr), to_string=True).strip()
        if not ret:
            return None
        if not allow_unaligned and "(unaligned?)" in ret:
            return None
        if keep_color:
            return ret
        return Color.remove_color(ret)

    @staticmethod
    @Cache.cache_until_next
    def p2v(paddr): # return list
        ret = gdb.execute("p2v {:#x}".format(paddr), to_string=True)
        return [int(x, 16) for x in re.findall(r"Phys: \S+ -> Virt: (\S+)", ret)]

    @staticmethod
    @Cache.cache_until_next
    def v2p(vaddr):
        # v2p is slow since it needs maps parsing for each time.
        # more faster using gva2gpa if available.
        ret = gdb.execute("monitor gva2gpa {:#x}".format(vaddr), to_string=True)
        r = re.search(r"gpa: (0x\S+)", ret)
        if r:
            return int(r.group(1), 16)

        ret = gdb.execute("v2p {:#x}".format(vaddr), to_string=True)
        r = re.search(r"Virt: 0x\S+ -> Phys: (0x\S+)", ret)
        if r:
            return int(r.group(1), 16)
        return None


@register_command
class KernelbaseCommand(GenericCommand):
    """Display kernel base address."""
    _cmdline_ = "kbase"
    _category_ = "08-b. Qemu-system Cooperation - Linux Basic"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if args.reparse:
            Cache.reset_gef_caches(all=True)

        # resolve text_base, ro_base
        if not args.quiet:
            info("Wait for memory scan")
        kinfo = Kernel.get_kernel_base()

        self.out = []
        if kinfo.text_base:
            self.out.append("kernel text:   {:#x}-{:#x} ({:#x} bytes)".format(kinfo.text_base, kinfo.text_end, kinfo.text_size))
        else:
            err("Failed to resolve kernel text")
        if kinfo.ro_base:
            self.out.append("kernel rodata: {:#x}-{:#x} ({:#x} bytes)".format(kinfo.ro_base, kinfo.ro_end, kinfo.ro_size))
        else:
            err("Failed to resolve kerel rodata")
        if kinfo.rw_base:
            self.out.append("kernel data:   {:#x}-{:#x} ({:#x} bytes)".format(kinfo.rw_base, kinfo.rw_end, kinfo.rw_size))
        else:
            err("Failed to resolve kernel data")
        if self.out:
            gef_print("\n".join(self.out))
        return


@register_command
class KernelVersionCommand(GenericCommand):
    """Display kernel version string."""
    _cmdline_ = "kversion"
    _category_ = "08-b. Qemu-system Cooperation - Linux Basic"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if args.reparse:
            Cache.reset_gef_caches(all=True)

        if not args.quiet:
            info("Wait for memory scan")
        kversion = Kernel.kernel_version()
        if kversion is None:
            if not args.quiet:
                err("Failed to resolve")
            return

        self.out = []
        self.out.append("{:#x}: {:s}".format(kversion.address, kversion.version_string))
        if self.out:
            gef_print("\n".join(self.out))
        return


@register_command
class KernelCmdlineCommand(GenericCommand):
    """Display kernel cmdline string."""
    _cmdline_ = "kcmdline"
    _category_ = "08-b. Qemu-system Cooperation - Linux Basic"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if args.reparse:
            Cache.reset_gef_caches(all=True)

        if not args.quiet:
            info("Wait for memory scan")
        kcmdline = Kernel.kernel_cmdline()
        if kcmdline is None:
            if not args.quiet:
                err("Failed to resolve")
            return

        self.out = []
        self.out.append("{:#x}: '{:s}'".format(kcmdline.address, kcmdline.cmdline))
        if self.out:
            gef_print("\n".join(self.out))
        return


@register_command
class KernelCurrentCommand(GenericCommand):
    """Display current task."""
    _cmdline_ = "kcurrent"
    _category_ = "08-b. Qemu-system Cooperation - Linux Basic"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__()
        self.__per_cpu_offset = None
        self.cpu_offset = None
        self.offset_comm = None
        return

    @staticmethod
    def get_each_cpu_offset(__per_cpu_offset):
        """
        Note that the number of CPUs and the number of threads may not match.
        x64 example:
        len(gdb.selected_inferior().threads()) == 2; but __per_cpu_offset entry is 1
        0xffffffff93980680|+0x0000|+000: 0xffff9724c7800000  ->  0x0000000000000000
        0xffffffff93980688|+0x0008|+001: 0xffffffff93d0d000
        0xffffffff93980690|+0x0010|+002: 0xffffffff93d0d000
        Therefore, when the same address is repeated, it is considered to be the end.
        """
        cpu_offset = []
        i = 0
        while True:
            off = read_int_from_memory(__per_cpu_offset + i * current_arch.ptrsize)
            """
            off itself may refer to inaccessible memory.
            x86 example:
            __per_cpu_offset: 0xc6a27440
            0xc6a27440|+0x0000|+000: 0x2d849000 -> inaccessible
            0xc6a27444|+0x0004|+001: 0x00000000
            """
            if (off <= 0x10) or (off & 0xf):
                break
            if len(cpu_offset) >= 1 and off == cpu_offset[-1]:
                cpu_offset.pop() # remove last one
                break
            cpu_offset.append(off)
            i += 1
        return cpu_offset

    def get_cpu_offset(self):
        # use cache
        if self.cpu_offset:
            if not self.quiet:
                info("__per_cpu_offset: {:#x}".format(self.__per_cpu_offset))
                info("num of cpu: {:d} (guessed)".format(len(self.cpu_offset)))
            return self.cpu_offset

        # resolve __per_cpu_offset
        __per_cpu_offset = KernelAddressHeuristicFinder.get_per_cpu_offset()

        # not found
        if __per_cpu_offset is None:
            if not self.quiet:
                warn("Failed to resolve `__per_cpu_offset`")
            return None

        # found
        if not self.quiet:
            info("__per_cpu_offset: {:#x}".format(__per_cpu_offset))
        self.__per_cpu_offset = __per_cpu_offset

        self.cpu_offset = KernelCurrentCommand.get_each_cpu_offset(__per_cpu_offset)
        if not self.quiet:
            info("num of cpu: {:d} (guessed)".format(len(self.cpu_offset)))
        return self.cpu_offset

    def get_comm_str(self, task_addr):
        if self.offset_comm is None:
            ret = gdb.execute("ktask --no-pager --meta", to_string=True)
            r = re.search(r"offsetof\(task_struct, comm\): (0x\S+)", ret)
            if r is not None:
                self.offset_comm = int(r.group(1), 16)
            else:
                warn("ktask is failed")
                self.offset_comm = False

        if self.offset_comm is False:
            return "???"

        comm = read_cstring_from_memory(task_addr + self.offset_comm)
        return comm or "???"

    def dump_current_arm(self):
        orig_thread = gdb.selected_thread()
        threads = gdb.selected_inferior().threads()
        threads = sorted(threads, key=lambda th: th.num)
        for thread in threads:
            thread.switch() # change thread
            task = KernelAddressHeuristicFinder.get_current_task_for_current_thread()
            if is_valid_addr(task):
                cpu_num = thread.num - 1 # ?
                gef_print("current (cpu{:d}): {:#x} {:s}".format(cpu_num, task, self.get_comm_str(task)))
        orig_thread.switch() # revert thread
        return

    def dump_current_x86(self):
        current_task = KernelAddressHeuristicFinder.get_current_task()
        if not current_task:
            if not self.quiet:
                warn("Failed to resolve `current_task`")
            return

        cpu_bases = self.get_cpu_offset()

        if cpu_bases:
            # pattern 1. Offset from __per_cpu_offset.
            if not self.quiet:
                info("current_task: {:#x}".format(current_task))
            task_offset = current_task
            for i, cpu_base in enumerate(cpu_bases):
                task = read_int_from_memory(cpu_base + task_offset)
                if not is_valid_addr(task):
                    break
                gef_print("current (cpu{:d}): {:#x} {:s}".format(i, task, self.get_comm_str(task)))
        else:
            # pattern 2: current_task is the address that stores a pointer to the current task (not per_cpu).
            if not self.quiet:
                info("__per_cpu_offset is unused")
            task = read_int_from_memory(current_task)
            if is_valid_addr(task):
                gef_print("current: {:#x} {:s}".format(task, self.get_comm_str(task)))
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet

        if not self.quiet:
            info("Wait for memory scan")

        if is_arm32() or is_arm64():
            self.dump_current_arm()
        elif is_x86():
            self.dump_current_x86()
        return


@register_command
class KernelTaskCommand(GenericCommand):
    """Display process list."""
    _cmdline_ = "ktask"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--filter", action="append", type=re.compile, default=[],
                        help="REGEXP filter.")
    parser.add_argument("-m", "--print-maps", action="store_true",
                        help="print memory map for each user-land process.")
    parser.add_argument("-r", "--print-regs", action="store_true",
                        help="print general registers saved on kstack for each user-land process.")
    parser.add_argument("-i", "--print-all-id", action="store_true",
                        help="print suid, sgid, euid, egid, fsuid and fsgid.")
    parser.add_argument("-t", "--print-thread", action="store_true",
                        help="display by thread (LWP), not by process.")
    parser.add_argument("-F", "--print-fd", action="store_true",
                        help="print file descriptors for each user process.")
    parser.add_argument("-s", "--print-sighand", action="store_true",
                        help="print signals for each user process.")
    parser.add_argument("-S", "--print-seccomp", action="store_true",
                        help="print seccomp informations for each user process.")
    parser.add_argument("-N", "--print-namespace", action="store_true",
                        help="print namespaces for each user process.")
    parser.add_argument("-u", "--user-process-only", action="store_true",
                        help="display user-land process (+ thread) only.")
    parser.add_argument("--meta", action="store_true", help="display offset information.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -q".format(_cmdline_)

    _note_ = "This command needs CONFIG_RANDSTRUCT=n.\n"
    _note_ += "\n"
    _note_ += "Simplified task_struct structure:\n"
    _note_ += "\n"
    _note_ += "    +-init_task-+\n"
    _note_ += "    | list_head |---+    +-->+-kstack----------+    +--->+-vm_area_struct--+\n"
    _note_ += "    +-----------+   |    |   | (thread_info)   |    |    | vm_start        |\n"
    _note_ += "                    |    |   | STACK_END_MAGIC |    |    | vm_end          |\n"
    _note_ += "+-------------------+    |   | ...             |    |    | vm_next (~6.1)  |\n"
    _note_ += "|                        |   | ...             |    |    | ...             |\n"
    _note_ += "|   +-task_struct---+    |   | ...             |    |    | vm_flags        |\n"
    _note_ += "|   | (thread_info) |    |   | ...             |    |    | vm_file         |-----+\n"
    _note_ += "|   | ...           |    |   | pt_regs         |    |    | ...             |     |\n"
    _note_ += "|   | stack         |----+   +-----------------+    |    +-----------------+     |\n"
    _note_ += "|   | ...           |                               |                            |\n"
    _note_ += "+-->| tasks         |-->...               +---------+<------------------------+  |\n"
    _note_ += "    | ...           |                     |                                   |  |\n"
    _note_ += "    | mm            |-->+-mm_struct----+  |  +-------->+-maple_node(6.1~)--+  |  |\n"
    _note_ += "    | ...           |   | mmap (~6.1)  |--+  |         | ...               |  |  |\n"
    _note_ += "    | pid           |   | ...          |     |         | mr64|ma64|alloc   |  |  |\n"
    _note_ += "    | tid           |   | mm_mt (6.1~) |     |         |   ...             |  |  |\n"
    _note_ += "    | ...           |   |   ma_root    |-----+         |   slot[]          |--+  |\n"
    _note_ += "    | stack_canary  |   | ...          |               +-------------------+     |\n"
    _note_ += "    | ...           |   +--------------+                                         |\n"
    _note_ += "    | group_leader  |                                         +------------------+             +-mount----------+\n"
    _note_ += "    | ...           |         +-->+-cred--------------+       |                                | ...            |\n"
    _note_ += "    | thread_group  |-->...   |   | ...               |       |                                | mnt_parent     |-->mount\n"
    _note_ += "    | ...           |         |   | uid, gid          |       |                                | mnt_mountpoint |-->dentry\n"
    _note_ += "    | cred          |---------+   | suid, sgid        |       |                         +----->| mnt (vfsmount) |\n"
    _note_ += "    | ...           |             | euid, egid        |       |                         |      |   mnt_root     |-->dentry\n"
    _note_ += "    | comm[16]      |             | fsuid, fsgid      |       |                         |      |   ...          |\n"
    _note_ += "    | ...           |             | ..., user_ns, ... |       |                         |      | ...            |\n"
    _note_ += "    | files         |--+          +-------------------+       |                         |      +----------------+\n"
    _note_ += "    | ...           |  |                                      |                         |\n"
    _note_ += "    | nsproxy       |------->+-nsproxy----------------+       |                         | +--->+-dentry-----+\n"
    _note_ += "    | ...           |  |     | count                  |       |                         | |    | ...        |\n"
    _note_ += "    | sighand       |-----+  | uts_ns, ipc_ns, mnt_ns |       |                         | |    | d_parent   |-->dentry\n"
    _note_ += "    | ...           |  |  |  | pid_ns_for_children    |       |                         | |    | ...        |\n"
    _note_ += "    | seccomp       |  |  |  | net_ns, time_ns, ...   |       |                         | |    | d_inode    |--+\n"
    _note_ += "    | ...           |  |  |  +------------------------+       |                         | |    | d_iname    |  |\n"
    _note_ += "    +---------------+  |  |                                   |                         | |    | ...        |  |\n"
    _note_ += "                       |  +->+-sighand_struct----+            |                         | |    +------------+  |\n"
    _note_ += "                       |     | ...               |            v                         | |                    |\n"
    _note_ += "                       |     | action[64]        |            +--->+-file------------+  | | +------------------+\n"
    _note_ += "+----------------------+     +-------------------+            |    | ...             |  | | |\n"
    _note_ += "|                                                             |    | f_path          |  | | v\n"
    _note_ += "+-->+-files_struct-+  +-->+-fdtable---+  +-->+-file*[]-----+  |    |   mnt           |--+ | +->+-inode------+\n"
    _note_ += "    | ...          |  |   | max_fds   |  |   | [0]         |--+    |   dentry        |----+ |  | ...        |\n"
    _note_ += "    | fdt          |--+   | fd        |--+   | ...         |       | f_inode (v3.9~) |------+  | i_ino      |\n"
    _note_ += "    | ...          |      | ...       |      | [max_fds-1] |       | ...             |         | ...        |\n"
    _note_ += "    +--------------+      +-----------+      +-------------+       +-----------------+         +------------+"

    def __init__(self):
        super().__init__()
        # task_struct
        self.offset_tasks = None
        self.offset_mm = None
        self.offset_stack = None
        self.offset_pid = None
        self.offset_kcanary = None
        self.offset_group_leader = None
        self.offset_thread_group = None
        self.offset_comm = None
        self.offset_cred = None
        self.offset_files = None
        self.offset_sighand = None
        self.offset_nsproxy = None
        self.offset_signal = None
        self.offset_seccomp = None
        # files_struct
        self.offset_fdt = None
        # kstack
        self.offset_ptregs = None
        # cred
        self.offset_uid = None
        self.offset_user_ns = None
        # vm_area_struct
        self.offset_vm_mm = None
        self.offset_vm_flags = None
        self.offset_vm_file = None
        # file
        self.offset_mnt = None
        self.offset_dentry = None
        # dentry
        self.offset_d_iname = None
        self.offset_d_parent = None
        self.offset_d_inode = None
        # inode
        self.offset_i_ino = None
        # signal
        self.offset_thread_head = None
        # sighand_struct
        self.offset_action = None
        self.sizeof_action = None
        # seccomp_filter
        self.offset_prev = None
        self.offset_prog = None
        # bpf_prog
        self.offset_bpf_func = None
        self.offset_orig_prog = None
        return

    def quiet_info(self, msg):
        if not self.quiet:
            msg = "{} {}".format(Color.colorify("[+]", "bold blue"), msg)
            gef_print(msg)
        return

    def quiet_err(self, msg):
        if not self.quiet:
            msg = "{} {}".format(Color.colorify("[+]", "bold red"), msg)
            gef_print(msg)
        return

    def get_offset_tasks(self, init_task):
        # search init_task->tasks
        for i in range(0x200):
            offset_tasks = current_arch.ptrsize * i
            pos1 = init_task + offset_tasks
            pos2 = init_task + offset_tasks + current_arch.ptrsize
            list1 = [pos1]
            list2 = [pos2]
            # validating candidate offset
            while True:
                # read check
                if not is_valid_addr(pos1) or not is_valid_addr(pos2):
                    found = False
                    break
                pos1 = read_int_from_memory(pos1)
                pos2 = read_int_from_memory(pos2) + current_arch.ptrsize
                # list validate
                if pos1 in list1[1:] or pos2 in list2[1:]: # incomplete infinity loop detected
                    found = False
                    break
                if (pos1 == list1[0] and len(list1) == 1) or (pos2 == list2[0] and len(list2) == 1): # self reference
                    found = False
                    break
                if (pos1 == list1[0] and len(list1) > 5) and (pos2 == list2[0] and len(list2) > 5): # maybe link list
                    found = True
                    break
                list1.append(pos1)
                list2.append(pos2)
            if found:
                return offset_tasks
        return None

    def get_task_list(self, init_task, offset_tasks):
        pos = init_task + offset_tasks
        task_list = [pos]
        # validating candidate offset
        while True:
            try:
                pos = read_int_from_memory(pos)
            except gdb.MemoryError:
                return None
            if pos in task_list:
                break
            task_list.append(pos)
        return [x - offset_tasks for x in task_list]

    def get_offset_mm(self, task_addr, offset_tasks):
        """
        struct task_struct {
            ...
            struct list_head tasks;
        #ifdef CONFIG_SMP
            struct plist_node {
                int prio;
                struct list_head prio_list;
                struct list_head node_list;
            } pushable_tasks;
            struct rb_node {
                unsigned long __rb_parent_color;
                struct rb_node *rb_right;
                struct rb_node *rb_left;
            } pushable_dl_tasks; // v3.14~
        #endif
            struct mm_struct *mm;
            struct mm_struct *active_mm;
            ...
        };
        """
        offset_mm = offset_tasks + 2 * current_arch.ptrsize
        r = read_int_from_memory(task_addr + offset_mm)
        if 0 < r <= 0xffffffff:
            # maybe prio, so CONFIG_SMP is y
            kversion = Kernel.kernel_version()
            if kversion >= "3.14":
                offset_mm = offset_tasks + 10 * current_arch.ptrsize
            else:
                offset_mm = offset_tasks + 7 * current_arch.ptrsize
        return offset_mm

    def get_offset_comm(self, task_addrs):
        for i in range(0x300):
            offset_comm = i * current_arch.ptrsize
            valid = True
            for task in task_addrs:
                if not is_ascii_string(task + offset_comm):
                    valid = False
                    break
                s = read_cstring_from_memory(task + offset_comm)
                if s == "swapper/0": # Very common name, so for speeding up, we assume that offset is found
                    break
                if len(s) < 2:
                    valid = False
                    break
            if valid:
                return offset_comm
        return None

    def get_offset_cred(self, task_addrs, offset_comm):
        """
        struct task_struct {
            ...
            const struct cred __rcu *real_cred; // These may point to the same address
            const struct cred __rcu *cred;      // These may point to the same address
        #ifdef CONFIG_KEYS
            struct key *cached_requested_key;
        #endif
            char comm[TASK_COMM_LEN];
            ...
        };
        """
        # backward search from `comm`
        for i in range(0x2):
            offset_cred = offset_comm - ((i + 1) * current_arch.ptrsize)
            for task in task_addrs:
                val1 = read_int_from_memory(task + offset_cred)
                val2 = read_int_from_memory(task + offset_cred - current_arch.ptrsize)
                if val1 == val2 and val1 != 0:
                    return offset_cred
        return None

    def get_offset_stack(self, task_addrs):
        """
        struct task_struct {
            ...
        #ifdef CONFIG_THREAD_INFO_IN_TASK
            struct thread_info thread_info;
        #endif
            volatile long state;
            void *stack;
            ...
        };
        """
        for i in range(0x100):
            found = False
            zcount = 0
            for task in task_addrs:
                v = read_int_from_memory(task + current_arch.ptrsize * i)
                if v == 0:
                    zcount += 1
                    continue
                if (v & 0x1fff) != 0:
                    break
                if not is_valid_addr(v):
                    break
            else:
                found = True

            # I don't know why, but it seems that sometimes you have a process that has no stack.
            # 0xffffa122c17db000 U   106     chal.sh ... 0xffffa43100218000 0xd16ef01535a35500
            # 0xffffa122c17da000 U   108     socat   ... 0xffffa43100278000 0x3d378b9e6f59bf00
            # 0xffffa122c17dc000 U   109     chal    ... 0xffffa431002d4000 0x277c67d5e5854500
            # 0xffffa122c17dd000 K   110     3       ... 0x0000000000000000 0x22a999743f180500
            # So I decided to allow a few NULL pointer.
            if zcount > len(task_addrs) // 10:
                found = False

            if found is False:
                continue

            offset_stack = current_arch.ptrsize * i
            return offset_stack
        return None

    def get_thread_info(self, task_addr, offset_stack):
        kstack = read_int_from_memory(task_addr + offset_stack)
        stack_top_val = u32(read_memory(kstack, 4))
        if stack_top_val == 0x57ac6e9d: # STACK_END_MAGIC
            """
            struct task_struct {
            #ifdef CONFIG_THREAD_INFO_IN_TASK
                struct thread_info thread_info;
            #endif
                ...
            """
            return task_addr # CONFIG_THREAD_INFO_IN_TASK=y
        else:
            return kstack # CONFIG_THREAD_INFO_IN_TASK=n

    def has_seccomp(self, task_addr):
        thread_info = self.get_thread_info(task_addr, self.offset_stack)
        kversion = Kernel.kernel_version()
        if is_x86():
            if kversion >= "5.11":
                syscall_work = read_int_from_memory(thread_info + current_arch.ptrsize)
                return bool(syscall_work & (1 << 0)) # SYSCALL_WORK_SECCOMP
            elif kversion >= "4.9":
                flags = read_int_from_memory(thread_info)
                return bool(flags & (1 << 8)) # TIF_SECCOMP
            elif kversion >= "4.1":
                flags = u32(read_memory(thread_info + current_arch.ptrsize, 4))
                return bool(flags & (1 << 8)) # TIF_SECCOMP
            else:
                flags = u32(read_memory(thread_info + current_arch.ptrsize * 2, 4))
                return bool(flags & (1 << 8)) # TIF_SECCOMP
        elif is_arm32():
            if kversion >= "6.0":
                flags = read_int_from_memory(thread_info)
                return bool(flags & (1 << 23)) # TIF_SECCOMP
            elif kversion >= "5.16":
                flags = read_int_from_memory(thread_info)
                return bool(flags & (1 << 7)) # TIF_SECCOMP
            elif kversion >= "5.15":
                flags = read_int_from_memory(thread_info)
                return bool(flags & (1 << 23)) # TIF_SECCOMP
            elif kversion >= "5.11":
                flags = read_int_from_memory(thread_info)
                return bool(flags & (1 << 7)) # TIF_SECCOMP
            elif kversion >= "5.10":
                flags = read_int_from_memory(thread_info)
                return bool(flags & (1 << 23)) # TIF_SECCOMP
            elif kversion >= "4.3":
                flags = read_int_from_memory(thread_info)
                return bool(flags & (1 << 7)) # TIF_SECCOMP
            elif kversion >= "3.8":
                flags = read_int_from_memory(thread_info)
                return bool(flags & (1 << 11)) # TIF_SECCOMP
            else:
                flags = read_int_from_memory(thread_info)
                return bool(flags & (1 << 21)) # TIF_SECCOMP
        elif is_arm64():
            if kversion >= "3.16":
                flags = read_int_from_memory(thread_info)
                return bool(flags & (1 << 11)) # TIF_SECCOMP
            else:
                # unimplemented
                return None
        return None

    def get_offset_ptregs(self, task_addrs, offset_stack):
        # calc kstack address pattern
        kstacks_raw = []
        for task in task_addrs:
            kstack = read_int_from_memory(task + offset_stack)
            kstacks_raw.append(kstack)

        # calc kstack size
        kstacks = sorted({x & 0xffff for x in kstacks_raw}) # uniq and sort
        diffs = []
        for i in range(len(kstacks) - 1):
            diff = kstacks[i + 1] - kstacks[i]
            diffs.append(diff)
        if len(diffs) == 0:
            kstack_size = gef_getpagesize() * 2
        else:
            kstack_size = min(diffs)

        # check
        while True:
            for kstack in kstacks_raw:
                if not is_valid_addr(kstack + kstack_size - current_arch.ptrsize):
                    kstack_size //= 2
                    break # for, then retry while
            else:
                break # while

        if is_x86_64():
            """
            struct pt_regs {
                unsigned long r15;
                unsigned long r14;
                unsigned long r13;
                unsigned long r12;
                unsigned long rbp;
                unsigned long rbx;
                unsigned long r11;
                unsigned long r10;
                unsigned long r9;
                unsigned long r8;
                unsigned long rax;
                unsigned long rcx;
                unsigned long rdx;
                unsigned long rsi;
                unsigned long rdi;
                unsigned long orig_rax;
                unsigned long rip;
                unsigned long cs;
                unsigned long eflags;
                unsigned long rsp;
                unsigned long ss;
            };
            """
            ptregs_size = current_arch.ptrsize * 21
            bottom_offset = 0
        elif is_x86_32():
            """
            struct pt_regs {
                long ebx;
                long ecx;
                long edx;
                long esi;
                long edi;
                long ebp;
                long eax;
                int xds;
                int xes;
                int xfs;
                int xgs;
                long orig_eax;
                long eip;
                int xcs;
                long eflags;
                long esp;
                int xss;
            };
            """
            ptregs_size = current_arch.ptrsize * 17
            bottom_offset = current_arch.ptrsize * 2 # ?
        elif is_arm64():
            """
            struct pt_regs {
                u64 regs[31];
                u64 sp;
                u64 pc;
                u64 pstate;
                u64 orig_x0;
                u64 syscallno;
                u64 orig_addr_limit;
                u64 pmr_save;
                u64 stackframe[2];
                u64 lockdep_hardirqs;
                u64 exit_rcu;
            };
            """
            ptregs_size = current_arch.ptrsize * 35
            bottom_offset = current_arch.ptrsize * 7
        elif is_arm32():
            """
            struct pt_regs {
                unsigned long uregs[18];
            };
            """
            ptregs_size = current_arch.ptrsize * 18
            bottom_offset = current_arch.ptrsize * 2 # ?
        else:
            return None

        offset_ptregs = kstack_size - ptregs_size - bottom_offset
        return kstack_size, offset_ptregs

    def get_regs(self, kstack, offset_ptregs):
        if is_x86_64():
            regs_name = [
                "r15", "r14", "r13", "r12", "rbp", "rbx", "r11", "r10",
                "r9", "r8", "rax", "rcx", "rdx", "rsi", "rdi", "orig_rax",
                "rip", "cs", "eflags", "rsp", "ss",
            ]
        elif is_x86_32():
            regs_name = [
                "ebx", "ecx", "edx", "esi", "edi", "ebp", "eax", "ds",
                "es", "fs", "gs", "orig_eax", "eip", "cs", "eflags", "esp", "ss",
            ]
        elif is_arm64():
            regs_name = [
                "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
                "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
                "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
                "x24", "x25", "x26", "x27", "x28", "x29", "x30",
                "sp", "pc", "pstate", "orig_x0",
            ]
        elif is_arm32():
            regs_name = [
                "r0", "r1", "r2", "r3", "r4", "r5", "r6",
                "r7", "r8", "r9", "r10", "r11", "r12",
                "sp", "lr", "pc", "cpsr", "orig_r0",
            ]

        ptregs_addr = kstack + offset_ptregs
        ptregs_size = len(regs_name) * current_arch.ptrsize
        regs_data = read_memory(ptregs_addr, ptregs_size)

        # maybe kernel thread
        if is_x86():
            if regs_data == b"\0" * len(regs_data):
                return None
        elif is_arm32():
            kernel_thread_regs = p32(0) * (len(regs_name) - 2) + p32(0x13) + p32(0)
            if regs_data == kernel_thread_regs:
                return None
        elif is_arm64():
            kernel_thread_regs = p64(0) * (len(regs_name) - 2) + p64(0x5) + p64(0)
            if regs_data == kernel_thread_regs:
                return None

        # get regs value
        regs_data = slice_unpack(regs_data, current_arch.ptrsize)
        regs = {}
        for name, value in zip(regs_name, regs_data):
            regs[name] = value
        return regs

    def get_offset_pid(self, task_addrs):
        """
        struct task_struct {
            ...
            pid_t pid;
            pid_t tgid;
            ...
        };

        0xc6d1e888:     0xc6d1f048      0xc6d1c1c8      0x0000008c      0xc6d1e894
        0xc6d1e898:     0xc6d1e894      0xc6d1e89c      0xc6d1e89c      0xc6d1e8a4
        0xc6d1e8a8:     0x00000000      0x00000000      0xc7830660      0xc7830660
        0xc6d1e8b8:     0x00000008      0x00000000      0xc6d51300      0x00000000
        0xc6d1e8c8:     0x00000000      0xc6d514e0      0x00000017      0x000000a9
        0xc6d1e8d8:     0x00000005      0x00000000      0x00000000      0x00000000
        0xc6d1e8e8:     0x00000000      0x00000011      0x00000000      0x00000000
        0xc6d1e8f8:     0x00000000      0x00000000      0x00000000      0x00000000
        0xc6d1e908:     0xc245a8d0      0x00000000      0x00000000      0x00000000
        0xc6d1e918:     0x00000000      0x00000000      0x00000000      0x00000000
        0xc6d1e928:     0x00000031*     0x00000031      0xc7834000      0xc7834000
        """
        pid_max = 0x400000 if is_64bit() else 0x8000
        for i in range(0x400):
            found = False
            seen_pid = []
            for task in task_addrs[1:]: # swapper/0 has pid 0. Don't use it as it will cause false positives.
                v1 = u32(read_memory(task + (i + 0) * 4, 4))
                v2 = u32(read_memory(task + (i + 1) * 4, 4))
                if v1 == 0 or pid_max < v1: # pid is 1 ~ pid_max
                    break
                if v2 == 0 or pid_max < v2: # tgid is 1 ~ pid_max
                    break
                if v1 in seen_pid:
                    break
                seen_pid.append(v1)
            else:
                found = True

            if found is False:
                continue

            offset_pid = i * 4
            return offset_pid
        return None

    def get_offset_canary(self, task_addrs, offset_pid):
        """
        struct task_struct {
            ...
            pid_t pid;
            pid_t tgid;
        #ifdef CONFIG_STACKPROTECTOR
            unsigned long stack_canary;
        #endif
            struct task_struct __rcu *real_parent;
            struct task_struct __rcu *parent;
            ...
        };
        """
        kversion = Kernel.kernel_version()
        offset_stack_canary = AddressUtil.align_address_to_size(offset_pid + 4 + 4, current_arch.ptrsize)
        found = True
        for task in task_addrs:
            v1 = read_int_from_memory(task + offset_stack_canary)
            v2 = read_int_from_memory(task + offset_stack_canary + current_arch.ptrsize)

            if v1 == v2: # stack canary != real_parent
                found = False
                break

            if kversion and kversion >= "4.13":
                if is_64bit() and (v1 & 0xff) != 0: # 32-bit canary does not have 0xXXXXXX00
                    found = False
                    break

        if found:
            return offset_stack_canary
        else:
            return None

    def get_offset_group_leader(self, offset_pid, offset_kcanary):
        """
        struct task_struct {
            ...
            pid_t pid;
            pid_t tgid;
        #ifdef CONFIG_STACKPROTECTOR
            unsigned long stack_canary;
        #endif
            struct task_struct __rcu *real_parent;
            struct task_struct __rcu *parent;
            struct list_head children;
            struct list_head sibling;
            struct task_struct *group_leader;
            ...
        };
        """
        if offset_kcanary is None:
            offset_real_parent = AddressUtil.align_address_to_size(offset_pid + 4 + 4, current_arch.ptrsize)
        else:
            offset_real_parent = offset_kcanary + current_arch.ptrsize
        offset_group_leader = offset_real_parent + current_arch.ptrsize * (1 + 1 + 2 + 2)
        return offset_group_leader

    def get_offset_thread_group(self, offset_group_leader):
        """
        struct task_struct {
            ...
            struct task_struct *group_leader;
            struct list_head ptraced;
            struct list_head ptrace_entry;
            struct pid *thread_pid;           // v4.19~
            struct hlist_node pid_links[4];   // v4.19~
            struct pid_link pids[3];          // ~v4.19
            struct list_head thread_group;
            ...
        };
        """
        kversion = Kernel.kernel_version()
        if kversion >= "4.19":
            offset_thread_group = offset_group_leader + current_arch.ptrsize * (1 + 2 + 2 + 1 + (2 * 4))
        else:
            offset_thread_group = offset_group_leader + current_arch.ptrsize * (1 + 2 + 2 + (3 * 3))
        return offset_thread_group

    def get_offset_signal(self, offset_nsproxy):
        """
        struct task_struct {
            ...
            struct nsproxy *nsproxy;
            struct signal_struct *signal;
            ...
        };
        """
        return offset_nsproxy + current_arch.ptrsize

    def get_offset_seccomp(self, task_addrs, offset_signal):
        """
        struct task_struct {
            ...
            struct signal_struct *signal;
            struct sighand_struct __rcu *sighand;
            sigset_t blocked;
            sigset_t real_blocked;
            sigset_t saved_sigmask;
            struct sigpending {
                struct list_head list;
                sigset_t signal;
            } pending;
            unsigned long sas_ss_sp;
            size_t sas_ss_size;
            unsigned int sas_ss_flags;
            struct callback_head *task_works;
        #ifdef CONFIG_AUDIT
        #ifdef CONFIG_AUDITSYSCALL
            struct audit_context *audit_context;
        #endif
            kuid_t loginuid;
            unsigned int sessionid;
        #endif
            struct seccomp {
                int mode;
                atomic_t filter_count;
                struct seccomp_filter *filter;
            } seccomp;
            ...
        }
        """

        # search seccomped process
        for task in task_addrs:
            if self.has_seccomp(task):
                seccomped_task = task
                break
        else:
            # Not found
            return None

        """
        0xffff99353fe721d8|+0x0000|+000: 0xffff99353fe6e600 <- &task_struct.signal
        0xffff99353fe721e0|+0x0008|+001: 0x0000000000004002
        0xffff99353fe721e8|+0x0010|+002: 0x0000000000000000
        0xffff99353fe721f0|+0x0018|+003: 0x0000000000000000
        0xffff99353fe721f8|+0x0020|+004: 0xffff99353fe721f8 <- &task_struct.pending.list
        0xffff99353fe72200|+0x0028|+005: 0xffff99353fe721f8
        0xffff99353fe72208|+0x0030|+006: 0x0000000000000000
        0xffff99353fe72210|+0x0038|+007: 0x0000000000000000
        0xffff99353fe72218|+0x0040|+008: 0x0000000000000000
        0xffff99353fe72220|+0x0048|+009: 0x0000000000000002
        0xffff99353fe72228|+0x0050|+010: 0x0000000000000000
        0xffff99353fe72230|+0x0058|+011: 0x0000000000000000
        0xffff99353fe72238|+0x0060|+012: 0xffffffffffffffff
        0xffff99353fe72240|+0x0068|+013: 0x0000002300000002 <- &task_struct.seccomp
        0xffff99353fe72248|+0x0070|+014: 0xffff9934c39e2300 <- &task_struct.seccomp.filter
        0xffff99353fe72250|+0x0078|+015: 0x0000000000000003
        0xffff99353fe72258|+0x0080|+016: 0x0000000000000004
        """
        # search sigpending
        base = offset_signal + current_arch.ptrsize
        for i in range(0x100):
            if is_double_link_list(seccomped_task + base + current_arch.ptrsize * i):
                base += current_arch.ptrsize * i * 2
                break
        else:
            # Not found sigpending
            return None

        # search seccomp
        for i in range(0x100):
            offset_filter = base + current_arch.ptrsize * i

            filt = read_int_from_memory(seccomped_task + offset_filter)
            if not is_valid_addr(filt):
                continue

            mode = u32(read_memory(seccomped_task + offset_filter - 4, 4))
            filtcnt = u32(read_memory(seccomped_task + offset_filter - 4 * 2, 4))

            """
            #define SECCOMP_MODE_DISABLED 0
            #define SECCOMP_MODE_STRICT   1
            #define SECCOMP_MODE_FILTER   2
            """
            if mode == 0 or filtcnt == 0:
                continue
            offset_seccomp = offset_filter - 4 * 2
            return offset_seccomp

        return None

    def get_offset_prev(self, task_addrs, offset_seccomp):
        if offset_seccomp is None:
            return None

        """
        struct seccomp_filter {
            refcount_t refs; // 5.9~
            refcount_t users; // 5.9~
            refcount_t usage; // ~5.9
            bool log; // 4.14~
            bool wait_killable_recv; // 5.19~
            struct action_cache cache; // 5.11~
            struct seccomp_filter *prev;
            struct bpf_prog *prog;
            ...
        """

        for task in task_addrs:
            if not self.has_seccomp(task):
                continue

            mode = u32(read_memory(task + self.offset_seccomp, 4))
            if mode != 2: # SECCOMP_MODE_FILTER
                continue

            filter_count = u32(read_memory(task + self.offset_seccomp + 4, 4))
            if filter_count == 0:
                continue # something is wrong

            filter_ = read_int_from_memory(task + self.offset_seccomp + 4 + 4)
            for i in range(0x100):
                # prev
                x = read_int_from_memory(filter_ + current_arch.ptrsize * i)
                if (x & 0x7) or not is_valid_addr(x): # must aligned
                    continue
                # prog
                y = read_int_from_memory(filter_ + current_arch.ptrsize * (i + 1))
                if (y & 0x7) or not is_valid_addr(y): # must aligned
                    continue

                if filter_count == 1:
                    return current_arch.ptrsize * (i - 1) # prev is NULL
                else:
                    return current_arch.ptrsize * i # prev is non-NULL
        return None

    def get_offset_prog(self, offset_prev):
        if offset_prev is None:
            return None

        kversion = Kernel.kernel_version()
        if kversion < "3.16":
            return None

        return offset_prev + current_arch.ptrsize

    def get_offset_bpf_func(self, task_addrs, offset_seccomp, offset_prog):
        if offset_seccomp is None:
            return None
        if offset_prog is None:
            return None

        def is_executable(x):
            maps = Kernel.get_maps()
            for start, size, perm in maps:
                if start <= x and x < start + size:
                    return perm.endswith("X")
            return False

        for task in task_addrs:
            if not self.has_seccomp(task):
                continue

            filter_ = read_int_from_memory(task + offset_seccomp + 4 + 4)
            bpf_prog = read_int_from_memory(filter_ + offset_prog)
            for i in range(0x100):
                x = read_int_from_memory(bpf_prog + current_arch.ptrsize * i)
                if is_valid_addr(x) and is_executable(x):
                    if read_int_from_memory(x) == 0: # something is wrong
                        continue
                    return current_arch.ptrsize * i
        return None

    def get_offset_orig_prog(self, offset_bpf_func):
        if offset_bpf_func is None:
            return None

        kversion = Kernel.kernel_version()
        if kversion >= "5.12":
            return offset_bpf_func + current_arch.ptrsize * 2
        elif kversion >= "4.1":
            return offset_bpf_func - current_arch.ptrsize
        elif kversion >= "3.18":
            return offset_bpf_func - current_arch.ptrsize * 2
        elif kversion >= "3.16":
            return offset_bpf_func - current_arch.ptrsize
        return None

    def get_offset_thread_head(self, task_addr, offset_signal):
        """
        struct signal_struct {
            refcount_t sigcnt;
            atomic_t live;
            int nr_threads;
            int quick_threads;
            struct list_head thread_head;
            ...
        };
        """
        signal = read_int_from_memory(task_addr + offset_signal)
        for i in range(10):
            x = read_int_from_memory(signal + current_arch.ptrsize * i)
            y = read_int_from_memory(signal + current_arch.ptrsize * (i + 1))
            if is_valid_addr(x) and is_valid_addr(y):
                offset_thread_head = current_arch.ptrsize * i
                return offset_thread_head
        return None

    def get_offset_files(self, task_addrs, offset_comm):
        """
        struct task_struct {
            ...
            char comm[TASK_COMM_LEN];
            struct nameidata *nameidata;
        #ifdef CONFIG_SYSVIPC
            struct sysv_sem {
                struct sem_undo_list *undo_list;
            } sysvsem;
            struct sysv_shm {
                struct list_head shm_clist;
            } sysvshm;
        #endif
        #ifdef CONFIG_DETECT_HUNG_TASK
            unsigned long last_switch_count;
            unsigned long last_switch_time;
        #endif
            struct thread_struct thread; // ~v4.2
            struct fs_struct *fs;
            struct files_struct *files; <-------- here
            ...
        };
        """
        base = offset_comm + 16 # comm
        base += current_arch.ptrsize # nameidata
        kversion = Kernel.kernel_version()
        if kversion >= "4.2":
            repeat_times = 6
        else:
            # sizeof(struct thread_struct) is very large, need more exproring
            repeat_times = 100
        for i in range(repeat_times):
            # check fs
            v1 = read_int_from_memory(task_addrs[0] + base + current_arch.ptrsize * i)
            if not is_valid_addr(v1):
                continue
            if is_valid_addr(read_int_from_memory(v1)):
                continue
            # check files
            v2 = read_int_from_memory(task_addrs[0] + base + current_arch.ptrsize * (i + 1))
            if not is_valid_addr(v2):
                continue
            if is_valid_addr(read_int_from_memory(v2)):
                continue
            # found
            offset_files = base + current_arch.ptrsize * (i + 1)
            return offset_files
        return None

    def get_offset_fdt(self, task_addrs, offset_files):
        """
        struct files_struct {
            atomic_t count;
            bool resize_in_progress;
            wait_queue_head_t resize_wait;
            struct fdtable __rcu *fdt; <------- here
            struct fdtable {
                unsigned int max_fds;
                struct file __rcu **fd;
                unsigned long *close_on_exec;
                unsigned long *open_fds;
                unsigned long *full_fds_bits;
                struct rcu_head rcu;
            } fdtab;
            ...
        };
        """
        MAX_FDS_DEFAULT = AddressUtil.get_memory_alignment(in_bits=True)
        files = read_int_from_memory(task_addrs[0] + offset_files)
        for i in range(0x100):
            v = read_int_from_memory(files + current_arch.ptrsize * i)
            if v != MAX_FDS_DEFAULT:
                continue
            offset_fdt = current_arch.ptrsize * (i - 1)
            return offset_fdt
        return None

    def get_offset_uid(self, init_task_cred_ptr):
        """
        struct cred {
            atomic_t usage;
        #ifdef CONFIG_DEBUG_CREDENTIALS
            atomic_t subscribers;
            void *put_addr;
            unsigned magic;
        #endif
            kuid_t uid;
            kgid_t gid;
            kuid_t suid;
            kgid_t sgid;
            kuid_t euid;
            kgid_t egid;
            kuid_t fsuid;
            kgid_t fsgid;
            unsigned securebits;
            kernel_cap_t cap_inheritable;
            kernel_cap_t cap_permitted;
            kernel_cap_t cap_effective;
            kernel_cap_t cap_bset;
            kernel_cap_t cap_ambient;
            ...
        };

        [Example x64]
            0xffffffff820460c0:     0x0000000000000004      0x0000000000000000
            0xffffffff820460d0:     0x0000000000000000      0x0000000000000000
            0xffffffff820460e0:     0x0000000000000000      0x0000000000000000
            0xffffffff820460f0:     0x0000003fffffffff      0x0000003fffffffff
            0xffffffff82046100:     0x0000003fffffffff      0x0000000000000000
            0xffffffff82046110:     0x0000000000000000      0x0000000000000000
        """
        init_task_cred = read_int_from_memory(init_task_cred_ptr)
        uid_gid_size = 4 * 8 # uid_t:4byte. len([uid,gid,suid,sgid,euid,egid,fsuid,fsgid]) == 8
        offset_uid = 4
        ret = read_memory(init_task_cred + offset_uid, uid_gid_size)
        if ret == b"\0" * uid_gid_size:
            pass
        else:
            offset_uid += 4 + current_arch.ptrsize + 4
        return offset_uid

    def get_offset_user_ns(self, init_task_cred_ptr, offset_uid):
        """
        struct cred {
            ...
            kernel_cap_t cap_bset;
            kernel_cap_t cap_ambient; // v4.3~
        #ifdef CONFIG_KEYS
            unsigned char jit_keyring;
            struct key *session_keyring;
            struct key *process_keyring;
            struct key *thread_keyring;
            struct key *request_key_auth;
        #endif
        #ifdef CONFIG_SECURITY
            void *security;
        #endif
            struct user_struct *user;
            struct user_namespace *user_ns;
            struct group_info *group_info;
            union {
                int non_rcu;
                struct rcu_head rcu;
            };
        } __randomize_layout;

        [Example x64; CONFIG_KEYS=y, CONFIG_SECURITY=y]
        0xffffffffbb454580|+0x0000|+000: 0x0000000000000004
        0xffffffffbb454588|+0x0008|+001: 0x0000000000000000
        0xffffffffbb454590|+0x0010|+002: 0x0000000000000000
        0xffffffffbb454598|+0x0018|+003: 0x0000000000000000
        0xffffffffbb4545a0|+0x0020|+004: 0x0000000000000000
        0xffffffffbb4545a8|+0x0028|+005: 0x0000000000000000
        0xffffffffbb4545b0|+0x0030|+006: 0x000001ffffffffff
        0xffffffffbb4545b8|+0x0038|+007: 0x000001ffffffffff
        0xffffffffbb4545c0|+0x0040|+008: 0x000001ffffffffff  // cap_bset
        0xffffffffbb4545c8|+0x0048|+009: 0x0000000000000000  // cap_ambilent
        0xffffffffbb4545d0|+0x0050|+010: 0x0000000000000000  // jit_keyring
        0xffffffffbb4545d8|+0x0058|+011: 0x0000000000000000  // session_keyring
        0xffffffffbb4545e0|+0x0060|+012: 0x0000000000000000  // process_keyring
        0xffffffffbb4545e8|+0x0068|+013: 0x0000000000000000  // thread_keyring
        0xffffffffbb4545f0|+0x0070|+014: 0x0000000000000000  // request_key_auth
        0xffffffffbb4545f8|+0x0078|+015: 0xffff998d8106cb68  ->  0xffff998d81052eb0  ->  0x0000000000000241 // security
        0xffffffffbb454600|+0x0080|+016: 0xffffffffbb44c6c0  ->  0x0000004e00000075 // user
        0xffffffffbb454608|+0x0088|+017: 0xffffffffbb44c740  ->  0x0000000000000001 // user_ns

        [Example x64; CONFIG_KEYS=y, CONFIG_SECURITY=y]
        0xffff9ec6c88379c0|+0x0000|+000: 0x000000000000000a
        0xffff9ec6c88379c8|+0x0008|+001: 0x0000000000000000
        0xffff9ec6c88379d0|+0x0010|+002: 0x0000000000000000
        0xffff9ec6c88379d8|+0x0018|+003: 0x0000000000000000
        0xffff9ec6c88379e0|+0x0020|+004: 0x0000000000000000
        0xffff9ec6c88379e8|+0x0028|+005: 0x0000000000000000
        0xffff9ec6c88379f0|+0x0030|+006: 0x000001ffffffffff
        0xffff9ec6c88379f8|+0x0038|+007: 0x000001ffffffffff
        0xffff9ec6c8837a00|+0x0040|+008: 0x000001ffffffffff  // cap_bset
        0xffff9ec6c8837a08|+0x0048|+009: 0x0000000000000000  // cap_ambient
        0xffff9ec6c8837a10|+0x0050|+010: 0x0000000000000000  // jit_keyring
        0xffff9ec6c8837a18|+0x0058|+011: 0xffff9ec6c4643700  ->  0x182031ce00000006 // session_keyring
        0xffff9ec6c8837a20|+0x0060|+012: 0x0000000000000000  // process_keyring
        0xffff9ec6c8837a28|+0x0068|+013: 0x0000000000000000  // thread_keyring
        0xffff9ec6c8837a30|+0x0070|+014: 0x0000000000000000  // request_key_auth
        0xffff9ec6c8837a38|+0x0078|+015: 0xffff9ec6c8873fe0  ->  0xffff9ec6c1052eb0  ->  0x00000000000002e8 // security
        0xffff9ec6c8837a40|+0x0080|+016: 0xffffffffbb64c5c0  ->  0x0000004f00000084 // user
        0xffff9ec6c8837a48|+0x0088|+017: 0xffff9ec6c820eaa0  ->  0x0000000000000001 // user_ns

        [Example ARM64; CONFIG_KEYS=n, CONFIG_SECURITY=y]
        0xffffd9e53efef538|+0x0000|+000: 0x0000000000000004
        0xffffd9e53efef540|+0x0008|+001: 0x0000000000000000
        0xffffd9e53efef548|+0x0010|+002: 0x0000000000000000
        0xffffd9e53efef550|+0x0018|+003: 0x0000000000000000
        0xffffd9e53efef558|+0x0020|+004: 0x0000000000000000
        0xffffd9e53efef560|+0x0028|+005: 0x0000000000000000
        0xffffd9e53efef568|+0x0030|+006: 0x000001ffffffffff
        0xffffd9e53efef570|+0x0038|+007: 0x000001ffffffffff
        0xffffd9e53efef578|+0x0040|+008: 0x000001ffffffffff  // cap_bset
        0xffffd9e53efef580|+0x0048|+009: 0x0000000000000000  // cap_ambient
        0xffffd9e53efef588|+0x0050|+010: 0x0000000000000000  // security
        0xffffd9e53efef590|+0x0058|+011: 0xffffd9e53efeeb10  ->  0x000000000000002a // user
        0xffffd9e53efef598|+0x0060|+012: 0xffffd9e53efeeb98  ->  0x0000000000000001 // user_ns

        [Example x86; CONFIG_KEYS=y, CONFIG_SECURITY=y]
        0xc1aabbe0|+0x0000|+000: 0x00000004
        0xc1aabbe4|+0x0004|+001: 0x00000000
        0xc1aabbe8|+0x0008|+002: 0x00000000
        0xc1aabbec|+0x000c|+003: 0x00000000
        0xc1aabbf0|+0x0010|+004: 0x00000000
        0xc1aabbf4|+0x0014|+005: 0x00000000
        0xc1aabbf8|+0x0018|+006: 0x00000000
        0xc1aabbfc|+0x001c|+007: 0x00000000
        0xc1aabc00|+0x0020|+008: 0x00000000
        0xc1aabc04|+0x0024|+009: 0x00000000
        0xc1aabc08|+0x0028|+010: 0x00000000
        0xc1aabc0c|+0x002c|+011: 0x00000000
        0xc1aabc10|+0x0030|+012: 0xffffffff
        0xc1aabc14|+0x0034|+013: 0x000001ff
        0xc1aabc18|+0x0038|+014: 0xffffffff
        0xc1aabc1c|+0x003c|+015: 0x000001ff
        0xc1aabc20|+0x0040|+016: 0xffffffff  // cap_bset
        0xc1aabc24|+0x0044|+017: 0x000001ff
        0xc1aabc28|+0x0048|+018: 0x00000000  // cap_abmient
        0xc1aabc2c|+0x004c|+019: 0x00000000
        0xc1aabc30|+0x0050|+020: 0x00000000  // jit_keyring
        0xc1aabc34|+0x0054|+021: 0x00000000  // session_keyring
        0xc1aabc38|+0x0058|+022: 0x00000000  // process_keyring
        0xc1aabc3c|+0x005c|+023: 0x00000000  // thread_keyring
        0xc1aabc40|+0x0060|+024: 0x00000000  // request_key_auth
        0xc1aabc44|+0x0064|+025: 0xc201e8b0  ->  0xc20ecd94  ->  0x00000234 // security
        0xc1aabc48|+0x0068|+026: 0xc1aa6b80  ->  0x00000068 // user
        0xc1aabc4c|+0x006c|+027: 0xc1aa6be0  ->  0x00000001 // user_ns
        """
        kversion = Kernel.kernel_version()
        uid_gid_size = 4 * 8 # uid_t:4byte. len([uid,gid,suid,sgid,euid,egid,fsuid,fsgid]) == 8
        sizeof_securebits = 4
        if kversion >= "4.3":
            cap_size = 8 * 5 # cap_t:8byte. len([cap_inheritable,cap_permitted,cap_effective,cap_bset,cap_ambient]) == 5
        else:
            cap_size = 8 * 4 # cap_t:8byte. len([cap_inheritable,cap_permitted,cap_effective,cap_bset]) == 4

        for i in range(10):
            offset_user_ns = offset_uid + uid_gid_size + sizeof_securebits + cap_size + current_arch.ptrsize * i
            v = read_int_from_memory(init_task_cred_ptr + offset_user_ns)
            if not is_valid_addr(v):
                continue
            w = read_int_from_memory(v)
            if w == 1:
                return offset_user_ns
        return None

    class MapleTree:
        """Linux v6.1 introduces maple_tree. This is a simple parser."""
        MT_FLAGS_HEIGHT_MASK = 0x7c
        MT_FLAGS_HEIGHT_OFFSET = 0x02
        MAPLE_NODE_TYPE_SHIFT = 0x03
        MAPLE_NODE_TYPE_MASK = 0x0f
        MAPLE_NODE_POINTER_MASK = 0xff
        MAPLE_DENSE = 0
        MAPLE_LEAF_64 = 1
        MAPLE_RANGE_64 = 2
        MAPLE_ARANGE_64 = 3

        def __init__(self, mm, quiet):
            self.quiet = quiet
            kversion = Kernel.kernel_version()
            """
            struct mm_struct {
                struct {
                    struct {
                        atomic_t mm_count;
                    } ____cacheline_aligned_in_smp; // ~6.4
                    struct maple_tree {
                        union {
                            spinlock_t ma_lock;
                            lockdep_map_p ma_external_lock;
                        };
                        unsigned int ma_flags; // v6.6~
                        void __rcu *ma_root; // this points root maple_node. (lower 8-bits are some flags)
                        unsigned int ma_flags; // ~v6.6
                    } mm_mt;
                    ...
                } __randomize_layout;
                ...
            };
            """

            # ____cacheline_aligned_in_smp attribute, spinlock_t and lockdep_map_p can be different size
            # in each environment or situation, so search heuristically.
            for i in range(0x20):
                x = read_int_from_memory(mm + current_arch.ptrsize * i)
                """
                [x64 v6.4.2]
                0xffff8bedc104db00|+0x0000|+000: 0x0000000000000000   // union  <--- mm_mt
                0xffff8bedc104db08|+0x0008|+001: 0xffff8bedc1a6601e   // ma_root
                0xffff8bedc104db10|+0x0010|+002: 0x000000000000030b   // ma_flags

                [x64 v6.6.1]
                0xffff972801b78a38|+0x0040|+008: 0x0000000000000000   // (the end of cacheline?)
                0xffff972801b78a40|+0x0040|+008: 0x0000030b00000000   // ma_flags || union  <--- mm_mt
                0xffff972801b78a48|+0x0048|+009: 0xffff972801b0cc1e   // ma_root
                """
                if is_valid_addr(x) and (x & 0xff) in [0x1e, 0x0e]:
                    offset_ma_root = current_arch.ptrsize * i
                    if kversion < "6.6":
                        offset_ma_flags = offset_ma_root + current_arch.ptrsize
                    else:
                        offset_ma_flags = offset_ma_root - 4
                        if is_64bit() and u32(read_memory(mm + offset_ma_flags, 4)) == 0:
                            offset_ma_flags = offset_ma_root - 8
                    break
            else:
                raise

            self.ma_root_raw = read_int_from_memory(mm + offset_ma_root)
            self.ma_flags = read_int_from_memory(mm + offset_ma_flags)
            self.max_depth = (self.ma_flags & self.MT_FLAGS_HEIGHT_MASK) >> self.MT_FLAGS_HEIGHT_OFFSET

            if is_64bit():
                self.MAPLE_NODE_SLOTS = 31
                self.MAPLE_RANGE64_SLOTS = 16
                self.MAPLE_ARANGE64_SLOTS = 10
                self.MAPLE_ALLOC_SLOTS = self.MAPLE_NODE_SLOTS - 1
                self.maple_range_64_offset_slot = current_arch.ptrsize * self.MAPLE_RANGE64_SLOTS
                self.maple_arange_64_offset_slot = current_arch.ptrsize * self.MAPLE_ARANGE64_SLOTS
                self.maple_alloc_offset_slot = current_arch.ptrsize * 2
            else:
                self.MAPLE_NODE_SLOTS = 63
                self.MAPLE_RANGE64_SLOTS = 32
                self.MAPLE_ARANGE64_SLOTS = 21
                self.MAPLE_ALLOC_SLOTS = self.MAPLE_NODE_SLOTS - 2
                self.maple_range_64_offset_slot = current_arch.ptrsize * self.MAPLE_RANGE64_SLOTS
                self.maple_arange_64_offset_slot = current_arch.ptrsize * self.MAPLE_ARANGE64_SLOTS
                self.maple_alloc_offset_slot = current_arch.ptrsize * 3

            self.seen = set()
            self.iters = self.parse_node(self.ma_root_raw, 1)
            return

        def get_next(self, _=None):
            # iterate all `vm_area_struct` pointers
            for addr in self.iters:
                return addr
            return None

        def parse_node(self, entry, depth):
            if entry in self.seen:
                return
            self.seen.add(entry)

            if self.max_depth < depth:
                return

            pointer = entry & ~(self.MAPLE_NODE_POINTER_MASK)
            node_type = (entry >> self.MAPLE_NODE_TYPE_SHIFT) & self.MAPLE_NODE_TYPE_MASK

            if node_type == self.MAPLE_DENSE:
                slot_top = pointer + self.maple_alloc_offset_slot
                for i in range(self.MAPLE_ALLOC_SLOTS):
                    slot = read_int_from_memory(slot_top + current_arch.ptrsize * i)
                    if (slot & ~(self.MAPLE_NODE_TYPE_MASK)) != 0:
                        if is_valid_addr(slot):
                            yield slot
            elif node_type == self.MAPLE_LEAF_64:
                slot_top = pointer + self.maple_range_64_offset_slot
                for i in range(self.MAPLE_RANGE64_SLOTS):
                    slot = read_int_from_memory(slot_top + current_arch.ptrsize * i)
                    if (slot & ~(self.MAPLE_NODE_TYPE_MASK)) != 0:
                        if is_valid_addr(slot):
                            yield slot
            elif node_type == self.MAPLE_RANGE_64:
                slot_top = pointer + self.maple_range_64_offset_slot
                for i in range(self.MAPLE_RANGE64_SLOTS):
                    slot = read_int_from_memory(slot_top + current_arch.ptrsize * i)
                    if (slot & ~(self.MAPLE_NODE_TYPE_MASK)) != 0:
                        yield from self.parse_node(slot, depth + 1)
            elif node_type == self.MAPLE_ARANGE_64:
                slot_top = pointer + self.maple_arange_64_offset_slot
                for i in range(self.MAPLE_ARANGE64_SLOTS):
                    slot = read_int_from_memory(slot_top + current_arch.ptrsize * i)
                    if (slot & ~(self.MAPLE_NODE_TYPE_MASK)) != 0:
                        yield from self.parse_node(slot, depth + 1)
            return

    def get_vm_area_struct(self, mm):
        kversion = Kernel.kernel_version()
        if kversion < "6.1":
            """
            struct mm_struct {
                struct {
                    struct vm_area_struct *mmap;
                    ...
                } __randomize_layout;
            };
            """
            offset_mmap = 0
            vm_area_struct = read_int_from_memory(mm + offset_mmap)

            """
            struct vm_area_struct {
                unsigned long vm_start;
                unsigned long vm_end;
                struct vm_area_struct *vm_next, *vm_prev;
                struct rb_node vm_rb;
                unsigned long rb_subtree_gap;
                struct mm_struct *vm_mm;
                pgprot_t vm_page_prot;
                unsigned long vm_flags;
                struct {
                    struct rb_node rb;
                    unsigned long rb_subtree_last;
                } shared;
                struct list_head anon_vma_chain;
                struct anon_vma *anon_vma;
                const struct vm_operations_struct *vm_ops;
                unsigned long vm_pgoff;
                struct file *vm_file;
                ...
            };
            """
            def get_next_vma_area_struct(current):
                return read_int_from_memory(current + current_arch.ptrsize * 2)

        else: # kversion >= "6.1"
            """
            struct mm_struct {
                struct {
                    struct {
                        atomic_t mm_count;
                    } ____cacheline_aligned_in_smp; // v6.4~
                    struct maple_tree {
                        union {
                            spinlock_t ma_lock;
                            lockdep_map_p ma_external_lock;
                        };
                        unsigned int ma_flags; // v6.6~
                        void __rcu *ma_root; // this points root maple_node. (lower 8-bits are some flags)
                        unsigned int ma_flags; // ~v6.6
                    } mm_mt;
                    ...
                } __randomize_layout;
                ...
            };

            struct maple_node {
                union {
                    struct {
                        struct maple_pnode *parent;
                        void __rcu *slot[MAPLE_NODE_SLOTS]; // 64-bit: 31; 32-bit: 63
                    };
                    struct {
                        void *pad;
                        struct rcu_head rcu;
                        struct maple_enode *piv_parent;
                        unsigned char parent_slot;
                        enum maple_type type;
                        unsigned char slot_len;
                        unsigned int ma_flags;
                    };
                    struct maple_range_64 {
                        struct maple_pnode *parent;
                        unsigned long pivot[MAPLE_RANGE64_SLOTS - 1];     // 64-bit: 15; 32-bit: 31
                        union {
                            void __rcu *slot[MAPLE_RANGE64_SLOTS];        // 64-bit: 16; 32-bit: 32
                            struct {
                                void __rcu *pad[MAPLE_RANGE64_SLOTS - 1]; // 64-bit: 15; 32-bit: 31
                                struct maple_metadata meta;
                            };
                        };
                    } mr64;
                    struct maple_arange_64 {
                        struct maple_pnode *parent;
                        unsigned long pivot[MAPLE_ARANGE64_SLOTS - 1]; // 64-bit: 9;  32-bit: 20
                        void __rcu *slot[MAPLE_ARANGE64_SLOTS];        // 64-bit: 10; 32-bit: 21
                        unsigned long gap[MAPLE_ARANGE64_SLOTS];       // 64-bit: 10; 32-bit: 21
                        struct maple_metadata meta;
                    } ma64;
                    struct maple_alloc {
                        unsigned long total;
                        unsigned char node_count;
                        unsigned int request_count;
                        struct maple_alloc *slot[MAPLE_ALLOC_SLOTS]; // 64-bit: 30; 32-bit: 31
                    } alloc;
                };
            };
            """
            get_next_vma_area_struct = self.MapleTree(mm, self.quiet).get_next
            vm_area_struct = get_next_vma_area_struct()

            """
            struct vm_area_struct {
                unsigned long vm_start;
                unsigned long vm_end;
                struct mm_struct *vm_mm;
                pgprot_t vm_page_prot;
                unsigned long vm_flags;
            #ifdef CONFIG_PER_VMA_LOCK                 // v6.4~
                int vm_lock_seq;                       // v6.4~
                struct vma_lock *vm_lock;              // v6.4~
                bool detached;                         // v6.4~
            #endif                                     // v6.4~
                union {                                // ~v6.2
                    struct {
                        struct rb_node rb;
                        unsigned long rb_subtree_last;
                    } shared;
                    struct anon_vma_name *anon_name;   // ~v6.2
                };                                     // ~v6.2
                struct list_head anon_vma_chain;
                struct anon_vma *anon_vma;
                const struct vm_operations_struct *vm_ops;
                unsigned long vm_pgoff;
                struct file *vm_file;
                ...
            };
            """
        return vm_area_struct, get_next_vma_area_struct

    def get_offset_vm_mm(self, task_addrs, offset_mm):
        for task in task_addrs:
            mm = read_int_from_memory(task + offset_mm)
            if mm == 0:
                continue

            vm_area_struct, _ = self.get_vm_area_struct(mm)
            current = vm_area_struct
            while True:
                x = read_int_from_memory(current)
                if x == mm:
                    break
                current += current_arch.ptrsize
            offset_vm_mm = current - vm_area_struct
            return offset_vm_mm
        return None

    def get_offset_vm_flags(self, offset_vm_mm):
        if is_64bit():
            offset_vm_flags = offset_vm_mm + 8 * 2
        elif is_x86_32():
            cr4 = get_register("cr4", use_monitor=True)
            if (cr4 >> 5) & 1: # PAE check
                offset_vm_flags = offset_vm_mm + 8 * 2
            else:
                offset_vm_flags = offset_vm_mm + 4 * 2
        elif is_arm32():
            ret = gdb.execute("pagewalk -n", to_string=True)
            if "using long description" in ret:
                offset_vm_flags = offset_vm_mm + 8 * 2
            else:
                offset_vm_flags = offset_vm_mm + 4 * 2
        return offset_vm_flags

    def get_offset_vm_file(self, task_addrs, offset_mm, offset_vm_flags):
        for task in task_addrs:
            mm = read_int_from_memory(task + offset_mm)
            if mm == 0:
                continue

            vm_area_struct, _ = self.get_vm_area_struct(mm)
            current = vm_area_struct + offset_vm_flags

            # now, `current` points vm_flags
            current += current_arch.ptrsize
            if is_32bit():
                mask = Kernel.get_kernel_base().text_base & 0xf0000000
            else:
                mask = 0xffff_0000_0000_0000
            while True:
                x = read_int_from_memory(current)
                if not is_valid_addr(x):
                    current += current_arch.ptrsize
                    continue

                y = read_int_from_memory(current + current_arch.ptrsize) # read one unit ahead
                if not is_valid_addr(y):
                    current += current_arch.ptrsize
                    continue

                if (x & mask) == (y & mask) == mask and x == y: # search anon_vma_chain
                    break
                current += current_arch.ptrsize

            # now, `current` points anon_vma_chain
            offset_anon_vma_chain = current - vm_area_struct
            offset_vm_file = offset_anon_vma_chain + current_arch.ptrsize * 5
            return offset_vm_file
        return None

    def get_mm(self, task, offset_mm):
        mm = read_int_from_memory(task + offset_mm)
        if mm == 0:
            return []

        vm_areas = []
        VmArea = collections.namedtuple("VmArea", "start end flags file")
        current, get_next_vma_area_struct = self.get_vm_area_struct(mm)
        while current:
            vm_start = read_int_from_memory(current)
            vm_end = read_int_from_memory(current + current_arch.ptrsize)
            vm_flags = read_int_from_memory(current + self.offset_vm_flags)
            vm_file = read_int_from_memory(current + self.offset_vm_file)
            filepath = self.get_filepath(vm_file)
            perm = Permission(value=vm_flags)
            vm_areas.append(VmArea(vm_start, vm_end, str(perm), filepath))
            current = get_next_vma_area_struct(current)
        return vm_areas

    def get_offset_mnt(self, file):
        if not is_valid_addr(file):
            return None

        """
        [~v6.4]
        struct file {
            union {                           // ~v6.0
                struct llist_node fu_llist;   // ~v6.0
                struct rcu_head fu_rcuhead;   // ~v6.0
            } f_u;                            // ~v6.0
            union {                           // v6.0~
                struct llist_node f_llist;    // v6.0~
                struct rcu_head f_rcuhead;    // v6.0~
                unsigned int f_iocb_flags;    // v6.0~
            };                                // v6.0~
            struct path {
                struct vfsmount *mnt;
                struct dentry *dentry;
            } f_path;
            struct inode *f_inode;            // v3.9~
            ...
        };

        [v6.5~]
        struct file {
            union {
                struct llist_node f_llist;
                struct rcu_head f_rcuhead;
                unsigned int f_iocb_flags;
            };
            spinlock_t f_lock;
            fmode_t f_mode;
            atomic_long_t f_count;
            struct mutex f_pos_lock;
            loff_t f_pos;
            unsigned int f_flags;
            struct fown_struct {
                rwlock_t lock;
                struct pid *pid;
                enum pid_type pid_type;
                kuid_t uid, euid;
                int signum;
            } f_owner;
            const struct cred *f_cred;
            struct file_ra_state {
                pgoff_t start;
                unsigned int size;
                unsigned int async_size;
                unsigned int ra_pages;
                unsigned int mmap_miss;
                loff_t prev_pos;
            } f_ra;
            struct path {
                struct vfsmount *mnt;
                struct dentry *dentry;
            } f_path;
            struct inode *f_inode;
            ...
        };
        """
        kversion = Kernel.kernel_version()

        if kversion < "6.5":
            offset_mnt = current_arch.ptrsize * 2

        else: # kversion >= "6.5"
            for i in range(0x40):
                cand_offset_mnt = current_arch.ptrsize * i
                mnt = read_int_from_memory(file + cand_offset_mnt)

                """
                gef> slab-contains 0xffff9f49811d33e0
                slab: 0xfffff93f800474c0
                kmem_cache: 0xffff9f4981048c00
                base: 0xffff9f49811d3000
                name: mnt_cache  size: 0x140  num_pages: 0x1 (unaligned?)
                """
                # f_path.mnt points in the middle of the chunk, so the "unaligned?" warning is not a problem.
                ret = Kernel.get_slab_contains(mnt, allow_unaligned=True)
                if not ret:
                    continue
                if "mnt_cache" in ret:
                    offset_mnt = cand_offset_mnt
                    break

                """
                It has also been observed when mnt_cache is not used.
                In this case, the 2 previous elements from ext4_inode_cache or shmem_inode_cache seem to be the relevant pointer.

                0xffff8b864013a298|+0x0098|+019: 0xffff8b86436e4da0 (task_group) <-- here
                0xffff8b864013a2a0|+0x00a0|+020: 0xffff8b86404079c0 (kmalloc-rcl-192)
                0xffff8b864013a2a8|+0x00a8|+021: 0xffff8b864041e0a8 (ext4_inode_cache)

                0xffff8b864013a698|+0x0098|+019: 0xffff8b8640171020 (task_group) <-- here
                0xffff8b864013a6a0|+0x00a0|+020: 0xffff8b86436159c0 (kmalloc-rcl-192)
                0xffff8b864013a6a8|+0x00a8|+021: 0xffff8b8643730640 (shmem_inode_cache)
                """
                if "inode_cache" in ret:
                    offset_mnt = cand_offset_mnt - current_arch.ptrsize * 2
                    break
            else:
                raise
        return offset_mnt

    def get_offset_dentry(self, offset_mnt):
        return offset_mnt + current_arch.ptrsize

    def get_offset_d_iname(self, dentry):
        """
        struct dentry {
            unsigned int d_flags;
            seqcount_spinlock_t d_seq;
            struct hlist_bl_node d_hash;
            struct dentry *d_parent;
            struct qstr {
                union {
                    struct {
                        HASH_LEN_DECLARE;
                    };
                    u64 hash_len;
                };
                const unsigned char *name; // this points d_iname
            } d_name;
            struct inode *d_inode;
            unsigned char d_iname[DNAME_INLINE_LEN];
            ...
        };
        """
        current = dentry
        while True:
            name = read_int_from_memory(current)
            if 0 < name - current <= 0x20:
                offset_d_iname = name - dentry
                break
            current += current_arch.ptrsize
        return offset_d_iname

    def get_offset_d_inode(self, offset_d_iname):
        return offset_d_iname - current_arch.ptrsize

    def get_offset_d_parent(self, dentry, offset_d_iname):
        offset_dname_name = offset_d_iname - current_arch.ptrsize * 2
        if read_int_from_memory(dentry + offset_dname_name) == 0: # skip if padding
            offset_dname_name -= current_arch.ptrsize
        offset_d_parent = offset_dname_name - 0x8 - current_arch.ptrsize
        if read_int_from_memory(dentry + offset_d_parent) == 0: # skip if padding
            offset_d_parent -= current_arch.ptrsize
        return offset_d_parent

    def get_offset_i_ino(self, inode):
        """
        struct inode {
            umode_t i_mode;
            unsigned short i_opflags;
            kuid_t i_uid;
            kgid_t i_gid;
            unsigned int i_flags;
        #ifdef CONFIG_FS_POSIX_ACL
            struct posix_acl *i_acl;
            struct posix_acl *i_default_acl;
        #endif
            const struct inode_operations *i_op;
            struct super_block *i_sb;
            struct address_space *i_mapping;
        #ifdef CONFIG_SECURITY
            void *i_security;
        #endif
            unsigned long i_ino;
            ...
        };
        """
        current = inode + 2 + 2 + 4 + 4 + 4

        # now, `current` points i_acl or i_op
        while True:
            v = read_int_from_memory(current)
            if v == 0:
                current += current_arch.ptrsize
                continue
            if is_64bit() and v == 0xffffffffffffffff:
                current += current_arch.ptrsize
                continue
            elif is_32bit() and v == 0xffffffff:
                current += current_arch.ptrsize
                continue
            elif is_valid_addr(v):
                current += current_arch.ptrsize
                continue
            offset_i_ino = current - inode
            break
        return offset_i_ino

    def get_ino(self, file):
        dentry = read_int_from_memory(file + self.offset_dentry)
        inode = read_int_from_memory(dentry + self.offset_d_inode)
        i_ino = read_int_from_memory(inode + self.offset_i_ino)
        return i_ino

    def get_filepath(self, file):
        if not is_valid_addr(file):
            return ""

        if file in self.filepath_cache:
            return self.filepath_cache[file]

        """
        struct path {
            struct vfsmount *mnt;
            struct dentry *dentry;
        } f_path;

        struct mount {
            struct hlist_node mnt_hash;
            struct mount *mnt_parent;
            struct dentry *mnt_mountpoint;
            struct vfsmount {
                struct dentry *mnt_root;
                struct super_block *mnt_sb;
                int mnt_flags;
            } mnt; <--- f_path.mnt points here
            ...
        };
        """

        def is_root(dentry):
            return dentry == read_int_from_memory(dentry + self.offset_d_parent)

        offset_vfsmount_mnt_root = 0
        offset_mount_mnt_parent = current_arch.ptrsize * 2
        offset_mount_mnt_mountpoint = current_arch.ptrsize * 3
        offset_mount_mnt = current_arch.ptrsize * 4

        filepath = []

        dentry = read_int_from_memory(file + self.offset_dentry)
        vfsmnt = read_int_from_memory(file + self.offset_mnt)
        mnt = vfsmnt - offset_mount_mnt

        while True:
            mnt_root = read_int_from_memory(vfsmnt + offset_vfsmount_mnt_root)
            if dentry == mnt_root or is_root(dentry):
                parent = read_int_from_memory(mnt + offset_mount_mnt_parent)

                # Global root?
                if mnt != parent:
                    dentry = read_int_from_memory(mnt + offset_mount_mnt_mountpoint)
                    mnt = parent
                    vfsmnt = mnt + offset_mount_mnt
                    continue

                name = read_cstring_from_memory(dentry + self.offset_d_iname)
                if name is None:
                    name_ptr = read_int_from_memory(dentry + self.offset_d_iname - current_arch.ptrsize * 2)
                    name = read_cstring_from_memory(name_ptr)
                filepath.append(name)
                break

            name = read_cstring_from_memory(dentry + self.offset_d_iname)
            if name is None:
                name_ptr = read_int_from_memory(dentry + self.offset_d_iname - current_arch.ptrsize * 2)
                name = read_cstring_from_memory(name_ptr)
            filepath.append(name)

            parent = read_int_from_memory(dentry + self.offset_d_parent)
            dentry = parent

        filepath = os.path.join(*filepath[::-1])
        if filepath in ["UNIX", "NETLINK", "TCP", "TCPv6", "UDP", "UDPv6", "PACKET"]:
            filepath = "socket:[{:d}]".format(self.get_ino(file))
        elif filepath and not filepath.startswith("/"):
            filepath = "anon_inode:{:s}".format(filepath)
        elif filepath == "":
            filepath = "pipe:[{:d}]".format(self.get_ino(file))

        self.filepath_cache[file] = filepath
        return filepath

    def add_lwp_task(self, task_addrs):
        lwp_task_addrs = []
        kversion = Kernel.kernel_version()

        for task in task_addrs:
            seen = []
            if kversion < "6.7":
                lwp = task
                while lwp not in seen:
                    seen.append(lwp)
                    lwp = read_int_from_memory(lwp + self.offset_thread_group) - self.offset_thread_group
                lwp_task_addrs.extend(seen)

            else:
                signal = read_int_from_memory(task + self.offset_signal)
                head = signal + self.offset_thread_head
                seen = [head]
                curr = read_int_from_memory(head)
                while curr not in seen:
                    seen.append(curr)
                    lwp = curr - self.offset_thread_group
                    lwp_task_addrs.append(lwp)
                    curr = read_int_from_memory(curr)
        return lwp_task_addrs

    def get_offset_nsproxy(self, task_addr, offset_files):
        """
        struct task_struct {
            ...
            struct files_struct *files;
        #ifdef CONFIG_IO_URING
            struct io_uring_task *io_uring;
        #endif
            struct nsproxy *nsproxy;
            struct signal_struct *signal;
            struct sighand_struct __rcu *sighand;
            sigset_t blocked;
            ...
        };
        """
        offset_nsproxy = offset_files + current_arch.ptrsize
        if not is_valid_addr(read_int_from_memory(task_addr + offset_nsproxy + current_arch.ptrsize * 3)): # blocked
            # CONFIG_IO_URING=n
            return offset_nsproxy
        # CONFIG_IO_URING=y
        return offset_nsproxy + current_arch.ptrsize

    def get_offset_sighand(self, task_addr, offset_files):
        """
        struct task_struct {
            ...
            struct files_struct *files;
        #ifdef CONFIG_IO_URING
            struct io_uring_task *io_uring;
        #endif
            struct nsproxy *nsproxy;
            struct signal_struct *signal;
            struct sighand_struct __rcu *sighand;
            sigset_t blocked;
            ...
        };
        """
        offset_sighand = offset_files + current_arch.ptrsize * 3
        if not is_valid_addr(read_int_from_memory(task_addr + offset_sighand + current_arch.ptrsize)): # blocked
            # CONFIG_IO_URING=n
            return offset_sighand
        # CONFIG_IO_URING=y
        return offset_sighand + current_arch.ptrsize

    def get_offset_action(self, sighand):
        """
        v5.3~
        struct sighand_struct {
            spinlock_t siglock;
            refcount_t count;
            struct wait_queue_head {
                spinlock_t lock;
                struct list_head head;
            } signalfd_wqh;
            struct k_sigaction {
                struct sigaction {
                    __sighandler_t sa_handler;
                    unsigned long sa_flags;
                #ifdef __ARCH_HAS_SA_RESTORER
                    __sigrestore_t sa_restorer;
                #endif
                    sigset_t sa_mask;
                } sa;
            #ifdef __ARCH_HAS_KA_RESTORER
                __sigrestore_t ka_restorer;
            #endif
            } action[_NSIG]; // 64
        };

        ~v5.3
        struct sighand_struct {
            refcount_t count;
            struct k_sigaction {
                struct sigaction sa;
            #ifdef __ARCH_HAS_KA_RESTORER
                __sigrestore_t ka_restorer;
            #endif
            } action[_NSIG]; // 64
            spinlock_t siglock;
            wait_queue_head_t signalfd_wqh;
        };
        """
        kversion = Kernel.kernel_version()

        if kversion >= "5.3":
            # search signalfd_wqh.list_head
            found = False
            for i in range(1, 30):
                offset_list_head = current_arch.ptrsize * i
                head = sighand + offset_list_head
                if not is_valid_addr(head):
                    continue

                current = read_int_from_memory(head)
                seen = []
                while True:
                    if current == head:
                        found = True
                        break
                    if not is_valid_addr(current):
                        break
                    if current in seen:
                        break
                    seen.append(current)
                    current = read_int_from_memory(current)
                if found:
                    break

            if not found:
                return None

            offset_action = offset_list_head + current_arch.ptrsize * 2

        else: # < 5.3
            offset_action = current_arch.ptrsize
        return offset_action

    def get_sizeof_action(self, task_addrs, offset_sighand, offset_action, offset_mm):
        """
        case 1 (x64)
        0xffff8f63011e4400|+0x0000|+000: 0x0000000100000000
        0xffff8f63011e4408|+0x0008|+001: 0x0000000000000000
        0xffff8f63011e4410|+0x0010|+002: 0xffff8f63593e11e0  ->  [loop detected]
        0xffff8f63011e4418|+0x0018|+003: 0xffff8f63593e11e0  ->  0xffff8f63011e4410  ->  [loop detected]
        0xffff8f63011e4420|+0x0020|+004: 0x0000000000000000 <- action[0]
        0xffff8f63011e4428|+0x0028|+005: 0x0000000014000000
        0xffff8f63011e4430|+0x0030|+006: 0x00007f3ec71d0d60
        0xffff8f63011e4438|+0x0038|+007: 0x0000000000000000
        0xffff8f63011e4440|+0x0040|+008: 0x0000000000000000 <- action[1]
        0xffff8f63011e4448|+0x0048|+009: 0x0000000014000000
        0xffff8f63011e4450|+0x0050|+010: 0x00007f3ec71d0d60
        0xffff8f63011e4458|+0x0058|+011: 0x0000000000000000
        0xffff8f63011e4460|+0x0060|+012: 0x0000562e3b34bdf0 <- action[2]
        0xffff8f63011e4468|+0x0068|+013: 0x0000000044000000
        0xffff8f63011e4470|+0x0070|+014: 0x00007f3ec71d0d60
        0xffff8f63011e4478|+0x0078|+015: 0x0000000000000000
        0xffff8f63011e4480|+0x0080|+016: 0x0000562e3b34bdf0 <- action[3]
        0xffff8f63011e4488|+0x0088|+017: 0x0000000044000000
        0xffff8f63011e4490|+0x0090|+018: 0x00007f3ec71d0d60
        0xffff8f63011e4498|+0x0098|+019: 0x0000000000000000
        ...

        case 2 (arm64)
        0xffff000003080000|+0x0000|+000: 0x0000000100000000
        0xffff000003080008|+0x0008|+001: 0x0000000000000000
        0xffff000003080010|+0x0010|+002: 0xffff000003080010  ->  [loop detected]
        0xffff000003080018|+0x0018|+003: 0xffff000003080010  ->  [loop detected]
        0xffff000003080020|+0x0020|+004: 0x0000000000000000 <- action[0]
        0xffff000003080028|+0x0028|+005: 0x0000000000000000
        0xffff000003080030|+0x0030|+006: 0x0000000000000000
        0xffff000003080038|+0x0038|+007: 0x0000000000000000
        0xffff000003080040|+0x0040|+008: 0x000000000051dc20 <- action[1]
        0xffff000003080048|+0x0048|+009: 0x0000000000000000
        0xffff000003080050|+0x0050|+010: 0x0000000000000002
        0xffff000003080058|+0x0058|+011: 0xfffffffe7ffbfeff
        0xffff000003080060|+0x0060|+012: 0x0000000000000001 <- action[2]
        0xffff000003080068|+0x0068|+013: 0x0000000000000000
        0xffff000003080070|+0x0070|+014: 0x0000000000000002
        0xffff000003080078|+0x0078|+015: 0xfffffffe7ffbfeff
        0xffff000003080080|+0x0080|+016: 0x0000000000000000 <- action[3]
        0xffff000003080088|+0x0088|+017: 0x0000000000000000
        0xffff000003080090|+0x0090|+018: 0x0000000000000000
        0xffff000003080098|+0x0098|+019: 0x0000000000000000
        ...
        """
        if is_32bit():
            possible_sizes = [0x10, 0x14, 0x18]
        else:
            possible_sizes = [0x18, 0x20, 0x28]

        # calc sizeof(action[0])
        sizeof_action = 0xffffffffffffffff
        for task in task_addrs:
            mm = read_int_from_memory(task + offset_mm)
            if mm == 0:
                # for speed up; ignore if kernel thread
                continue

            sighand = read_int_from_memory(task + offset_sighand)
            current = sighand + offset_action
            found_offset_case1 = []
            found_offset_case2 = []

            for i in range(64 * 4):
                offset = current_arch.ptrsize * i

                # check case 1 (sa_flags)
                v = read_int_from_memory(current + offset)
                # SA_RESTORER, SA_RESTART, SA_NODEFER, SA_RESTART|SA_RESTORER, SA_NODEFER|SA_RESTORER
                if v in [0x4000000, 0x10000000, 0x40000000, 0x14000000, 0x44000000]:
                    found_offset_case1.append(offset)

                # check case 2 (sa_mask)
                v = u64(read_memory(current + offset, 8))
                if bin(v)[2:].count("1") > 56: # heuristic threshold
                    found_offset_case2.append(offset)

            if len(found_offset_case1) >= 2:
                sizeof_action_tmp = min(y - x for x, y in zip(found_offset_case1[:-1], found_offset_case1[1:]))
                # it is minimum size, so fast return
                if sizeof_action_tmp in possible_sizes:
                    return sizeof_action_tmp
                # not minimum size, so check next task
                sizeof_action = min(sizeof_action, sizeof_action_tmp)

            if len(found_offset_case2) >= 2:
                sizeof_action_tmp = min(y - x for x, y in zip(found_offset_case2[:-1], found_offset_case2[1:]))
                # it is minimum size, so fast return
                if sizeof_action_tmp in possible_sizes:
                    return sizeof_action_tmp
                # not minimum size, so check next task
                sizeof_action = min(sizeof_action, sizeof_action_tmp)

        if sizeof_action != 0xffffffffffffffff:
            for ps in possible_sizes:
                if sizeof_action % ps == 0:
                    return sizeof_action
        return None

    def initialize(self, args):
        kversion = Kernel.kernel_version()

        # init_task
        init_task = KernelAddressHeuristicFinder.get_init_task()
        if init_task is None:
            self.quiet_err("Not found init_task")
            return False
        self.quiet_info("init_task: {:#x}".format(init_task))

        # task_struct->tasks
        if self.offset_tasks is None:
            self.offset_tasks = self.get_offset_tasks(init_task)
        if self.offset_tasks is None:
            self.quiet_err("Not found init_task->tasks")
            return False
        self.quiet_info("offsetof(task_struct, tasks): {:#x}".format(self.offset_tasks))

        # task addresses
        task_addrs = self.get_task_list(init_task, self.offset_tasks)
        if task_addrs is None:
            self.quiet_err("Failed to list up each tasks")
            return False
        self.quiet_info("Number of tasks: {:d}".format(len(task_addrs)))

        # task_struct->mm
        if self.offset_mm is None:
            self.offset_mm = self.get_offset_mm(task_addrs[0], self.offset_tasks)
        self.quiet_info("offsetof(task_struct, mm): {:#x}".format(self.offset_mm))

        # task_struct->stack
        if self.offset_stack is None:
            self.offset_stack = self.get_offset_stack(task_addrs)
        if self.offset_stack is None:
            self.quiet_err("Not found task->stack")
            return False
        self.quiet_info("offsetof(task_struct, stack): {:#x}".format(self.offset_stack))

        # task_struct->pid
        if self.offset_pid is None:
            self.offset_pid = self.get_offset_pid(task_addrs)
        if self.offset_pid is None:
            self.quiet_err("Not found task->pid")
            return False
        self.quiet_info("offsetof(task_struct, pid): {:#x}".format(self.offset_pid))

        # task_struct->stack_canary
        if self.offset_kcanary is None:
            self.offset_kcanary = self.get_offset_canary(task_addrs, self.offset_pid)
        if self.offset_kcanary is None:
            self.quiet_info("offsetof(task_struct, stack_canary): None")
        else:
            self.quiet_info("offsetof(task_struct, stack_canary): {:#x}".format(self.offset_kcanary))

        # task_struct->comm
        if self.offset_comm is None:
            self.offset_comm = self.get_offset_comm(task_addrs)
        if self.offset_comm is None:
            self.quiet_err("Not found task->comm[TASK_CMM_LEN]")
            return False
        self.quiet_info("offsetof(task_struct, comm): {:#x}".format(self.offset_comm))

        # task_struct->cred
        if self.offset_cred is None:
            self.offset_cred = self.get_offset_cred(task_addrs, self.offset_comm)
        if self.offset_cred is None:
            self.quiet_err("Not found task->cred")
            return False
        self.quiet_info("offsetof(task_struct, cred): {:#x}".format(self.offset_cred))

        # cred.uid
        if self.offset_uid is None:
            self.offset_uid = self.get_offset_uid(task_addrs[0] + self.offset_cred)
        self.quiet_info("offsetof(cred, uid): {:#x}".format(self.offset_uid))

        # kstack_top->saved_ptregs
        if args.print_regs:
            if self.offset_ptregs is None:
                self.kstack_size, self.offset_ptregs = self.get_offset_ptregs(task_addrs, self.offset_stack)
            if self.offset_ptregs is None:
                self.quiet_err("Not found saved ptregs")
                return False
            self.quiet_info("kstack size: {:#x}".format(self.kstack_size))
            self.quiet_info("offsetof(kstack_top, saved ptregs): {:#x}".format(self.offset_ptregs))

        # vm_area_struct->vm_mm
        # vm_area_struct->vm_flags
        # vm_area_struct->vm_file
        # file->f_path.mnt
        # file->f_path.dentry
        # dentry->d_iname
        # dentry->d_parent
        # dentry->d_inode
        # inode->i_ino
        if args.print_maps or args.print_fd:
            if self.offset_vm_mm is None:
                self.offset_vm_mm = self.get_offset_vm_mm(task_addrs, self.offset_mm)
            if self.offset_vm_mm is None:
                self.quiet_err("Not found vm_area_struct->vm_mm")
                return False
            self.quiet_info("offsetof(vm_area_struct, vm_mm): {:#x}".format(self.offset_vm_mm))

            if self.offset_vm_flags is None:
                self.offset_vm_flags = self.get_offset_vm_flags(self.offset_vm_mm)
            if self.offset_vm_flags is None:
                self.quiet_err("Not found vm_area_struct->vm_flags")
                return False
            self.quiet_info("offsetof(vm_area_struct, vm_flags): {:#x}".format(self.offset_vm_flags))

            if self.offset_vm_file is None:
                self.offset_vm_file = self.get_offset_vm_file(task_addrs, self.offset_mm, self.offset_vm_flags)
            if self.offset_vm_file is None:
                self.quiet_err("Not found vm_area_struct->vm_file")
                return False
            self.quiet_info("offsetof(vm_area_struct, vm_file): {:#x}".format(self.offset_vm_file))

            if self.offset_mnt is None:
                mm = read_int_from_memory(task_addrs[1] + self.offset_mm)
                current, _ = self.get_vm_area_struct(mm)
                vm_file = read_int_from_memory(current + self.offset_vm_file)
                self.offset_mnt = self.get_offset_mnt(vm_file)
            if self.offset_mnt is None:
                self.quiet_err("Not found file->f_path.mnt")
                return False
            self.quiet_info("offsetof(file, f_path.mnt): {:#x}".format(self.offset_mnt))

            if self.offset_dentry is None:
                self.offset_dentry = self.get_offset_dentry(self.offset_mnt)
            self.quiet_info("offsetof(file, f_path.dentry): {:#x}".format(self.offset_dentry))

            if self.offset_d_iname is None:
                dentry = read_int_from_memory(vm_file + self.offset_dentry)
                self.offset_d_iname = self.get_offset_d_iname(dentry)
            self.quiet_info("offsetof(dentry, d_iname): {:#x}".format(self.offset_d_iname))

            if self.offset_d_inode is None:
                self.offset_d_inode = self.get_offset_d_inode(self.offset_d_iname)
            self.quiet_info("offsetof(file, d_inode): {:#x}".format(self.offset_d_inode))

            if self.offset_d_parent is None:
                dentry = read_int_from_memory(vm_file + self.offset_dentry)
                self.offset_d_parent = self.get_offset_d_parent(dentry, self.offset_d_iname)
            self.quiet_info("offsetof(dentry, d_parent): {:#x}".format(self.offset_d_parent))

            if self.offset_i_ino is None:
                dentry = read_int_from_memory(vm_file + self.offset_dentry)
                inode = read_int_from_memory(dentry + self.offset_d_inode)
                self.offset_i_ino = self.get_offset_i_ino(inode)
            self.quiet_info("offsetof(inode, i_ino): {:#x}".format(self.offset_i_ino))

        # task_struct->files
        if args.print_fd or args.print_sighand or args.print_namespace or (kversion >= "6.7" and args.print_thread) or args.print_seccomp:
            if self.offset_files is None:
                self.offset_files = self.get_offset_files(task_addrs, self.offset_comm)
            if self.offset_files is None:
                self.quiet_err("Not found task->files")
                return False
            self.quiet_info("offsetof(task_struct, files): {:#x}".format(self.offset_files))

        # files_struct->fdt
        if args.print_fd:
            if self.offset_fdt is None:
                self.offset_fdt = self.get_offset_fdt(task_addrs, self.offset_files)
            if self.offset_fdt is None:
                self.quiet_err("Not found files_struct->fdt")
                return False
            self.quiet_info("offsetof(files_struct, fdt): {:#x}".format(self.offset_fdt))

        # cred->user_ns
        # task_struct->nsproxy
        if args.print_namespace or (kversion >= "6.7" and args.print_thread) or args.print_seccomp:
            if self.offset_user_ns is None:
                init_cred = read_int_from_memory(task_addrs[0] + self.offset_cred)
                self.offset_user_ns = self.get_offset_user_ns(init_cred, self.offset_uid)
            if self.offset_user_ns is None:
                self.quiet_err("Not found cred->user_ns")
                return False
            self.quiet_info("offsetof(cred, user_ns): {:#x}".format(self.offset_user_ns))

            if self.offset_nsproxy is None:
                self.offset_nsproxy = self.get_offset_nsproxy(task_addrs[0], self.offset_files)
            if self.offset_nsproxy is None:
                self.quiet_err("Not found task_struct->nsproxy")
                return False
            self.quiet_info("offsetof(task_struct, nsproxy): {:#x}".format(self.offset_nsproxy))

        # task_struct->group_leader
        # task_struct->thread_group
        # task_struct->signal (6.7~)
        # signal->thread_head (6.7~)
        if args.print_thread:
            if self.offset_group_leader is None:
                self.offset_group_leader = self.get_offset_group_leader(self.offset_pid, self.offset_kcanary)
            self.quiet_info("offsetof(task_struct, group_leader): {:#x}".format(self.offset_group_leader))

            if self.offset_thread_group is None:
                self.offset_thread_group = self.get_offset_thread_group(self.offset_group_leader)
            if kversion >= "6.7":
                self.quiet_info("offsetof(task_struct, thread_node): {:#x}".format(self.offset_thread_group))
            else:
                self.quiet_info("offsetof(task_struct, thread_group): {:#x}".format(self.offset_thread_group))

            if kversion >= "6.7":
                if self.offset_signal is None:
                    self.offset_signal = self.get_offset_signal(self.offset_nsproxy)
                self.quiet_info("offsetof(task_struct, signal): {:#x}".format(self.offset_signal))

                if self.offset_thread_head is None:
                    self.offset_thread_head = self.get_offset_thread_head(task_addrs[0], self.offset_signal)
                self.quiet_info("offsetof(signal, thread_head): {:#x}".format(self.offset_thread_head))

        # task_struct->sighand
        if args.print_sighand:
            if self.offset_sighand is None:
                self.offset_sighand = self.get_offset_sighand(task_addrs[0], self.offset_files)
            if self.offset_sighand is None:
                self.quiet_err("Not found task_struct->sighand")
                return False
            self.quiet_info("offsetof(task_struct, sighand): {:#x}".format(self.offset_sighand))

            if self.offset_action is None:
                sighand = read_int_from_memory(task_addrs[1] + self.offset_sighand)
                self.offset_action = self.get_offset_action(sighand)
            if self.offset_action is None:
                self.quiet_err("Not found sighand_struct->action")
                return False
            self.quiet_info("offsetof(sighand_struct, action): {:#x}".format(self.offset_action))

            if self.sizeof_action is None:
                self.sizeof_action = self.get_sizeof_action(task_addrs, self.offset_sighand, self.offset_action, self.offset_mm)
            if self.sizeof_action is None:
                self.quiet_err("Not found sizeof(action[0])")
                return False
            self.quiet_info("sizeof(action[0]): {:#x}".format(self.sizeof_action))

            self.signame_list = {
                1: "SIGHUP",
                2: "SIGINT",
                3: "SIGQUIT",
                4: "SIGILL",
                5: "SIGTRAP",
                6: "SIGABRT",
                7: "SIGBUS",
                8: "SIGFPE",
                9: "SIGKILL",
                10: "SIGUSR1",
                11: "SIGSEGV",
                12: "SIGUSR2",
                13: "SIGPIPE",
                14: "SIGALRM",
                15: "SIGTERM",
                16: "SIGSTKFLT",
                17: "SIGCHLD",
                18: "SIGCONT",
                19: "SIGSTOP",
                20: "SIGTSTP",
                21: "SIGTTIN",
                22: "SIGTTOU",
                23: "SIGURG",
                24: "SIGXCPU",
                25: "SIGXFSZ",
                26: "SIGVTALRM",
                27: "SIGPROF",
                28: "SIGWINCH",
                29: "SIGIO",
                30: "SIGPWR",
                31: "SIGSYS",
                32: "SIGCANCEL", # from glibc source code
                33: "SIGSETXID", # from glibc source code
                34: "SIGRTMIN",
                # 35 ... 49: SIGRTMIN+i
                # 50 ... 63: SIGRTMAX-i
                64: "SIGRTMAX",
            }
            for i in range(35, 50):
                self.signame_list[i] = "SIGRTMIN+{:d}".format(i - 34)
            for i in range(63, 49, -1):
                self.signame_list[i] = "SIGRTMAX-{:d}".format(64 - i)

        # task_struct->seccomp
        if args.print_seccomp:
            if self.offset_signal is None:
                self.offset_signal = self.get_offset_signal(self.offset_nsproxy)
            self.quiet_info("offsetof(task_struct, signal): {:#x}".format(self.offset_signal))

            if self.offset_seccomp is None:
                self.offset_seccomp = self.get_offset_seccomp(task_addrs, self.offset_signal)
            if self.offset_seccomp is None:
                self.quiet_err("Not found task_struct->seccomp")
                return False
            self.quiet_info("offsetof(task_struct, seccomp): {:#x}".format(self.offset_seccomp))

            if self.offset_prev is None:
                self.offset_prev = self.get_offset_prev(task_addrs, self.offset_seccomp)
            if self.offset_prev is None:
                self.quiet_err("Not found seccomp_filter->prev")
                return False
            self.quiet_info("offsetof(seccomp_filter, prev): {:#x}".format(self.offset_prev))

            if self.offset_prog is None:
                self.offset_prog = self.get_offset_prog(self.offset_prev)
            if self.offset_prog is None:
                self.quiet_err("Not found seccomp_filter->prog")
                return False
            self.quiet_info("offsetof(seccomp_filter, prog): {:#x}".format(self.offset_prog))

            if self.offset_bpf_func is None:
                self.offset_bpf_func = self.get_offset_bpf_func(task_addrs, self.offset_seccomp, self.offset_prog)
            if self.offset_bpf_func is None:
                self.quiet_err("Not found bpf_prog->bpf_func")
                return False
            self.quiet_info("offsetof(bpf_prog, bpf_func): {:#x}".format(self.offset_bpf_func))

            if self.offset_orig_prog is None:
                self.offset_orig_prog = self.get_offset_orig_prog(self.offset_bpf_func)
            if self.offset_orig_prog is None:
                self.quiet_err("Not found bpf_prog->orig_prog")
                return False
            self.quiet_info("offsetof(bpf_prog: orig_prog): {:#x}".format(self.offset_orig_prog))

            try:
                self.seccomp_tools_command = GefUtil.which("seccomp-tools")
                self.quiet_info("seccomp-tools is found")
                if is_arm32():
                    if not self.quiet:
                        warn("seccomp-tools is unsupported on arm32")
            except FileNotFoundError:
                self.quiet_info("seccomp-tools is not found, use `capstone-disable bpf_func`")
                self.seccomp_tools_command = None

        return task_addrs

    def dump(self, args, task_addrs):
        # LWP
        if args.print_thread:
            task_addrs = self.add_lwp_task(task_addrs)

        # print legend
        out = []
        if not self.quiet:
            fmt = "{:<18s} {:3s} {:<7s} {:<16s} {:<18s} [{:s}] {:<8s} {:<18s} {:<18s}"
            if args.print_all_id:
                ids_str = ["uid", "gid", "suid", "sgid", "euid", "egid", "fsuid", "fsgid"]
                uids_fmt = "{:>5s} {:>5s} {:>5s} {:>5s} {:>5s} {:>5s} {:>5s} {:>5s}"
            else:
                ids_str = ["uid", "gid"]
                uids_fmt = "{:>5s} {:>5s}"
            uids_str = uids_fmt.format(*ids_str)
            legend = ["task", "K/U", "lwpid", "task->comm", "task->cred", uids_str, "seccomp", "kstack", "kcanary"]
            out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        if args.print_namespace:
            kversion = Kernel.kernel_version()
            nsproxy_members = ["count", "uts_ns", "ipc_ns", "mnt_ns", "pid_ns_for_children", "net_ns"]
            if kversion >= "5.6":
                nsproxy_members += ["time_ns", "time_ns_for_children"]
            if kversion >= "4.6":
                nsproxy_members += ["cgroup_ns"]
            if task_addrs:
                init_cred = read_int_from_memory(task_addrs[0] + self.offset_cred)
                init_user_ns = read_int_from_memory(init_cred + self.offset_user_ns)
                init_nsproxy = read_int_from_memory(task_addrs[0] + self.offset_nsproxy)

        # task parse
        tqdm = GefUtil.get_tqdm(not args.quiet)
        for task in tqdm(task_addrs, leave=False):
            comm_string = read_cstring_from_memory(task + self.offset_comm)
            if args.filter:
                if not any(re_pattern.search(comm_string) for re_pattern in args.filter):
                    continue

            kstack = read_int_from_memory(task + self.offset_stack)
            pid = u32(read_memory(task + self.offset_pid, 4))
            cred = read_int_from_memory(task + self.offset_cred)

            # get process type (kernel or user-land)
            mm = read_int_from_memory(task + self.offset_mm)
            if mm == 0 or pid == 0:
                proctype = "K"
            else:
                proctype = "U"

            if args.user_process_only:
                if proctype == "K":
                    continue

            # get process type (main process or not)
            if args.print_thread:
                leader = read_int_from_memory(task + self.offset_group_leader)
                if leader != task:
                    proctype += "T"

            # uid
            if args.print_all_id:
                uids = [u32(read_memory(cred + self.offset_uid + j * 4, 4)) for j in range(8)]
                uids_fmt = "{:>5d},{:>5d},{:>5d},{:>5d},{:>5d},{:>5d},{:>5d},{:>5d}"
            else:
                uids = [u32(read_memory(cred + self.offset_uid + j * 4, 4)) for j in range(2)]
                uids_fmt = "{:>5d},{:>5d}"
            uids_str = uids_fmt.format(*uids)

            # kcanary
            if self.offset_kcanary:
                kcanary = read_int_from_memory(task + self.offset_kcanary)
                kcanary = "{:#018x}".format(kcanary)
            else:
                kcanary = "None"

            # seccomp
            if self.has_seccomp(task):
                seccomp = "Enabled"
            else:
                seccomp = "Disabled"

            # make output
            out.append("{:#018x} {:<3s} {:<7d} {:<16s} {:#018x} [{:s}] {:<8s} {:#018x} {:<18s}".format(
                task, proctype, pid, comm_string, cred, uids_str, seccomp, kstack, kcanary,
            ))

            # skip additional information when swapper/N
            if pid == 0:
                continue

            additional = False

            # additional information (maps)
            if args.print_maps:
                additional = True
                mms = self.get_mm(task, self.offset_mm)
                if mms:
                    out.append(titlify("memory map of `{:s}`".format(comm_string)))
                    for mm in mms:
                        out.append("{:#018x}-{:#018x} {:s} {:s}".format(mm.start, mm.end, mm.flags, mm.file))

            # additional information (regs)
            if proctype == "U" and args.print_regs:
                additional = True
                regs = self.get_regs(kstack, self.offset_ptregs)
                syscall_table = get_syscall_table().table
                syscall_nr_regs = ["orig_rax", "orig_eax", "r7", "x8"]
                if regs:
                    out.append(titlify("registers of `{:s}`".format(comm_string)))
                    for k, v in regs.items():
                        if k in syscall_nr_regs and v in syscall_table:
                            syscall_name = syscall_table[v].name
                            out.append("{:16s}: {:s} ({:s})".format(
                                k, AddressUtil.format_address(v, long_fmt=True), syscall_name,
                            ))
                        else:
                            out.append("{:16s}: {:s}".format(
                                k, AddressUtil.format_address(v, long_fmt=True,
                            )))

            # additional information (files)
            if proctype == "U" and args.print_fd:
                additional = True
                out.append(titlify("file descriptors of `{:s}`".format(comm_string)))
                fmt = "{:3s} {:18s} {:18s} {:18s} {:s}"
                legend = ["fd", "struct file", "struct dentry", "struct inode", "path"]
                out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

                files = read_int_from_memory(task + self.offset_files)
                fdt = read_int_from_memory(files + self.offset_fdt)
                if is_valid_addr(fdt):
                    max_fds = u32(read_memory(fdt, 4))
                    array = read_int_from_memory(fdt + current_arch.ptrsize)
                    for i in range(max_fds):
                        file = read_int_from_memory(array + current_arch.ptrsize * i)
                        if file == 0:
                            continue
                        dentry = read_int_from_memory(file + self.offset_dentry)
                        inode = read_int_from_memory(dentry + self.offset_d_inode)
                        filepath = self.get_filepath(file)
                        out.append("{:<3d} {:#018x} {:#018x} {:#018x} {:s}".format(i, file, dentry, inode, filepath))

            # additional information (sighands)
            if proctype == "U" and args.print_sighand:
                additional = True
                out.append(titlify("sighandlers of `{:s}`".format(comm_string)))
                fmt = "{:14s} {:18s} {:18s} {:18s}"
                legend = ["sig", "sigaction", "handler", "flags"]
                out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

                sighand = read_int_from_memory(task + self.offset_sighand)
                for i in range(64):
                    sigaction = sighand + self.offset_action + self.sizeof_action * i
                    signame = self.signame_list.get(i + 1, "???")
                    handler = read_int_from_memory(sigaction + current_arch.ptrsize * 0)
                    if handler == 0:
                        handler = "SIG_DFL"
                    elif handler == 1:
                        handler = "SIG_IGN"
                    elif handler == -1:
                        handler = "SIG_ERR"
                    else:
                        handler = "{:#018x}".format(handler)
                    flags = read_int_from_memory(sigaction + current_arch.ptrsize * 1)
                    out.append("{:<2d} {:11s} {:#018x} {:18s} {:#018x}".format(i + 1, signame, sigaction, handler, flags))

            # additional information (namespace)
            if proctype == "U" and args.print_namespace:
                additional = True
                out.append(titlify("namespace of `{:s}`".format(comm_string)))
                fmt = "{:30s} {:18s} {:8s}"
                legend = ["name", "value", "init_ns?"]
                out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

                # user_ns (via real_cred)
                real_cred = read_int_from_memory(task + self.offset_cred - current_arch.ptrsize)
                user_ns = read_int_from_memory(real_cred + self.offset_user_ns)
                is_init_ns = str(user_ns == init_user_ns)
                out.append("{:30s} {:#018x} {:8s}".format("real_cred->user_ns", user_ns, is_init_ns))

                # other ns (via nsproxy)
                nsproxy = read_int_from_memory(task + self.offset_nsproxy)
                for i, name in enumerate(nsproxy_members):
                    value = read_int_from_memory(nsproxy + current_arch.ptrsize * i)
                    if i == 0:
                        is_init_ns = "-"
                    else:
                        init_value = read_int_from_memory(init_nsproxy + current_arch.ptrsize * i)
                        is_init_ns = str(value == init_value)
                    out.append("{:30s} {:#018x} {:8s}".format("nsproxy->" + name, value, is_init_ns))

            # additional information (seccomp)
            if proctype == "U" and args.print_seccomp:
                if self.has_seccomp(task):
                    additional = True
                    out.append(titlify("seccomp of `{:s}`".format(comm_string)))
                    fmt = "{:18s} {:25s} {:12s} {:18s}"
                    legend = ["&task.seccomp", "mode", "filter_count", "filter"]
                    out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

                    seccomp = task + self.offset_seccomp
                    mode = u32(read_memory(seccomp, 4))
                    mode_define = {
                        0: "SECCOMP_MODE_DISABLED",
                        1: "SECCOMP_MODE_STRICT",
                        2: "SECCOMP_MODE_FILTER",
                    }.get(mode, "UNKNOWN")
                    mode_str = "{:d} ({:s})".format(mode, mode_define)
                    filter_count = u32(read_memory(seccomp + 4, 4))
                    filter_current = read_int_from_memory(seccomp + 4 * 2)
                    out.append("{:#018x} {:25s} {:<12d} {:#018x}".format(seccomp, mode_str, filter_count, filter_current))

                    i = 1
                    while filter_current and i <= filter_count:
                        prog = read_int_from_memory(filter_current + self.offset_prog)
                        filter_prev = read_int_from_memory(filter_current + self.offset_prev)
                        bpf_func = read_int_from_memory(prog + self.offset_bpf_func)
                        orig_prog = read_int_from_memory(prog + self.offset_orig_prog)

                        out.append("")
                        out.append("[{:d}/{:d}] filter:{:#x} prev:{:#x} bpf_func:{:#x} orig_prog:{:#x}".format(
                            i, filter_count, filter_current, filter_prev, bpf_func, orig_prog,
                        ))

                        if self.seccomp_tools_command:
                            cnt = read_int_from_memory(orig_prog) & 0xffff
                            prog = read_int_from_memory(orig_prog + current_arch.ptrsize)
                            data = read_memory(prog, cnt * 8)
                            tmp_fd, tmp_path = tempfile.mkstemp(dir=GEF_TEMP_DIR, prefix="ktask_")
                            os.fdopen(tmp_fd, "wb").write(data)
                            ret = GefUtil.gef_execute_external([self.seccomp_tools_command, "disasm", tmp_path], as_list=True)
                            out.extend(ret)
                            os.unlink(tmp_path)
                        else:
                            ret = gdb.execute("capstone-disassemble {:#x}".format(bpf_func), to_string=True).rstrip()
                            out.append(ret)
                            out.append("      ...")

                        filter_current = filter_prev
                        i += 1

            # print separator
            if additional:
                out.append(titlify(""))
        return out

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet
        self.quiet_info("Wait for memory scan")
        self.filepath_cache = {}

        # initialize
        ret = self.initialize(args)
        if ret is False:
            return
        task_addrs = ret

        # skip real parse if specified --meta option
        if args.meta:
            return

        out = self.dump(args, task_addrs)
        gef_print("\n".join(out), less=not args.no_pager)
        return


@register_command
class KernelFilesCommand(GenericCommand):
    """Display open files list of each process (shortcut for `ktask -quF`)."""
    _cmdline_ = "kfiles"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        info("Redirect to `ktask -quF`")

        no_pager = ""
        if args.no_pager:
            no_pager = "--no-pager"
        gdb.execute("ktask --user-process-only --print-fd --quiet {:s}".format(no_pager))
        return


@register_command
class KernelSavedRegsCommand(GenericCommand):
    """Display saved registers of each process (shortcut for `ktask -qur`)."""
    _cmdline_ = "kregs"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        info("Redirect to `ktask -qur`")

        no_pager = ""
        if args.no_pager:
            no_pager = "--no-pager"
        gdb.execute("ktask --user-process-only --print-regs --quiet {:s}".format(no_pager))
        return


@register_command
class KernelSignalsCommand(GenericCommand):
    """Display signal handlers of each process (shortcut for `ktask -qus`)."""
    _cmdline_ = "ksighands"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        info("Redirect to `ktask -qus`")

        no_pager = ""
        if args.no_pager:
            no_pager = "--no-pager"
        gdb.execute("ktask --user-process-only --print-sighand --quiet {:s}".format(no_pager))
        return


@register_command
class KernelNamespacesCommand(GenericCommand):
    """Display namespaces of each process (shortcut for `ktask -quN`)."""
    _cmdline_ = "knamespaces"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        info("Redirect to `ktask -quN`")

        no_pager = ""
        if args.no_pager:
            no_pager = "--no-pager"
        gdb.execute("ktask --user-process-only --print-namespace --quiet {:s}".format(no_pager))
        return


@register_command
class KernelModuleCommand(GenericCommand):
    """Display kernel module list."""
    _cmdline_ = "kmod"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-s", "--resolve-symbol", action="store_true", help="try to resolve symbols.")
    parser.add_argument("--symbol-unsort", action="store_true",
                        help="print resolved symbols without sorting by address.")
    parser.add_argument("-f", "--filter", action="append", type=re.compile, default=[], help="REGEXP filter.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -q".format(_cmdline_)

    _note_ = "This command needs CONFIG_RANDSTRUCT=n.\n"
    _note_ += "\n"
    _note_ += "Simplified clocksource structure:\n"
    _note_ += "\n"
    _note_ += "                   +-module------------------+\n"
    _note_ += "+-modules-----+    | ...                     |\n"
    _note_ += "| list_head   |--->| list                    |--->...\n"
    _note_ += "+-------------+    | name[]                  |\n"
    _note_ += "                   | ...                     |\n"
    _note_ += "                   | mem[] (v6.4~)           |\n"
    _note_ += "                   |     base                |\n"
    _note_ += "                   |     size                |\n"
    _note_ += "                   |     ...                 |\n"
    _note_ += "                   | init_layout (v4.5~v6.4) |\n"
    _note_ += "                   |     base                |\n"
    _note_ += "                   |     size                |\n"
    _note_ += "                   |     text_size           |\n"
    _note_ += "                   |     ro_size             |\n"
    _note_ += "                   |     ro_after_init_size  |\n"
    _note_ += "                   |     ...                 |\n"
    _note_ += "                   | module_core    (~v4.5)  |\n"
    _note_ += "                   | init_size      (~v4.5)  |\n"
    _note_ += "                   | core_size      (~v4.5)  |\n"
    _note_ += "                   | init_text_size (~v4.5)  |  +-->+-mod_kallsyms---+\n"
    _note_ += "                   | core_text_size (~v4.5)  |  |   | symtab         |\n"
    _note_ += "                   | ...                     |  |   | num_symtab     |\n"
    _note_ += "                   | kallsyms                |--+   | strtab         |\n"
    _note_ += "                   | ...                     |      | typetab (v5.2~)|\n"
    _note_ += "                   +-------------------------+      +----------------+"

    def get_modules_list(self):
        modules = KernelAddressHeuristicFinder.get_modules()
        if modules is None:
            if not self.quiet:
                err("Not found modules (maybe, CONFIG_MODULES is not set)")
            return None

        if not self.quiet:
            info("modules: {:#x}".format(modules))

        module_addrs = []
        current = modules
        while True:
            try:
                addr = read_int_from_memory(current)
            except gdb.MemoryError:
                return None
            if addr == modules:
                break
            module_addrs.append(addr - current_arch.ptrsize)
            current = addr
        return module_addrs

    def get_offset_name(self, module_addrs):
        for i in range(0x100):
            offset_name = i * current_arch.ptrsize
            valid = True
            for module in module_addrs:
                if not is_ascii_string(module + offset_name):
                    valid = False
                    break
                s = read_cstring_from_memory(module + offset_name)
                if len(s) < 2:
                    valid = False
                    break
            if valid:
                if not self.quiet:
                    info("offsetof(module, name): {:#x}".format(offset_name))
                return offset_name

        if not self.quiet:
            err("Not found module->name[MODULE_NAME_LEN]")
        return None

    def get_offset_mem(self, module_addrs): # v6.4~
        """
        ac3b43283923440900b4f36ca5f9f0b1ca43b70e changed the module layout information structure
        MOD_TEXT = 0,
        MOD_DATA,
        MOD_RODATA,
        MOD_RO_AFTER_INIT,
        MOD_INIT_TEXT,
        MOD_INIT_DATA,
        MOD_INIT_RODATA,

        struct module {
            enum module_state state;
            struct list_head list;
            char name[MODULE_NAME_LEN]; // 64 - sizeof(unsigned long) bytes
        #ifdef CONFIG_STACKTRACE_BUILD_ID
            unsigned char build_id[BUILD_ID_SIZE_MAX]; // 20 bytes
        #endif
            struct module_kobject mkobj;
            struct module_attribute *modinfo_attrs;
            const char *version;
            const char *srcversion;
            struct kobject *holders_dir;
            const struct kernel_symbol *syms;
            const s32 *crcs;
            unsigned int num_syms;
        #ifdef CONFIG_ARCH_USES_CFI_TRAPS
            s32 *kcfi_traps;
            s32 *kcfi_traps_end;
        #endif
        #ifdef CONFIG_SYSFS
            struct mutex param_lock;
        #endif
            struct kernel_param *kp;
            unsigned int num_kp;
            unsigned int num_gpl_syms;
            const struct kernel_symbol *gpl_syms;
            const s32 *gpl_crcs;
            bool using_gplonly_symbols;
        #ifdef CONFIG_MODULE_SIG
            bool sig_ok;
        #endif
            bool async_probe_requested;
            unsigned int num_exentries;
            struct exception_table_entry *extable;
            int (*init)(void);
            struct module_memory mem[MOD_MEM_NUM_TYPES] __module_memory_align;
            struct mod_arch_specific arch;
            unsigned long taints;
        #ifdef CONFIG_GENERIC_BUG
            unsigned num_bugs;
            struct list_head bug_list;
            struct bug_entry *bug_table;
        #endif
        #ifdef CONFIG_KALLSYMS
            struct mod_kallsyms __rcu *kallsyms;
            struct mod_kallsyms core_kallsyms;
            struct module_sect_attrs *sect_attrs;
            struct module_notes_attrs *notes_attrs;
        #endif
        };

        struct module_memory {
            void *base;
            unsigned int size;
        #ifdef CONFIG_MODULES_TREE_LOOKUP
            struct mod_tree_node mtn; (0x38)
        #endif
        };
        """
        MOD_TEXT = 0
        MOD_DATA = 1
        MOD_RODATA = 2
        MOD_RO_AFTER_INIT = 3 # noqa: F841
        MOD_INIT_TEXT = 4 # noqa: F841
        MOD_INIT_DATA = 5 # noqa: F841
        MOD_INIT_RODATA = 6 # noqa: F841
        MOD_MEM_NUM_TYPES = 7 # noqa: F841
        # TODO: only handles non init module type
        for i in range(300):
            offset_mem = i * current_arch.ptrsize
            for sizeof_module_memory in (8, 0x48):
                valid = True
                for module in module_addrs:
                    for mem_type in (MOD_TEXT, MOD_DATA, MOD_RODATA):
                        # memory access check
                        if not is_valid_addr(module + offset_mem + mem_type * sizeof_module_memory):
                            valid = False
                            break
                        # base align check
                        cand_base = read_int_from_memory(module + offset_mem + mem_type * sizeof_module_memory)
                        if cand_base == 0 or cand_base & 0xfff:
                            valid = False
                            break
                        # size check
                        cand_size = u32(read_memory(module + offset_mem + mem_type * sizeof_module_memory + current_arch.ptrsize + 4 * 0, 4))
                        if cand_size == 0 or cand_size > 0x100000:
                            valid = False
                            break
                if valid:
                    if not self.quiet:
                        info(f"offsetof(module, mem): {offset_mem:#x}")
                        info(f"sizeof(module_memory): {sizeof_module_memory:#x}")
                    return offset_mem
        if not self.quiet:
            err("Not found module->mem")
        return None

    def get_offset_layout(self, module_addrs): # v4.5 ~ v6.4
        """
        struct module { // kernel v4.5-rc1~
            enum module_state state;
            struct list_head list;
            char name[MODULE_NAME_LEN]; // 64 - sizeof(unsigned long) bytes
        #ifdef CONFIG_STACKTRACE_BUILD_ID
            unsigned char build_id[BUILD_ID_SIZE_MAX]; // 20 bytes
        #endif
            struct module_kobject mkobj;
            struct module_attribute *modinfo_attrs;
            const char *version;
            const char *srcversion;
            struct kobject *holders_dir;
            const struct kernel_symbol *syms;
            const s32 *crcs;
            unsigned int num_syms;
        #ifdef CONFIG_CFI_CLANG
            cfi_check_fn cfi_check;
        #endif
        #ifdef CONFIG_SYSFS
            struct mutex param_lock;
        #endif
            struct kernel_param *kp;
            unsigned int num_kp;
            unsigned int num_gpl_syms;
            const struct kernel_symbol *gpl_syms;
            const s32 *gpl_crcs;
            bool using_gplonly_symbols;
        #ifdef CONFIG_MODULE_SIG
            bool sig_ok;
        #endif
            bool async_probe_requested;
            unsigned int num_exentries;
            struct exception_table_entry *extable;
            int (*init)(void);
            struct module_layout core_layout __module_layout_align;
            struct module_layout init_layout;
        #ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC
            struct module_layout data_layout;
        #endif
            struct mod_arch_specific arch;
            unsigned long taints;
        #ifdef CONFIG_GENERIC_BUG
            unsigned num_bugs;
            struct list_head bug_list;
            struct bug_entry *bug_table;
        #endif
        #ifdef CONFIG_KALLSYMS
            struct mod_kallsyms __rcu *kallsyms;
            struct mod_kallsyms core_kallsyms;
            struct module_sect_attrs *sect_attrs;
            struct module_notes_attrs *notes_attrs;
        #endif
            ...
        };

        struct module_layout {
            /* The actual code + data. */
            void *base;
            /* Total size. */
            unsigned int size;
            /* The size of the executable code.  */
            unsigned int text_size;
            /* Size of RO section of the module (text+rodata) */
            unsigned int ro_size;
            /* Size of RO after init section */
            unsigned int ro_after_init_size;
        #ifdef CONFIG_MODULES_TREE_LOOKUP
            struct mod_tree_node mtn;
        #endif
        };

        [Example arm32]
            gef> x/128xw 0x00000000bf22b084
            0xbf22b084:     0xbf1bb044      0xc1696530      0x00006773      0x00000000
            0xbf22b094:     0x00000000      0x00000000      0x00000000      0x00000000
            0xbf22b0a4:     0x00000000      0x00000000      0x00000000      0x00000000
            0xbf22b0b4:     0x00000000      0x00000000      0x00000000      0x00000000
            0xbf22b0c4:     0x00000000      0xc1ec2d00      0xc1a11d80      0xbf1bb08c
            0xbf22b0d4:     0xc1a11d8c      0xc1a11d80      0xc1628e38      0xc8e0b2c0
            0xbf22b0e4:     0x00000003      0x00000007      0xbf22b080      0x00000000
            0xbf22b0f4:     0xc8d4f380      0x00000000      0xc1e47400      0xc8f6d900
            0xbf22b104:     0xc8f6d080      0xc8004300      0x00000000      0x00000000
            0xbf22b114:     0x00000000      0x00000000      0x00000000      0x00000000
            0xbf22b124:     0xbf22b124      0xbf22b124      0xbf22a990      0x00000003
            0xbf22b134:     0x00000000      0x00000000      0x00000000      0x00000001
            0xbf22b144:     0x00000000      0x00000000      0x00000000      0x00000000
            0xbf22b154:     0x00000000      0xbf17e000      0x00000000      0x00000000
            0xbf22b164:     0x00000000      0x00000000      0x00000000      0x00000000
            0xbf22b174:     0x00000000      0x00000000      0x00000000      0xbf225000 <- init_layout.base
            0xbf22b184:     0x00008000      0x00005000      0x00006000      0x00006000
        """
        for i in range(300):
            offset_layout = i * current_arch.ptrsize
            valid = True
            for module in module_addrs:
                # memory access check
                if not is_valid_addr(module + offset_layout):
                    valid = False
                    break
                # base align check
                cand_base = read_int_from_memory(module + offset_layout)
                if cand_base == 0 or cand_base & 0xfff:
                    valid = False
                    break
                # size check
                cand_size = u32(read_memory(module + offset_layout + current_arch.ptrsize + 4 * 0, 4))
                if cand_size == 0 or cand_size > 0x200000:
                    valid = False
                    break
                # text_size check
                cand_text_size = u32(read_memory(module + offset_layout + current_arch.ptrsize + 4 * 1, 4))
                if cand_text_size == 0 or cand_text_size > 0x200000:
                    valid = False
                    break
                # ro_size check
                cand_ro_size = u32(read_memory(module + offset_layout + current_arch.ptrsize + 4 * 2, 4))
                if cand_ro_size == 0 or cand_ro_size > 0x200000:
                    valid = False
                    break
                # ro_after_init_size check
                cand_ro_after_init_size = u32(read_memory(module + offset_layout + current_arch.ptrsize + 4 * 3, 4))
                if cand_ro_after_init_size == 0 or cand_ro_after_init_size > 0x200000:
                    valid = False
                    break
            if valid:
                if not self.quiet:
                    info("offsetof(module, init_layout): {:#x}".format(offset_layout))
                return offset_layout

        if not self.quiet:
            err("Not found module->init_layout")
        return None

    def get_offset_module_core(self, module_addrs): # ~ v4.5
        """
        struct module { // ~v4.5-rc1
            enum module_state state;
            struct list_head list;
            char name[MODULE_NAME_LEN];
            struct module_kobject mkobj;
            struct module_attribute *modinfo_attrs;
            const char *version;
            const char *srcversion;
            struct kobject *holders_dir;
            const struct kernel_symbol *syms;
            const unsigned long *crcs;
            unsigned int num_syms;
        #ifdef CONFIG_SYSFS
            struct mutex param_lock;
        #endif
            struct kernel_param *kp;
            unsigned int num_kp;
            unsigned int num_gpl_syms;
            const struct kernel_symbol *gpl_syms;
            const unsigned long *gpl_crcs;
        #ifdef CONFIG_UNUSED_SYMBOLS
            const struct kernel_symbol *unused_syms;
            const unsigned long *unused_crcs;
            unsigned int num_unused_syms;
            unsigned int num_unused_gpl_syms;
            const struct kernel_symbol *unused_gpl_syms;
            const unsigned long *unused_gpl_crcs;
        #endif
        #ifdef CONFIG_MODULE_SIG
            bool sig_ok;
        #endif
            bool async_probe_requested;
            const struct kernel_symbol *gpl_future_syms;
            const unsigned long *gpl_future_crcs;
            unsigned int num_gpl_future_syms;
            unsigned int num_exentries;
            struct exception_table_entry *extable;
            int (*init)(void);
            void *module_init ____cacheline_aligned;
            /* Here is the actual code + data, vfree'd on unload. */
            void *module_core;
            /* Here are the sizes of the init and core sections */
            unsigned int init_size, core_size;
            /* The size of the executable code in each section. */
            unsigned int init_text_size, core_text_size;
        #ifdef CONFIG_MODULES_TREE_LOOKUP
            struct mod_tree_node mtn_core;
            struct mod_tree_node mtn_init;
        #endif
            unsigned int init_ro_size, core_ro_size;
            struct mod_arch_specific arch;
            unsigned int taints;
        #ifdef CONFIG_GENERIC_BUG
            unsigned num_bugs;
            struct list_head bug_list;
            struct bug_entry *bug_table;
        #endif
        #ifdef CONFIG_KALLSYMS
            struct mod_kallsyms *kallsyms;
            struct mod_kallsyms core_kallsyms;
            struct module_sect_attrs *sect_attrs;
            struct module_notes_attrs *notes_attrs;
        #endif
            ...
        };
        """
        for i in range(300):
            offset_module_core = i * current_arch.ptrsize
            valid = True
            for module in module_addrs:
                # memory access check
                if not is_valid_addr(module + offset_module_core):
                    valid = False
                    break
                # module_core align check
                cand_module_core = read_int_from_memory(module + offset_module_core)
                if cand_module_core == 0 or cand_module_core & 0xfff:
                    valid = False
                    break
                # init_size check
                cand_init_size = u32(read_memory(module + offset_module_core + current_arch.ptrsize + 4 * 0, 4))
                if cand_init_size > 0x100000:
                    valid = False
                    break
                # core_size check
                cand_core_size = u32(read_memory(module + offset_module_core + current_arch.ptrsize + 4 * 1, 4))
                if cand_core_size == 0 or cand_core_size > 0x100000:
                    valid = False
                    break
                # init_text_size check
                cand_init_text_size = u32(read_memory(module + offset_module_core + current_arch.ptrsize + 4 * 2, 4))
                if cand_init_text_size > 0x100000:
                    valid = False
                    break
                # core_text_size check
                cand_core_text_size = u32(read_memory(module + offset_module_core + current_arch.ptrsize + 4 * 3, 4))
                if cand_core_text_size == 0 or cand_core_text_size > 0x100000:
                    valid = False
                    break
            if valid:
                if not self.quiet:
                    info("offsetof(module, module_core): {:#x}".format(offset_module_core))
                return offset_module_core

        if not self.quiet:
            err("Not found module->module_core")
        return None

    def get_offset_kallsyms(self, module_addrs):
        """
        struct mod_kallsyms {
            Elf_Sym *symtab;
            unsigned int num_symtab;
            char *strtab;
            char *typetab; // v5.2~
        };
        """
        kversion = Kernel.kernel_version()
        for i in range(300):
            offset_kallsyms = i * current_arch.ptrsize
            valid = True
            for module in module_addrs:
                # access check
                if not is_valid_addr(module + offset_kallsyms):
                    valid = False
                    break
                # kallsyms access check
                cand_kallsyms = read_int_from_memory(module + offset_kallsyms)
                if not is_valid_addr(cand_kallsyms):
                    valid = False
                    break
                # struct mod_kallsyms member access check
                cand_symtab = read_int_from_memory(cand_kallsyms)
                if not is_valid_addr(cand_symtab):
                    valid = False
                    break
                cand_num_symtab = read_int_from_memory(cand_kallsyms + current_arch.ptrsize * 1)
                if is_valid_addr(cand_num_symtab) or cand_num_symtab == 0:
                    valid = False
                    break
                cand_strtab = read_int_from_memory(cand_kallsyms + current_arch.ptrsize * 2)
                if not is_valid_addr(cand_strtab):
                    valid = False
                    break
                if kversion >= "5.2":
                    cand_typetab = read_int_from_memory(cand_kallsyms + current_arch.ptrsize * 3)
                    if not is_valid_addr(cand_typetab):
                        valid = False
                        break
            if valid:
                if not self.quiet:
                    info("offsetof(module, kallsyms): {:#x}".format(offset_kallsyms))
                return offset_kallsyms

        if not self.quiet:
            err("Not found module->kallsyms")
        return None

    def parse_kallsyms(self, kallsyms):
        kversion = Kernel.kernel_version()

        symtab = read_int_from_memory(kallsyms + current_arch.ptrsize * 0)
        sizeof_symtab_entry = 24 if is_64bit() else 16
        num_symtab = read_int_from_memory(kallsyms + current_arch.ptrsize * 1)
        strtab = read_int_from_memory(kallsyms + current_arch.ptrsize * 2)
        strtab_pos = 0
        if kversion >= "5.2":
            typetab = read_int_from_memory(kallsyms + current_arch.ptrsize * 3)

        #gef_print("symtab: {:#x}".format(symtab))
        #gef_print("sizeof_symtab_entry: {:#x}".format(sizeof_symtab_entry))
        #gef_print("num_symab: {:#x}".format(num_symtab))
        #gef_print("strtab: {:#x}".format(strtab))
        #if kversion >= "5.2":
        #    gef_print("typetab: {:#x}".format(typetab))

        entries = []
        for i in range(num_symtab):
            sym_addr = read_int_from_memory(symtab + sizeof_symtab_entry * i + current_arch.ptrsize)
            sym_name = read_cstring_from_memory(strtab + strtab_pos)
            strtab_pos += len(sym_name) + 1

            if kversion >= "5.2":
                sym_type = chr(u8(read_memory(typetab + i, 1)))
            elif kversion >= "5.0":
                # st_size
                if is_64bit():
                    sym_type = chr(u8(read_memory(symtab + sizeof_symtab_entry * i + 16, 1)))
                else:
                    sym_type = chr(u8(read_memory(symtab + sizeof_symtab_entry * i + 8, 1)))
            else:
                # st_info
                if is_64bit():
                    sym_type = chr(u8(read_memory(symtab + sizeof_symtab_entry * i + 4, 1)))
                else:
                    sym_type = chr(u8(read_memory(symtab + sizeof_symtab_entry * i + 12, 1)))
            entries.append([sym_addr, sym_type, sym_name])
        return entries

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet

        if not self.quiet:
            info("Wait for memory scan")

        module_addrs = self.get_modules_list()
        if module_addrs is None:
            return

        offset_name = self.get_offset_name(module_addrs)
        if offset_name is None:
            return

        kversion = Kernel.kernel_version()
        if kversion >= "6.4":
            offset_mem = self.get_offset_mem(module_addrs)
            if offset_mem is None:
                return
        elif kversion >= "4.5":
            offset_layout = self.get_offset_layout(module_addrs)
            if offset_layout is None:
                return
        else: # ~ v4.5
            offset_module_core = self.get_offset_module_core(module_addrs)
            if offset_module_core is None:
                return

        if args.resolve_symbol:
            offset_kallsyms = self.get_offset_kallsyms(module_addrs)
            if offset_kallsyms is None:
                return

        self.out = []
        if not self.quiet:
            fmt = "{:<18s} {:<24s} {:<18s} {:<18s}"
            legend = ["module", "module->name", "base", "size"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        tqdm = GefUtil.get_tqdm(not args.quiet)
        for module in tqdm(module_addrs, leave=False):
            name_string = read_cstring_from_memory(module + offset_name)
            if args.filter:
                if not any(re_pattern.search(name_string) for re_pattern in args.filter):
                    continue

            if kversion >= "6.4":
                base = read_int_from_memory(module + offset_mem)
                size = u32(read_memory(module + offset_mem + current_arch.ptrsize, 4))
            elif kversion >= "4.5":
                base = read_int_from_memory(module + offset_layout)
                size = u32(read_memory(module + offset_layout + current_arch.ptrsize, 4))
            else: # ~ 4.5
                base = read_int_from_memory(module + offset_module_core)
                size = u32(read_memory(module + offset_module_core + current_arch.ptrsize + 4, 4))
            self.out.append("{:#018x} {:<24s} {:#018x} {:#018x}".format(module, name_string, base, size))

            if args.resolve_symbol:
                self.out.append(titlify("module symbols"))
                kallsyms = read_int_from_memory(module + offset_kallsyms)
                entries = self.parse_kallsyms(kallsyms)

                # symbol_unsort is used for debugging.
                if not args.symbol_unsort:
                    entries = sorted(entries)

                for sym_addr, sym_type, sym_name in entries:
                    self.out.append("{:#018x} {:s} {:s}".format(sym_addr, sym_type, sym_name))

                self.out.append(titlify(""))

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelBlockDevicesCommand(GenericCommand):
    """Display block device list."""
    _cmdline_ = "kbdev"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -q".format(_cmdline_)

    _note_ = "This command needs CONFIG_RANDSTRUCT=n.\n"
    _note_ += "If there are too many block devices, detection will not be successful.\n"
    _note_ += "This is because block devices are not managed in one place, \n"
    _note_ += "so I use the list of bdev_cache obtained from the slub-dump results."

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        self.offset_bd_dev = None
        return

    def get_bdev_list(self):
        allocator = KernelChecksecCommand.get_slab_type()
        if allocator == "SLUB":
            ret = gdb.execute("slub-dump --quiet --no-pager -vv bdev_cache", to_string=True)
        elif allocator == "SLUB_TINY":
            ret = gdb.execute("slub-tiny-dump --quiet --no-pager bdev_cache", to_string=True)
        else:
            if not self.quiet:
                err("Unsupported SLAB, SLOB")
            return None

        bdevs = []
        for line in ret.splitlines():
            line = Color.remove_color(line)
            r = re.search(r"(0x\S+) \(in-use\)", line)
            if not r:
                continue
            bdev = int(r.group(1), 16)
            bdevs.append(bdev)
        return bdevs

    @staticmethod
    def get_bdev_name(major, minor):
        # https://www.kernel.org/doc/Documentation/admin-guide/devices.txt
        # https://github.com/lrs-lang/lib/blob/master/src/dev/lib.rs
        dev_name_list = {
            0: "???",
            4: "/dev/root",
            7: "/dev/loop{:d}",
            9: "/dev/md{:d}",
            11: "/dev/scd{0:d} (sr{0:d})",
            12: "/dev/dos_cd{:d}",
            15: "/dev/sonycd",
            16: "/dev/gscd",
            17: "/dev/optcd",
            18: "/dev/sjcd",
            20: "/dev/hitcd",
            23: "/dev/mcd",
            24: "/dev/cdu535",
            29: "/dev/aztcd",
            30: "/dev/cm205cd",
            32: "/dev/cm206cd",
            35: "/dev/slram",
            37: "/dev/z2ram",
            41: "/dev/bpcd",
            43: "/dev/nb{:d}",
            46: "/dev/pcd{:d}",
            47: "/dev/pf{:d}",
            59: "/dev/pda{:d}",
            92: "/dev/ppdd{:d}",
            97: "/dev/pktcdvd",
            99: "/dev/jsfd",
            103: "/dev/audit",
            115: "/dev/nwfs/v{:d}",
            147: "/dev/drbd{:d}",
            152: "/dev/etherd/{:d}",
            199: "/dev/vx/dsk/*/*",
            201: "/dev/vx/dmp/*/*",
            258: "/dev/blockrom{:d}",
        }

        if major in dev_name_list:
            return dev_name_list[major].format(minor)

        def common_pattern(kind_sep, kind_max, devstr, sym_start="a"):
            kind = minor // kind_sep
            num = minor % kind_sep
            if kind < kind_max:
                dev = "/dev/{:s}{:s}".format(devstr, chr(ord(sym_start) + kind))
                if num:
                    dev = "{:s}{:d}".format(dev, num)
                return dev
            return "???"

        def common_pattern_num_p(kind_sep, kind_max, devstr, kind_offset=0):
            kind = minor // kind_sep
            num = minor % kind_sep
            if kind_max is None or kind < kind_max:
                dev = "/dev/{:s}{:d}".format(devstr, kind + kind_offset)
                if num:
                    dev = "{:s}p{:d}".format(dev, num)
                return dev
            return "???"

        def iterate_pattern(kind_sep, kind_max, dev_str, sym_start):
            def gen():
                cs = "abcdefghijklmnopqrstuvwxyz"
                for c in cs:
                    yield c
                for c1 in cs:
                    for c2 in cs:
                        yield c1 + c2
                return
            name_list = list(gen())
            kind = minor // kind_sep
            num = minor % kind_sep
            if kind < (kind_max or len(name_list)):
                offset = name_list.index(sym_start)
                dev = "/dev/{:s}{:s}".format(dev_str, name_list[offset + kind])
                if num:
                    dev = "{:s}{:d}".format(dev, num)
                return dev
            return "???"

        if major == 1:
            if 0 <= minor < 250:
                return "/dev/ram{:d}".format(minor)
            elif minor == 250:
                return "/dev/initrd"
        elif major == 2:
            if 0 <= minor < 128:
                num = minor % 4
            elif 128 <= minor < 256:
                num = 4 + minor % 4
            else:
                return "???"
            fd_type = (minor % 128) & ~0b11
            type_dic = {
                0: "",
                4: "d360",
                8: "h1200",
                12: "u360",
                16: "u720",
                20: "h360",
                24: "h720",
                28: "u1440",
                32: "u2880",
                36: "CompaQ",
                40: "h1440",
                44: "u1680",
                48: "h410",
                52: "u820",
                56: "h1476",
                60: "u1722",
                64: "h420",
                68: "u830",
                72: "h1494",
                76: "u1743",
                80: "h880",
                84: "u1040",
                88: "u1120",
                92: "h1600",
                96: "u1760",
                100: "u1920",
                104: "u3200",
                108: "u3520",
                112: "u3840",
                116: "u1840",
                120: "u800",
                124: "u1600",
            }
            if fd_type in type_dic:
                return "/dev/fd{:d}{:s}".format(num, type_dic[fd_type])
        elif major == 3:
            return common_pattern(64, 2, "hd", sym_start="a")
        elif major == 8:
            return iterate_pattern(16, 16, "sd", sym_start="a")
        elif major == 13:
            return common_pattern(64, 4, "xd")
        elif major == 14:
            return common_pattern(64, 4, "dos_hd")
        elif major == 19:
            if 0 <= minor < 8:
                return "/dev/double{:d}".format(minor)
            elif 128 <= minor < 136:
                return "/dev/cdouble{:d}".format(minor - 128)
        elif major == 21:
            return common_pattern(64, 2, "mfm")
        elif major == 22:
            return common_pattern(64, 2, "hd", sym_start="c")
        elif 25 <= major < 28:
            if 0 <= minor < 4:
                return "/dev/sbpcd{:d}".format(minor + (major - 25) * 4)
        elif major == 28: # 28 are duplicates
            if is_m68k():
                return common_pattern(16, 16, "ad")
            else:
                if 0 <= minor < 4:
                    return "/dev/sbpcd{:d}".format(minor + (major - 25) * 4)
        elif major == 31:
            if 0 <= minor < 8:
                return "/dev/rom{:d}".format(minor)
            elif 8 <= minor < 16:
                return "/dev/rrom{:d}".format(minor - 8)
            elif 16 <= minor < 24:
                return "/dev/flash{:d}".format(minor - 16)
            elif 24 <= minor < 32:
                return "/dev/rflash{:d}".format(minor - 24)
        elif 33 <= major < 35:
            return common_pattern(64, 2, "hd", sym_start=["e", "g"][major - 33])
        elif major == 36:
            return common_pattern(64, 4, "ed")
        elif major == 40:
            if minor == 0:
                return "/dev/eza"
            elif 1 <= minor < 64:
                return "/dev/eza{:d}".format(minor)
        elif major == 44:
            return common_pattern(16, 16, "ftl")
        elif major == 45:
            return common_pattern(16, 4, "pd")
        elif 48 <= major < 56:
            return common_pattern_num_p(8, 32, "rd/c{:d}d".format(major - 48))
        elif 56 <= major < 58:
            return common_pattern(64, 2, "hd", sym_start=["i", "k"][major - 56])
        elif major == 64:
            if minor == 0:
                return "/dev/scramdisk/master"
            elif 1 <= minor:
                return "/dev/scramdisk/{:d}".format(minor)
        elif 65 <= major < 72:
            return iterate_pattern(16, 16, "sd", sym_start=["q", "ag", "aw", "bm", "cc", "cs", "di"][major - 65])
        elif 72 <= major < 80:
            return common_pattern_num_p(16, 16, "ida/c{:d}d".format(major - 72))
        elif 80 <= major < 88:
            return iterate_pattern(16, 16, "i2o/hd", sym_start=["a", "q", "ag", "aw", "bm", "cc", "cs", "di"][major - 80])
        elif 88 <= major < 92:
            return common_pattern(64, 2, "hd", sym_start=["m", "o", "q", "s"][major - 88])
        elif major == 93:
            return common_pattern(16, 16, "nftl")
        elif major == 94:
            return common_pattern(4, 26, "dasd")
        elif major == 96:
            return common_pattern(16, 16, "inftl")
        elif major == 98:
            return common_pattern(16, 26, "ubd")
        elif major == 101:
            return common_pattern_num_p(16, 16, "amiraid/ar")
        elif major == 102:
            return common_pattern(16, 16, "cbd/")
        elif 104 <= major < 112:
            return common_pattern_num_p(16, 16, "cciss/c{:d}d".format(major - 104))
        elif major == 112:
            return iterate_pattern(8, 64, "iseries/vd", sym_start="a")
        elif major == 113:
            return iterate_pattern(1, None, "iseries/vcd", sym_start="a")
        elif major == 114:
            return common_pattern_num_p(16, 16, "ataraid/d")
        elif major == 116:
            return common_pattern_num_p(16, 16, "umem/d")
        elif major == 117:
            if minor == 0:
                return "/dev/evms/block_device"
            elif 1 <= minor < 128:
                return "/dev/evms/legacyname{:d}".format(minor)
            elif 128 <= minor < 256:
                return "/dev/evms/EVMSname{:d}".format(256 - minor)
        elif 128 <= major < 136:
            return iterate_pattern(16, 16, "sd", sym_start=["dy", "eo", "fe", "fu", "gk", "ha", "hq", "ig"][major - 128])
        elif 136 <= major < 144:
            return common_pattern_num_p(16, 16, "rd/c{:d}d".format(major - 136 + 8))
        elif major == 153:
            return common_pattern_num_p(16, 16, "emd/")
        elif 160 <= major < 162:
            return common_pattern_num_p(32, 8, "carmel/", kind_offset=(major - 160) * 8)
        elif major == 179:
            return common_pattern_num_p(8, None, "mmcblk")
        elif major == 180:
            return common_pattern(8, 26, "ub")
        elif major == 202:
            return common_pattern(16, 16, "xvd")
        elif 240 <= major < 255: # LOCAL/EXPERIMENTAL USE, but maybe this is virtio when qemu-system
            return common_pattern(16, 16, "vd")
        elif major == 256:
            return common_pattern(16, 16, "rfd")
        elif major == 257:
            return common_pattern(8, 8, "ssfdc")
        return "???"

    def get_dev_num(self, bdev):
        """
        [~v5.11]
        struct block_device {
            dev_t                       bd_dev;
            ...
        };

        [v5.11~]
        struct block_device {
            sector_t                    bd_start_sect;      // sector_t: u64
            sector_t                    bd_nr_sectors;      // sector_t: u64, v5.17~
            struct gendisk             *bd_disk;            // v6.4~
            struct request_queue       *bd_queue;           // v6.4~
            struct disk_stats __percpu *bd_stats;
            unsigned long               bd_stamp;
            bool                        bd_read_only;       // 1byte + 3byte padding
            dev_t                       bd_dev;
            ...
        };
        """
        if self.offset_bd_dev is None:
            kversion = Kernel.kernel_version()
            if kversion < "5.11":
                self.offset_bd_dev = 0
            elif kversion < "5.16":
                self.offset_bd_dev = 8 * 1 + current_arch.ptrsize * 2 + 4
            elif kversion < "6.4":
                self.offset_bd_dev = 8 * 2 + current_arch.ptrsize * 2 + 4
            else:
                self.offset_bd_dev = 8 * 2 + current_arch.ptrsize * 4 + 4

        dev = u32(read_memory(bdev + self.offset_bd_dev, 4))
        major = dev >> 20
        minor = dev & ((1 << 20) - 1)
        name = KernelBlockDevicesCommand.get_bdev_name(major, minor)
        return major, minor, name

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet

        if not self.quiet:
            info("Wait for memory scan")

        bdevs = self.get_bdev_list()
        if not bdevs:
            err("Not found any bdev")
            return

        self.out = []
        if not self.quiet:
            fmt = "{:<18s} {:<18s} {:<6s} {:<6s}"
            legend = ["bdev", "name (guessed)", "major", "minor"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        # ignore bdev if major is 0
        bdevs = [bdev for bdev in bdevs if self.get_dev_num(bdev)[0] != 0]
        if not bdevs:
            err("Not found any bdev (after filtering major == 0)")
            return

        # parse major, minor and name
        bdevs_with_info = []
        for bdev in bdevs:
            major, minor, name = self.get_dev_num(bdev)
            bdevs_with_info.append([major, minor, name, bdev])

        # print
        fmt = "{:#018x} {:<18s} {:<6d} {:<6d}"
        for major, minor, name, bdev in sorted(bdevs_with_info):
            self.out.append(fmt.format(bdev, name, major, minor))

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelCharacterDevicesCommand(GenericCommand):
    """Display character device list."""
    _cmdline_ = "kcdev"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="enable verbose mode.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _note_ = "This command needs CONFIG_RANDSTRUCT=n.\n"
    _note_ += "\n"
    _note_ += "Simplified cdev structure:\n"
    _note_ += "\n"
    _note_ += "+-chrdevs[255]-+    +-char_device_struct-+\n"
    _note_ += "| [0]          |--->| next               |--->...\n"
    _note_ += "| ...          |    | major              |\n"
    _note_ += "| [254]        |    | baseminor          |           +--->+-cdev--+  +-->+-kobject-+\n"
    _note_ += "+--------------+    | minorct            |           |    | kobj  |--+   | name    |\n"
    _note_ += "                    | name[64]           |           |    | ...   |      | ...     |\n"
    _note_ += "                    | cdev               |-----------+    | ops   |      | parent  |\n"
    _note_ += "                    +--------------------+           |    | ...   |      | ...     |\n"
    _note_ += "                                                     |    | dev   |      +---------+\n"
    _note_ += "+----------+    +-kobj_map----+    +-probe-+         |    | ...   |\n"
    _note_ += "| cdev_map |--->| probes[0]   |--->| next  |--->...  |    +-------+\n"
    _note_ += "+----------+    | ...         |    | dev   |         |\n"
    _note_ += "                | probes[254] |    | ...   |         |\n"
    _note_ += "                | lock        |    | data  |---------+\n"
    _note_ += "                +-------------+    +-------+\n"
    _note_ += "\n"
    _note_ += "The character devices are managed at chrdevs[] and cdev_map.\n"
    _note_ += "This command use each of them for getting structure information."

    @staticmethod
    def get_cdev_name(major, minor):
        # https://www.kernel.org/doc/Documentation/admin-guide/devices.txt
        # https://github.com/lrs-lang/lib/blob/master/src/dev/lib.rs
        dev_name_list = {
            (1, 0): "/dev/mem", # Undocumented, but it seems to be used
            (1, 1): "/dev/mem",
            (1, 2): "/dev/kmem",
            (1, 3): "/dev/null",
            (1, 4): "/dev/port",
            (1, 5): "/dev/zero",
            (1, 6): "/dev/core",
            (1, 7): "/dev/full",
            (1, 8): "/dev/random",
            (1, 9): "/dev/urandom",
            (1, 10): "/dev/aio",
            (1, 11): "/dev/kmsg",
            (1, 12): "/dev/oldmem",
            (5, 0): "/dev/tty",
            (5, 1): "/dev/console",
            (5, 2): "/dev/ptmx",
            (5, 3): "/dev/ttyprintk",
            (10, 0): "/dev/logibm",
            (10, 1): "/dev/psaux",
            (10, 2): "/dev/inportbm",
            (10, 3): "/dev/atibm",
            #(10, 4): "/dev/jbm", # duplicates
            (10, 4): "/dev/amigamouse",
            (10, 5): "/dev/atarimouse",
            (10, 6): "/dev/sunmouse",
            (10, 7): "/dev/amigamouse1",
            (10, 8): "/dev/smouse",
            (10, 9): "/dev/pc110pad",
            (10, 10): "/dev/adbmouse",
            (10, 11): "/dev/vrtpanel",
            (10, 13): "/dev/vpcmouse",
            (10, 14): "/dev/touchscreen/ucb1x00",
            (10, 15): "/dev/touchscreen/mk712",
            (10, 128): "/dev/beep",
            (10, 130): "/dev/watchdog",
            (10, 131): "/dev/temperature",
            (10, 132): "/dev/hwtrap",
            (10, 133): "/dev/exttrp",
            (10, 134): "/dev/apm_bios",
            (10, 135): "/dev/rtc",
            (10, 137): "/dev/vhci",
            (10, 139): "/dev/openprom",
            (10, 140): "/dev/relay8",
            (10, 141): "/dev/relay16",
            (10, 143): "/dev/pciconf",
            (10, 144): "/dev/nvram",
            (10, 145): "/dev/hfmodem",
            (10, 146): "/dev/graphics",
            (10, 147): "/dev/opengl",
            (10, 148): "/dev/gfx",
            (10, 149): "/dev/input/mouse",
            (10, 150): "/dev/input/keyboard",
            (10, 151): "/dev/led",
            (10, 152): "/dev/kpoll",
            (10, 153): "/dev/mergemem",
            (10, 154): "/dev/pmu",
            (10, 156): "/dev/lcd",
            (10, 157): "/dev/ac",
            (10, 158): "/dev/nwbutton",
            (10, 159): "/dev/nwdebug",
            (10, 160): "/dev/nwflash",
            (10, 161): "/dev/userdma",
            (10, 162): "/dev/smbus",
            (10, 163): "/dev/lik",
            (10, 164): "/dev/ipmo",
            (10, 165): "/dev/vmmon",
            (10, 166): "/dev/i2o/ctl",
            (10, 167): "/dev/specialix_sxctl",
            (10, 168): "/dev/tcldrv",
            (10, 169): "/dev/specialix_rioctl",
            (10, 170): "/dev/thinkpad/thinkpad",
            (10, 171): "/dev/srripc",
            (10, 172): "/dev/usemaclone",
            (10, 173): "/dev/ipmikcs",
            (10, 174): "/dev/uctrl",
            (10, 175): "/dev/agpgart",
            (10, 176): "/dev/gtrsc",
            (10, 177): "/dev/cbm",
            (10, 178): "/dev/jsflash",
            (10, 179): "/dev/xsvc",
            (10, 180): "/dev/vrbuttons",
            (10, 181): "/dev/toshiba",
            (10, 182): "/dev/perfctr",
            (10, 183): "/dev/hwrng",
            (10, 184): "/dev/cpu/microcode",
            (10, 186): "/dev/atomicps",
            (10, 187): "/dev/irnet",
            (10, 188): "/dev/smbusbios",
            (10, 189): "/dev/ussp_ctl",
            (10, 190): "/dev/crash",
            (10, 191): "/dev/pcl181",
            (10, 192): "/dev/nas_xbus",
            (10, 193): "/dev/d7s",
            (10, 194): "/dev/zkshim",
            (10, 195): "/dev/elographics/e2201",
            (10, 196): "/dev/vfio/vfio",
            (10, 197): "/dev/pxa3xx-gcu",
            (10, 198): "/dev/sexec",
            (10, 199): "/dev/scanners/cuecat",
            (10, 200): "/dev/net/tun",
            (10, 201): "/dev/button/gulpb",
            (10, 202): "/dev/emd/ctl",
            (10, 203): "/dev/cuse",
            (10, 204): "/dev/video/em8300",
            (10, 205): "/dev/video/em8300_mv",
            (10, 206): "/dev/video/em8300_ma",
            (10, 207): "/dev/video/em8300_sp",
            (10, 208): "/dev/compaq/cpqphpc",
            (10, 209): "/dev/compaq/cpqrid",
            (10, 210): "/dev/impi/bt",
            (10, 211): "/dev/impi/smic",
            (10, 212): "/dev/watchdogs/0",
            (10, 213): "/dev/watchdogs/1",
            (10, 214): "/dev/watchdogs/2",
            (10, 215): "/dev/watchdogs/3",
            (10, 216): "/dev/fujitsu/apanel",
            (10, 217): "/dev/ni/natmotn",
            (10, 218): "/dev/kchuid",
            (10, 219): "/dev/modems/mwave",
            (10, 220): "/dev/mptctl",
            (10, 221): "/dev/mvista/hssdsi",
            (10, 222): "/dev/mvista/hasi",
            (10, 223): "/dev/input/uinput",
            (10, 224): "/dev/tpm",
            (10, 225): "/dev/pps",
            (10, 226): "/dev/systrace",
            (10, 227): "/dev/mcelog",
            (10, 228): "/dev/hpet",
            (10, 229): "/dev/fuse",
            (10, 230): "/dev/midishare",
            (10, 231): "/dev/snapshot",
            (10, 232): "/dev/kvm",
            (10, 233): "/dev/kmview",
            (10, 234): "/dev/btrfs-control",
            (10, 235): "/dev/autofs",
            (10, 236): "/dev/mapper/control",
            (10, 237): "/dev/loop-control",
            (10, 238): "/dev/vhost-net",
            (10, 239): "/dev/uhid",
            (10, 240): "/dev/userio",
            (10, 241): "/dev/vhost-vsock",
            (10, 242): "/dev/rfkill",
            (12, 2): "/dev/ntpqic11",
            (12, 3): "/dev/tpqic11",
            (12, 4): "/dev/ntpqic24",
            (12, 5): "/dev/tpqic24",
            (12, 6): "/dev/ntpqic120",
            (12, 7): "/dev/tpqic120",
            (12, 8): "/dev/ntpqic150",
            (12, 9): "/dev/tpqic150",
            (14, 0): "/dev/mixer",
            (14, 1): "/dev/sequencer",
            (14, 2): "/dev/midi00",
            (14, 3): "/dev/dsp",
            (14, 4): "/dev/audio",
            (14, 7): "/dev/audioctl",
            (14, 8): "/dev/sequencer2",
            (14, 16): "/dev/mixer1",
            (14, 17): "/dev/patmgr0",
            (14, 18): "/dev/midi01",
            (14, 19): "/dev/dsp1",
            (14, 20): "/dev/audio1",
            (14, 33): "/dev/patmgr1",
            (14, 34): "/dev/midi02",
            (14, 50): "/dev/midi03",
            (30, 0): "/dev/socksys",
            (30, 1): "/dev/spx",
            (30, 32): "/dev/inet/ip",
            (30, 33): "/dev/inet/icmp",
            (30, 34): "/dev/inet/ggp",
            (30, 35): "/dev/inet/ipip",
            (30, 36): "/dev/inet/tcp",
            (30, 37): "/dev/inet/egp",
            (30, 38): "/dev/inet/pup",
            (30, 39): "/dev/inet/udp",
            (30, 40): "/dev/inet/idp",
            (30, 41): "/dev/inet/rawip",
            (31, 0): "/dev/mpu401data",
            (31, 1): "/dev/mpu401stat",
            (36, 0): "/dev/route",
            (36, 1): "/dev/skip",
            (36, 3): "/dev/fwmonitor",
            (70, 0): "/dev/apscfg",
            (70, 1): "/dev/apsauth",
            (70, 2): "/dev/apslog",
            (70, 3): "/dev/apsdbg",
            (70, 64): "/dev/apsisdn",
            (70, 65): "/dev/apsasync",
            (70, 128): "/dev/apsmon",
            (73, 0): "/dev/ip2ipl0",
            (73, 1): "/dev/ip2stat0",
            (73, 4): "/dev/ip2ipl1",
            (73, 5): "/dev/ip2stat1",
            (73, 8): "/dev/ip2ipl2",
            (73, 9): "/dev/ip2stat2",
            (73, 12): "/dev/ip2ipl3",
            (73, 13): "/dev/ip2stat",
            (95, 0): "/dev/ipl",
            (95, 1): "/dev/ipnat",
            (95, 2): "/dev/ipstate",
            (95, 3): "/dev/ipauth",
            (152, 0): "/dev/etherd/ctl",
            (152, 1): "/dev/etherd/err",
            (152, 2): "/dev/etherd/raw",
            (200, 0): "/dev/vx/config",
            (200, 1): "/dev/vx/trace",
            (200, 2): "/dev/vx/iod",
            (200, 3): "/dev/vx/info",
            (200, 4): "/dev/vx/task",
            (200, 5): "/dev/vx/taskmon",
            (207, 0): "/dev/cpqhealth/cpqw",
            (207, 1): "/dev/cpqhealth/crom",
            (207, 2): "/dev/cpqhealth/cdt",
            (207, 3): "/dev/cpqhealth/cevt",
            (207, 4): "/dev/cpqhealth/casr",
            (207, 5): "/dev/cpqhealth/cecc",
            (207, 6): "/dev/cpqhealth/cmca",
            (207, 7): "/dev/cpqhealth/ccsm",
            (207, 8): "/dev/cpqhealth/cnmi",
            (207, 9): "/dev/cpqhealth/css",
            (207, 10): "/dev/cpqhealth/cram",
            (207, 11): "/dev/cpqhealth/cpci",
        }
        if (major, minor) in dev_name_list:
            return dev_name_list[major, minor]

        dev_name_list2 = {
            0: "???",
            6: "/dev/lp{:d}",
            16: "/dev/gs4500",
            17: "/dev/ttyH{:d}",
            18: "/dev/cuh{:d}",
            19: "/dev/ttyC{:d}",
            20: "/dev/cub{:d}",
            21: "/dev/sg{:d}",
            22: "/dev/ttyD{:d}",
            23: "/dev/cud{:d}",
            24: "/dev/ttyE{:d}",
            25: "/dev/cue{:d}",
            26: "/dev/wvisfgrab",
            29: "/dev/fb{:d}",
            32: "/dev/ttyX{:d}",
            33: "/dev/cux{:d}",
            34: "/dev/scc{:d}",
            38: "/dev/mlanai{:d}",
            40: "/dev/mmetfgrab",
            41: "/dev/yamm",
            43: "/dev/ttyI{:d}",
            44: "/dev/cui{:d}",
            46: "/dev/ttyR{:d}",
            47: "/dev/cur{:d}",
            48: "/dev/ttyL{:d}",
            49: "/dev/cul{:d}",
            51: "/dev/bc{:d}",
            52: "/dev/dcbri{:d}",
            54: "/dev/holter{:d}",
            55: "/dev/dsp56k",
            56: "/dev/adb",
            57: "/dev/ttyP{:d}",
            58: "/dev/cup{:d}",
            59: "/dev/firewall",
            64: "/dev/enskip",
            66: "/dev/yppcpci{:d}",
            67: "/dev/cfs0",
            69: "/dev/ma16",
            71: "/dev/ttyF{:d}",
            72: "/dev/cuf{:d}",
            74: "/dev/SCI/{:d}",
            75: "/dev/ttyW{:d}",
            76: "/dev/cuw{:d}",
            77: "/dev/qng",
            78: "/dev/ttyM{:d}",
            79: "/dev/cum{:d}",
            80: "/dev/at200",
            82: "/dev/winradio{:d}",
            83: "/dev/mga_vid{:d}",
            84: "/dev/ihcp{:d}",
            86: "/dev/sch{:d}",
            87: "/dev/controla{:d}",
            88: "/dev/comx{:d}",
            89: "/dev/i2c-{:d}",
            91: "/dev/can{:d}",
            94: "/dev/dcxx{:d}",
            97: "/dev/pg{:d}",
            98: "/dev/comedi{:d}",
            99: "/dev/parport{:d}",
            100: "/dev/phone{:d}",
            102: "/dev/tlk{:d}",
            103: "/dev/nnpfs{:d}",
            105: "/dev/ttyV{:d}",
            106: "/dev/cuv{:d}",
            107: "/dev/3dfx",
            108: "/dev/ppp",
            110: "/dev/srnd{:d}",
            111: "/dev/av{:d}",
            112: "/dev/ttyM{:d}", # same 78
            113: "/dev/cum{:d}", # same 79
            119: "/dev/vnet{:d}",
            136: "/dev/pts/{:d}",
            137: "/dev/pts/{:d}",
            138: "/dev/pts/{:d}",
            139: "/dev/pts/{:d}",
            140: "/dev/pts/{:d}",
            141: "/dev/pts/{:d}",
            142: "/dev/pts/{:d}",
            143: "/dev/pts/{:d}",
            144: "/dev/pppox{:d}",
            146: "/dev/scramnet{:d}",
            147: "/dev/aureal{:d}",
            148: "/dev/ttyT{:d}",
            149: "/dev/cut{:d}",
            150: "/dev/rtf{:d}",
            151: "/dev/dpti{:d}",
            153: "/dev/spi{:d}",
            154: "/dev/ttySR{:d}",
            155: "/dev/cusr{:d}",
            158: "/dev/gfax{:d}",
            160: "/dev/gpib{:d}",
            166: "/dev/ttyACM{:d}",
            167: "/dev/cuacm{:d}",
            168: "/dev/ecsa{:d}",
            169: "/dev/ecsa8-{:d}",
            170: "/dev/megarac{:d}",
            174: "/dev/ttySI{:d}",
            175: "/dev/cusi{:d}",
            176: "/dev/nfastpci{:d}",
            178: "/dev/clanvi{:d}",
            179: "/dev/dvxirq{:d}",
            181: "/dev/pcfclock{:d}",
            182: "/dev/pethr{:d}",
            183: "/dev/ss5136dn{:d}",
            184: "/dev/pevss{:d}",
            185: "/dev/intermezzo{:d}",
            186: "/dev/obd{:d}",
            187: "/dev/deskey{:d}",
            188: "/dev/ttyUSB{:d}",
            189: "/dev/cuusb{:d}",
            190: "/dev/kctt{:d}",
            196: "/dev/tor/{:d}",
            198: "/dev/tpmp2/{:d}",
            199: "/dev/vx/rdsk/*/*",
            201: "/dev/vx/rdmp/*",
            202: "/dev/cpu/{:d}/msr",
            203: "/dev/cpu/{:d}/cpuid",
            208: "/dev/ttyU{:d}",
            209: "/dev/cuu{:d}",
            211: "/dev/addinum/cpci1500/{:d}",
            216: "/dev/rfcomm{:d}",
            217: "/dev/curf{:d}",
            218: "/dev/logicalco/bci/{:d}",
            219: "/dev/logicalco/dci1300/{:d}",
            224: "/dev/ttyY{:d}",
            225: "/dev/cuy{:d}",
            226: "/dev/dri/card{:d}",
            229: "/dev/hvc{:d}",
            256: "/dev/ttyEQ{:d}",
            257: "/dev/ptlsec",
            259: "/dev/icap{:d}",
            260: "/dev/osd{:d}",
            261: "/dev/accel/accel{:d}",
        }
        if major in dev_name_list2:
            return dev_name_list2[major].format(minor)

        def pty_tty_pattern(devstr):
            cs1 = "pqrstuvwxyzabcde"
            cs2 = "0123456789abcdef"
            return "/dev/{:s}{:s}{:s}".format(devstr, cs1[minor // 16], cs2[minor % 16])

        if major == 2:
            return pty_tty_pattern("pty")
        elif major == 3:
            return pty_tty_pattern("tty")
        elif major == 4:
            if 0 <= minor < 64:
                return "/dev/tty{:d}".format(minor)
            elif 64 <= minor < 256:
                return "/dev/ttyS{:d}".format(minor - 64)
        elif major == 5:
            if 64 <= minor < 256:
                return "/dev/cua{:d}".format(minor - 64)
        elif major == 7:
            if minor == 0:
                return "/dev/vcs"
            elif 1 <= minor < 64:
                return "/dev/vcs{:d}".format(minor)
            elif minor == 64:
                return "/dev/vcsu"
            elif 65 <= minor < 128:
                return "/dev/vcsu{:d}".format(minor - 64)
            elif minor == 128:
                return "/dev/vcsa"
            elif 129 <= minor < 192:
                return "/dev/vcsa{:d}".format(minor - 128)
        elif major == 9:
            if 0 <= minor < 32:
                return "/dev/st{:d}".format(minor)
            elif 32 <= minor < 64:
                return "/dev/st{:d}l".format(minor - 32)
            elif 64 <= minor < 96:
                return "/dev/st{:d}m".format(minor - 64)
            elif 96 <= minor < 128:
                return "/dev/st{:d}a".format(minor - 96)
            elif 128 <= minor < 160:
                return "/dev/nst{:d}".format(minor - 128)
            elif 160 <= minor < 192:
                return "/dev/nst{:d}l".format(minor - 160)
            elif 192 <= minor < 224:
                return "/dev/nst{:d}m".format(minor - 192)
            elif 224 <= minor < 256:
                return "/dev/nst{:d}a".format(minor - 224)
        elif major == 11: # 11 are duplicates
            if is_sparc32() or is_sparc32plus() or is_sparc64():
                return "/dev/kbd"
            elif is_hppa32() or is_hppa64():
                return "/dev/ttyB{:d}".format(minor)
        elif major == 13:
            if 0 <= minor < 32:
                return "/dev/input/js{:d}".format(minor)
            elif 32 <= minor < 63:
                return "/dev/input/mouse{:d}".format(minor - 32)
            elif minor == 63:
                return "/dev/input/mice"
            elif 64 <= minor < 96:
                return "/dev/input/event{:d}".format(minor - 64)
        elif major == 15:
            if 0 <= minor < 128:
                return "/dev/js{:d}".format(minor)
            elif 128 <= minor < 256:
                return "/dev/djs{:d}".format(minor - 128)
        elif major == 27:
            if 0 <= minor < 4:
                return "/dev/qft{:d}".format(minor)
            elif 4 <= minor < 8:
                return "/dev/nqft{:d}".format(minor - 4)
            elif 16 <= minor < 20:
                return "/dev/zqft{:d}".format(minor - 16)
            elif 20 <= minor < 24:
                return "/dev/nzqft{:d}".format(minor - 20)
            elif 32 <= minor < 36:
                return "/dev/rawqft{:d}".format(minor - 32)
            elif 36 <= minor < 40:
                return "/dev/nrawqft{:d}".format(minor - 36)
        elif major == 28: # 28 are duplicates
            if is_m68k():
                return "/dev/slm{:d}".format(minor)
            else:
                return "/dev/staliomem{:d}".format(minor)
        elif major == 35:
            if 0 <= minor < 4:
                return "/dev/midi{:d}".format(minor)
            elif 64 <= minor < 67:
                return "/dev/rmidi{:d}".format(minor - 64)
            elif 128 <= minor < 132:
                return "/dev/smpte{:d}".format(minor - 128)
        elif major == 36:
            if 16 <= minor < 32:
                return "/dev/tap{:d}".format(minor - 16)
        elif major == 37:
            if 0 <= minor < 128:
                return "/dev/ht{:d}".format(minor)
            elif 128 <= minor < 256:
                return "/dev/nht{:d}".format(minor - 128)
        elif major == 39:
            if 0 <= minor % 32 < 16:
                return "/dev/ml16p{:s}-a{:d}".format(chr(ord("a") + minor // 32), minor)
            elif minor % 32 == 16:
                return "/dev/ml16p{:s}-d".format(chr(ord("a") + minor // 32))
            elif 17 <= minor % 32 < 20:
                return "/dev/ml16p{:s}-c{:d}".format(chr(ord("a") + minor // 32), minor - 17)
        elif major == 45:
            if 0 <= minor < 64:
                return "/dev/isdn{:d}".format(minor)
            elif 64 <= minor < 128:
                return "/dev/isdncntl{:d}".format(minor - 64)
            elif 128 <= minor < 192:
                return "/dev/ippp{:d}".format(minor - 128)
            elif minor == 255:
                return "/dev/isdninfo"
        elif major == 53:
            if 0 <= minor < 3:
                return "/dev/pd_bdm{:d}".format(minor)
            elif 4 <= minor < 7:
                return "/dev/icd_bdm{:d}".format(minor)
        elif major == 65:
            if 0 <= minor < 4:
                return "/dev/plink{:d}".format(minor)
            elif 64 <= minor < 67:
                return "/dev/rplink{:d}".format(minor - 64)
            elif 128 <= minor < 132:
                return "/dev/plink{:d}d".format(minor - 128)
            elif 192 <= minor < 196:
                return "/dev/rplink{:d}d".format(minor - 192)
        elif major == 68:
            if minor == 0:
                return "/dev/capi20"
            elif 1 <= minor < 20:
                return "/dev/capi20.{:02d}".format(minor - 1)
        elif major == 81:
            if 0 <= minor < 64:
                return "/dev/video{:d}".format(minor)
            elif 64 <= minor < 128:
                return "/dev/radio{:d}".format(minor - 64)
            elif 128 <= minor < 192:
                return "/dev/swradio{:d}".format(minor - 128)
            elif 192 <= minor < 256:
                return "/dev/vbi{:d}".format(minor - 192)
        elif major == 85:
            if minor == 0:
                return "/dev/shmiq"
            elif 1 <= minor:
                return "/dev/qcntl{:d}".format(minor)
        elif major == 90:
            if 0 <= minor < 32:
                if minor % 2 == 0:
                    return "/dev/mtd{:d}".format(minor // 2)
                elif minor % 2 == 1:
                    return "/dev/mtdr{:d}".format(minor // 2)
        elif major == 93:
            if 0 <= minor < 128:
                return "/dev/iscc{:d}".format(minor)
            elif 128 <= minor < 256:
                return "/dev/isccctl{:d}".format(minor - 128)
        elif major == 96:
            if 0 <= minor < 128:
                return "/dev/pt{:d}".format(minor)
            elif 128 <= minor < 256:
                return "/dev/npt{:d}".format(minor - 128)
        elif major == 101:
            if minor == 0:
                return "/dev/mdspstat"
            elif 1 <= minor < 17:
                return "/dev/mdsp{:d}".format(minor)
        elif major == 114:
            if 0 <= minor < 128:
                return "/dev/ise{:d}".format(minor)
            elif 128 <= minor < 256:
                return "/dev/isex{:d}".format(minor - 128)
        elif major == 115:
            if 0 <= minor < 8:
                return "/dev/tipar{:d}".format(minor)
            elif 8 <= minor < 16:
                return "/dev/tiser{:d}".format(minor - 8)
            elif 16 <= minor < 48:
                return "/dev/tiusb{:d}".format(minor - 16)
        elif major == 117:
            return "/dev/cosa{:d}c{:d}".format(minor // 16, minor % 16)
        elif major == 118:
            if minor == 0:
                return "/dev/ica"
            elif 1 <= minor:
                return "/dev/ica{:d}".format(minor - 1)
        elif major == 145:
            if minor % 64 == 0:
                return "/dev/sam{:d}_mixer".format(minor // 64)
            elif minor % 64 == 1:
                return "/dev/sam{:d}_sequencer".format(minor // 64)
            elif minor % 64 == 2:
                return "/dev/sam{:d}_midi00".format(minor // 64)
            elif minor % 64 == 3:
                return "/dev/sam{:d}_dsp".format(minor // 64)
            elif minor % 64 == 4:
                return "/dev/sam{:d}_audio".format(minor // 64)
            elif minor % 64 == 6:
                return "/dev/sam{:d}_sndstat".format(minor // 64)
            elif minor % 64 == 18:
                return "/dev/sam{:d}_midi01".format(minor // 64)
            elif minor % 64 == 34:
                return "/dev/sam{:d}_midi02".format(minor // 64)
            elif minor % 64 == 50:
                return "/dev/sam{:d}_midi03".format(minor // 64)
        elif major == 156:
            return "/dev/ttySR{:d}".format(minor + 256)
        elif major == 157:
            return "/dev/cusr{:d}".format(minor + 256)
        elif major == 161:
            if 0 <= minor < 16:
                return "/dev/ircomm{:d}".format(minor)
            elif 16 <= minor < 32:
                return "/dev/irlpt{:d}".format(minor - 16)
        elif major == 162:
            if minor == 0:
                return "/dev/rawctl",
            elif 1 <= minor:
                return "/dev/raw/raw{:d}".format(minor)
        elif major == 164:
                return "/dev/ttyCH{:d}".format(minor)
        elif major == 165:
            if 0 <= minor < 64:
                return "/dev/cuch{:d}".format(minor)
        elif major == 172:
            if 0 <= minor < 128:
                return "/dev/ttyMX{:d}".format(minor)
            elif minor == 128:
                return "/dev/moxactl"
        elif major == 173:
            if 0 <= minor < 128:
                return "/dev/cumx{:d}".format(minor)
        elif major == 177:
            if 0 <= minor < 16:
                return "/dev/pcilynx/aux{:d}".format(minor)
            elif 16 <= minor < 32:
                return "/dev/pcilynx/rom{:d}".format(minor - 16)
            elif 32 <= minor < 48:
                return "/dev/pcilynx/ram{:d}".format(minor - 32)
        elif major == 180:
            if 0 <= minor < 16:
                return "/dev/usb/lp{:d}".format(minor)
            elif 48 <= minor < 64:
                return "/dev/usb/scanner{:d}".format(minor - 48)
            elif minor == 64:
                return "/dev/usb/rio500"
            elif minor == 65:
                return "/dev/usb/usblcd"
            elif minor == 66:
                return "/dev/usb/cpad0"
            elif 96 <= minor < 112:
                return "/dev/usb/hiddev{:d}".format(minor - 96)
            elif 112 <= minor < 128:
                return "/dev/usb/auer{:d}".format(minor - 112)
            elif 128 <= minor < 132:
                return "/dev/usb/brlvgr{:d}".format(minor - 128)
            elif minor == 132:
                return "/dev/usb/idmouse"
            elif 133 <= minor < 141:
                return "/dev/usb/sisusbvga{:d}".format(minor - 133 + 1)
            elif minor == 144:
                return "/dev/usb/lcd"
            elif 160 <= minor < 176:
                return "/dev/usb/legousbtower{:d}".format(minor - 160)
            elif 176 <= minor < 192:
                return "/dev/usb/usbtmc{:d}".format(minor - 176 + 1)
            elif 192 <= minor < 210:
                return "/dev/usb/yurex{:d}".format(minor - 192 + 1)
        elif major == 192:
            if minor == 0:
                return "/dev/profile"
            elif 1 <= minor:
                return "/dev/profile{:d}".format(minor - 1)
        elif major == 193:
            if minor == 0:
                return "/dev/trace"
            elif 1 <= minor:
                return "/dev/trace{:d}".format(minor - 1)
        elif major == 194:
            if minor % 16 == 0:
                return "/dev/mvideo/status{:d}".format(minor // 16)
            elif minor % 16 == 1:
                return "/dev/mvideo/stream{:d}".format(minor // 16)
            elif minor % 16 == 2:
                return "/dev/mvideo/frame{:d}".format(minor // 16)
            elif minor % 16 == 3:
                return "/dev/mvideo/rawframe{:d}".format(minor // 16)
            elif minor % 16 == 4:
                return "/dev/mvideo/codec{:d}".format(minor // 16)
            elif minor % 16 == 5:
                return "/dev/mvideo/video4linux{:d}".format(minor // 16)
        elif major == 195:
            if 0 <= minor < 255:
                return "/dev/nvidia{:d}".format(minor)
            elif minor == 255:
                return "/dev/nvidiactl"
        elif major == 197:
            if 0 <= minor < 128:
                return "/dev/tnf/t{:d}".format(minor)
            elif minor == 128:
                return "/dev/tnf/status"
            elif minor == 130:
                return "/dev/tnf/trace"
        elif major == 204:
            if 0 <= minor < 4:
                return "/dev/ttyLU{:d}".format(minor)
            elif minor == 4:
                return "/dev/ttyFB0"
            elif 5 <= minor < 8:
                return "/dev/ttySA{:d}".format(minor - 5)
            elif 8 <= minor < 12:
                return "/dev/ttySC{:d}".format(minor - 8)
            elif 12 <= minor < 16:
                return "/dev/ttyFW{:d}".format(minor - 12)
            elif 16 <= minor < 32:
                return "/dev/ttyAM{:d}".format(minor - 16)
            elif 32 <= minor < 40:
                return "/dev/ttyDB{:d}".format(minor - 32)
            elif minor == 40:
                return "/dev/ttySG0"
            elif 41 <= minor < 44:
                return "/dev/ttySMX{:d}".format(minor - 41)
            elif 44 <= minor < 46:
                return "/dev/ttyMM{:d}".format(minor - 44)
            elif 46 <= minor < 50:
                return "/dev/ttyCPM{:d}".format(minor - 46)
            elif 50 <= minor < 82:
                return "/dev/ttyIOC{:d}".format(minor - 50)
            elif 82 <= minor < 84:
                return "/dev/ttyVR{:d}".format(minor - 82)
            elif 84 <= minor < 116:
                return "/dev/ttyIOC{:d}".format(minor)
            elif 116 <= minor < 148:
                return "/dev/ttySIOC{:d}".format(minor - 116)
            elif 148 <= minor < 154:
                return "/dev/ttyPSC{:d}".format(minor - 148)
            elif 154 <= minor < 170:
                return "/dev/ttyAT{:d}".format(minor - 154)
            elif 170 <= minor < 186:
                return "/dev/ttyNX{:d}".format(minor - 170)
            elif minor == 186:
                return "/dev/ttyJ0"
            elif 187 <= minor < 190:
                return "/dev/ttyUL{:d}".format(minor - 187)
            elif minor == 191:
                return "/dev/xvc0"
            elif 192 <= minor < 196:
                return "/dev/ttyPZ{:d}".format(minor - 192)
            elif 196 <= minor < 204:
                return "/dev/ttyTX{:d}".format(minor - 196)
            elif 205 <= minor < 209:
                return "/dev/ttySC{:d}".format(minor - 205)
            elif 209 <= minor < 213:
                return "/dev/ttyMAX{:d}".format(minor - 209)
        elif major == 205:
            if 0 <= minor < 4:
                return "/dev/culu{:d}".format(minor)
            elif minor == 4:
                return "/dev/cufb0"
            elif 5 <= minor < 8:
                return "/dev/cusa{:d}".format(minor - 5)
            elif 8 <= minor < 12:
                return "/dev/cusc{:d}".format(minor - 8)
            elif 12 <= minor < 16:
                return "/dev/cufw{:d}".format(minor - 12)
            elif 16 <= minor < 32:
                return "/dev/cuam{:d}".format(minor - 16)
            elif 32 <= minor < 40:
                return "/dev/cudb{:d}".format(minor - 32)
            elif minor == 40:
                return "/dev/cusg0"
            elif 41 <= minor < 44:
                return "/dev/ttycusmx{:d}".format(minor - 41)
            elif 46 <= minor < 50:
                return "/dev/cucpm{:d}".format(minor - 46)
            elif 50 <= minor < 82:
                return "/dev/cuioc4{:d}".format(minor - 50)
            elif 82 <= minor < 84:
                return "/dev/cuvr{:d}".format(minor - 82)
        elif major == 206:
            if 0 <= minor < 32:
                return "/dev/osst{:d}".format(minor)
            elif 32 <= minor < 64:
                return "/dev/osst{:d}l".format(minor - 32)
            elif 64 <= minor < 96:
                return "/dev/osst{:d}m".format(minor - 64)
            elif 96 <= minor < 128:
                return "/dev/osst{:d}a".format(minor - 96)
            elif 128 <= minor < 160:
                return "/dev/nosst{:d}".format(minor - 128)
            elif 160 <= minor < 192:
                return "/dev/nosst{:d}l".format(minor - 160)
            elif 192 <= minor < 224:
                return "/dev/nosst{:d}m".format(minor - 192)
            elif 224 <= minor < 256:
                return "/dev/nosst{:d}a".format(minor - 224)
        elif major == 210:
            if minor % 10 == 0:
                return "/dev/sbei/wxcfg{:d}".format(minor // 10)
            elif minor % 10 == 1:
                return "/dev/sbei/dld{:d}".format(minor // 10)
            elif 2 <= minor % 10 < 6:
                return "/dev/sbei/wan{:d}{:d}".format(minor // 10, minor % 10)
            elif 6 <= minor % 10 < 10:
                return "/dev/sbei/wanc{:d}{:d}".format(minor // 10, minor % 10)
        elif major == 212:
            if minor % 64 % 9 == 0:
                return "/dev/dvb/adapter{:d}/video{:d}".format(minor // 64, minor % 64 // 9)
            elif minor % 64 % 9 == 1:
                return "/dev/dvb/adapter{:d}/audio{:d}".format(minor // 64, minor % 64 // 9)
            elif minor % 64 % 9 == 2:
                return "/dev/dvb/adapter{:d}/sec{:d}".format(minor // 64, minor % 64 // 9)
            elif minor % 64 % 9 == 3:
                return "/dev/dvb/adapter{:d}/frontend{:d}".format(minor // 64, minor % 64 // 9)
            elif minor % 64 % 9 == 4:
                return "/dev/dvb/adapter{:d}/demux{:d}".format(minor // 64, minor % 64 // 9)
            elif minor % 64 % 9 == 5:
                return "/dev/dvb/adapter{:d}/dvr{:d}".format(minor // 64, minor % 64 // 9)
            elif minor % 64 % 9 == 6:
                return "/dev/dvb/adapter{:d}/ca{:d}".format(minor // 64, minor % 64 // 9)
            elif minor % 64 % 9 == 7:
                return "/dev/dvb/adapter{:d}/net{:d}".format(minor // 64, minor % 64 // 9)
            elif minor % 64 % 9 == 8:
                return "/dev/dvb/adapter{:d}/osd{:d}".format(minor // 64, minor % 64 // 9)
        elif major == 220:
            if minor % 2 == 0:
                return "/dev/myricom/gm{:d}".format(minor // 2)
            elif minor % 2 == 1:
                return "/dev/myricom/gmp{:d}".format(minor // 2)
        elif major == 221:
            if 0 <= minor < 4:
                return "/dev/bus/vme/m{:d}".format(minor)
            elif 4 <= minor < 8:
                return "/dev/bus/vme/s{:d}".format(minor - 4)
            elif minor == 8:
                return "/dev/bus/vme/ctl"
        elif major == 227:
            if 1 <= minor:
                return "/dev/3270/tty{:d}".format(minor)
        elif major == 228:
            if minor == 0:
                return "/dev/3270/tub"
            elif 1 <= minor:
                return "/dev/3270/tub{:d}".format(minor)
        elif major == 230:
            if 0 <= minor < 32:
                return "/dev/iseries/vt{:d}".format(minor)
            elif 32 <= minor < 64:
                return "/dev/iseries/vt{:d}l".format(minor - 32)
            elif 64 <= minor < 96:
                return "/dev/iseries/vt{:d}m".format(minor - 64)
            elif 96 <= minor < 128:
                return "/dev/iseries/vt{:d}a".format(minor - 96)
            elif 128 <= minor < 160:
                return "/dev/iseries/nvt{:d}".format(minor - 128)
            elif 160 <= minor < 192:
                return "/dev/iseries/nvt{:d}l".format(minor - 160)
            elif 192 <= minor < 224:
                return "/dev/iseries/nvt{:d}m".format(minor - 192)
            elif 224 <= minor < 256:
                return "/dev/iseries/nvt{:d}a".format(minor - 224)
        elif major == 231:
            if 0 <= minor < 64:
                return "/dev/infiniband/umad{:d}".format(minor)
            elif 64 <= minor < 128:
                return "/dev/infiniband/issm{:d}".format(minor - 64)
            elif 192 <= minor < 224:
                return "/dev/infiniband/uverbs{:d}".format(minor - 192)
        elif major == 232:
            if minor % 10 == 0:
                return "/dev/biometric/sensor{:d}/fingerprint".format(minor // 10)
            elif minor % 10 == 1:
                return "/dev/biometric/sensor{:d}/iris".format(minor // 10)
            elif minor % 10 == 2:
                return "/dev/biometric/sensor{:d}/retina".format(minor // 10)
            elif minor % 10 == 3:
                return "/dev/biometric/sensor{:d}/voiceprint".format(minor // 10)
            elif minor % 10 == 4:
                return "/dev/biometric/sensor{:d}/facial".format(minor // 10)
            elif minor % 10 == 5:
                return "/dev/biometric/sensor{:d}/hand".format(minor // 10)
        elif major == 233:
            if minor == 0:
                return "/dev/ipath"
            elif 1 <= minor < 5:
                return "/dev/ipath{:d}".format(minor - 1)
            elif minor == 129:
                return "/dev/ipath_sma"
            elif minor == 130:
                return "/dev/ipath_diag"
        return "???"

    def get_chrdev_list(self): # [chrdev, chrdev, chrdev, ...]
        """
        #define CHRDEV_MAJOR_HASH_SIZE 255
        static struct char_device_struct {
            struct char_device_struct *next;
            unsigned int major;
            unsigned int baseminor;
            int minorct;
            char name[64];
            struct cdev *cdev;
        } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
        """
        chrdevs = KernelAddressHeuristicFinder.get_chrdevs()
        if chrdevs is None:
            if not self.quiet:
                err("Not found chrdevs")
            return None
        if not self.quiet:
            info("chrdevs: {:#x}".format(chrdevs))

        chrdev_addrs = []
        for i in range(255):
            addr = read_int_from_memory(chrdevs + i * current_arch.ptrsize)
            while addr and addr not in chrdev_addrs:
                chrdev_addrs.append(addr)
                addr = read_int_from_memory(addr)
        return chrdev_addrs

    def get_cdev_list(self): # [[cdev, major, minor], [...] ...]
        """
        struct kobj_map {
            struct probe {
                struct probe *next;
                dev_t dev;
                unsigned long range;
                struct module *owner;
                kobj_probe_t *get;
                int (*lock)(dev_t, void *);
                void *data;  // -> cdev
            } *probes[255];
            struct mutex *lock;
        };
        static struct kobj_map *cdev_map;

        struct cdev {
            struct kobject kobj;
            struct module *owner;
            const struct file_operations *ops;
            struct list_head list;
            dev_t dev;
            unsigned int count;
        } __randomize_layout;

        struct kobject {
            const char *name;
            struct list_head entry;
            struct kobject *parent;
            struct kset *kset;
            const struct kobj_type *ktype;
            struct kernfs_node *sd;
            struct kref kref;
        #ifdef CONFIG_DEBUG_KOBJECT_RELEASE
            struct delayed_work release;
        #endif
            unsigned int state_initialized:1;
            unsigned int state_in_sysfs:1;
            unsigned int state_add_uevent_sent:1;
            unsigned int state_remove_uevent_sent:1;
            unsigned int uevent_suppress:1;
        };
        """
        cdev_map = KernelAddressHeuristicFinder.get_cdev_map()
        if cdev_map is None:
            if not self.quiet:
                err("Not found cdev_map")
            return None
        if not self.quiet:
            info("cdev_map: {:#x}".format(cdev_map))

        try:
            cdev_map_ = read_int_from_memory(cdev_map)
            if not self.quiet:
                info("*cdev_map: {:#x}".format(cdev_map_))
        except Exception:
            if not self.quiet:
                err("cdev_map is not initialized")
            return None

        cdev_addrs = []
        seen = []
        for i in range(255):
            addr = read_int_from_memory(cdev_map_ + i * current_arch.ptrsize)
            while addr:
                cdev = read_int_from_memory(addr + 6 * current_arch.ptrsize)
                dev = u32(read_memory(addr + current_arch.ptrsize, 4))
                major = dev >> 20
                minor = dev & ((1 << 20) - 1)
                if cdev and cdev not in seen:
                    cdev_addrs.append([cdev, major, minor])
                    seen.append(cdev)
                addr = read_int_from_memory(addr)
        return cdev_addrs

    def get_offset_ops(self, cdevs):
        for i in range(3, 0x20):
            offset_list = i * current_arch.ptrsize
            valid = True
            for cdev in cdevs:
                pos_next = cdev + offset_list
                pos_prev = cdev + offset_list + current_arch.ptrsize
                list_entry_next = [pos_next]
                list_entry_prev = [pos_prev]
                while valid:
                    # read check
                    try:
                        pos_next = read_int_from_memory(pos_next)
                        pos_prev = read_int_from_memory(pos_prev) + current_arch.ptrsize
                    except gdb.MemoryError: # memory read error
                        valid = False
                        break
                    # list validate
                    if pos_next in list_entry_next[1:]: # incomplete infinity loop detected
                        valid = False
                        break
                    if pos_prev in list_entry_prev[1:]: # incomplete infinity loop detected
                        valid = False
                        break
                    if pos_next == list_entry_next[0] and pos_prev == list_entry_prev[0]:
                        break
                    list_entry_next.append(pos_next)
                    list_entry_prev.append(pos_prev)
                if not valid:
                    break
            else:
                # for loop is finished until last element
                if valid:
                    offset_ops = offset_list - current_arch.ptrsize
                    if not self.quiet:
                        info("offsetof(cdev, ops): {:#x}".format(offset_ops))
                    return offset_ops

        if not self.quiet:
            err("Not found offsetof(cdev, ops)")
        return None

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet

        if not self.quiet:
            info("Wait for memory scan")

        chrdev_addrs = self.get_chrdev_list()
        if chrdev_addrs is None:
            return
        cdev_addrs = self.get_cdev_list()
        if cdev_addrs is None:
            return

        # merge chrdev (from chrdevs)
        merged = {}
        for chrdev in chrdev_addrs:
            major = u32(read_memory(chrdev + current_arch.ptrsize, 4))
            minor = u32(read_memory(chrdev + current_arch.ptrsize + 4, 4))
            name_string = read_cstring_from_memory(chrdev + current_arch.ptrsize + 4 * 3) or "<None>"
            off = chrdev + current_arch.ptrsize + 4 * 3 + 64
            while off % current_arch.ptrsize: # align
                off += 1
            cdev = read_int_from_memory(off)
            merged[major, minor] = {"chrdev": chrdev, "name": name_string, "cdev": cdev}

        # merge cdev (from cdev_map)
        for cdev, major, minor in cdev_addrs:
            kobj = read_int_from_memory(cdev)
            name_string = read_cstring_from_memory(kobj) or "<None>"

            if (major, minor) in merged:
                if merged[major, minor]["cdev"] == 0:
                    merged[major, minor]["cdev"] = cdev
                if merged[major, minor]["name"] == "<None>":
                    merged[major, minor]["name"] = name_string
            else:
                merged[major, minor] = {"chrdev": 0x0, "name": name_string, "cdev": cdev}

        # add ops info
        off_ops = self.get_offset_ops([v["cdev"] for k, v in merged.items() if v["cdev"]])
        if off_ops is None:
            return
        for k in merged.keys():
            if merged[k]["cdev"]:
                merged[k]["ops"] = read_int_from_memory(merged[k]["cdev"] + off_ops)
            else:
                merged[k]["ops"] = 0x0
            merged[k]["ops_sym"] = Symbol.get_symbol_string(merged[k]["ops"])

        # add parent info
        for k in merged.keys():
            if merged[k]["cdev"]:
                parent = read_int_from_memory(merged[k]["cdev"] + current_arch.ptrsize * 3)
                merged[k]["parent"] = parent
                if parent:
                    if not is_valid_addr(parent):
                        merged[k]["parent_name"] = "???"
                    else:
                        name = read_int_from_memory(parent)
                        if name:
                            merged[k]["parent_name"] = read_cstring_from_memory(name) or "<None>"
                        else:
                            merged[k]["parent_name"] = "<None>"
                else:
                    merged[k]["parent_name"] = "<None>"
            else:
                merged[k]["parent"] = 0x0
                merged[k]["parent_name"] = "<None>"

        # print
        self.out = []
        if not self.quiet:
            fmt = "{:<18s} {:<18s} {:<24s} {:<6s} {:<6s} {:<18s} {:<18s} {:18s} {:<s}"
            legend = [
                "chrdev", "name", "name (guessed)", "major", "minor",
                "cdev", "cdev->kobj.parent", "parent_name", "cdev->ops",
            ]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        for (major, minor), m in sorted(merged.items()):
            fmt = "{:#018x} {:<18s} {:<24s} {:<6d} {:<6d} {:#018x} {:#018x} {:<18s} {:#018x}{:s}"
            guessed_name = KernelCharacterDevicesCommand.get_cdev_name(major, minor)
            if not args.verbose:
                if m["chrdev"] == 0:
                    continue
            self.out.append(fmt.format(m["chrdev"], m["name"], guessed_name, major, minor,
                                       m["cdev"], m["parent"], m["parent_name"], m["ops"], m["ops_sym"]))

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelOperationsCommand(GenericCommand):
    """Display the members of commonly used function table (like struct file_operations) in the kernel."""
    _cmdline_ = "kops"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    types = [
        "address_space",
        "block_device",
        "dentry",
        "file",
        "inode",
        "pernet",
        "pipe_buf",
        "seq",
        "smp",
        "super",
        "tty",
        "tty_ldisc",
        "vm",
        "dma_buf",
    ]
    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("mode", choices=types, help="the structure type.")
    parser.add_argument("address", metavar="ADDRESS", nargs="?", type=AddressUtil.parse_address,
                        help="the address interpreted as ops.")
    parser.add_argument("-V", "--version", help="use specific kernel version")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -q\n".format(_cmdline_)
    _example_ += "{:s} -q -V 6.6.0".format(_cmdline_)

    _note_ = "This command needs CONFIG_RANDSTRUCT=n."

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def initialize(self, kversion):
        if kversion.major < 3:
            err("Unsupported v3.0 or before")
            return False

        self.members = {}

        def adapt_to_kernel_version(ops):
            out = []
            for entry in ops:
                if len(entry) == 5:
                    typ, name, minver, maxver, enabled = entry
                    if not enabled:
                        continue
                else:
                    typ, name, minver, maxver = entry

                if minver and kversion < minver:
                    continue
                if maxver and kversion > maxver:
                    continue
                out.append((typ, name))
            return out

        file_operations = [
            # type,      name                                       minver     maxver
            ["ptr",      "owner",                                   None,      None],
            ["func_ptr", "llseek",                                  None,      None],
            ["func_ptr", "read",                                    None,      None],
            ["func_ptr", "write",                                   None,      None],
            ["func_ptr", "aio_read",                                None,      "4.0.9"],
            ["func_ptr", "aio_write",                               None,      "4.0.9"],
            ["func_ptr", "read_iter",                               "3.16.0",  None],
            ["func_ptr", "write_iter",                              "3.16.0",  None],
            ["func_ptr", "readdir",                                 None,      "3.10.108"],
            ["func_ptr", "iopoll",                                  "5.1.0",   None],
            ["func_ptr", "iterate",                                 "3.11.0",  None],
            ["func_ptr", "iterate_shared",                          "4.7.0",   None],
            ["func_ptr", "poll",                                    None,      None],
            ["func_ptr", "unlocked_ioctl",                          None,      None],
            ["func_ptr", "compat_ioctl",                            None,      None],
            ["func_ptr", "mmap",                                    None,      None],
            ["func_ptr", "mremap",                                  "3.19.0",  "4.2.8"],
            ["ulong",    "mmap_supported_flags",                    "4.15.0",  None],
            ["func_ptr", "open",                                    None,      None],
            ["func_ptr", "flush",                                   None,      None],
            ["func_ptr", "release",                                 None,      None],
            ["func_ptr", "fsync",                                   None,      None],
            ["func_ptr", "aio_fsync",                               None,      "4.8.17"],
            ["func_ptr", "fasync",                                  None,      None],
            ["func_ptr", "lock",                                    None,      None],
            ["func_ptr", "sendpage",                                None,      None],
            ["func_ptr", "get_unmapped_area",                       None,      None],
            ["func_ptr", "check_flags",                             None,      None],
            ["func_ptr", "flock",                                   None,      None],
            ["func_ptr", "splice_write",                            None,      None],
            ["func_ptr", "splice_read",                             None,      None],
            ["func_ptr", "setlease",                                None,      None],
            ["func_ptr", "fallocate",                               None,      None],
            ["func_ptr", "show_fdinfo",                             "3.8.0",   None],
            ["func_ptr", "copy_file_range",                         "4.5.0",   None],
            ["func_ptr", "clone_file_range",                        None,      "4.19.288"],
            ["func_ptr", "dedupe_file_range",                       None,      "4.19.288"],
            ["func_ptr", "remap_file_range",                        "4.20.0",  None],
            ["func_ptr", "fadvise",                                 "4.19.0",  None],
            ["func_ptr", "uring_cmd",                               "5.19.0",  None],
            ["func_ptr", "uring_cmd_iopoll",                        "6.1.0",   None],
        ]
        self.members["file"] = adapt_to_kernel_version(file_operations)

        tty_operations = [
            # type,      name                                       minver     maxver
            ["func_ptr", "lookup",                                  None,      None],
            ["func_ptr", "install",                                 None,      None],
            ["func_ptr", "remove",                                  None,      None],
            ["func_ptr", "open",                                    None,      None],
            ["func_ptr", "close",                                   None,      None],
            ["func_ptr", "shutdown",                                None,      None],
            ["func_ptr", "cleanup",                                 None,      None],
            ["func_ptr", "write",                                   None,      None],
            ["func_ptr", "put_char",                                None,      None],
            ["func_ptr", "flush_chars",                             None,      None],
            ["func_ptr", "write_room",                              None,      None],
            ["func_ptr", "chars_in_buffer",                         None,      None],
            ["func_ptr", "ioctl",                                   None,      None],
            ["func_ptr", "compat_ioctl",                            None,      None],
            ["func_ptr", "set_termios",                             None,      None],
            ["func_ptr", "throttle",                                None,      None],
            ["func_ptr", "unthrottle",                              None,      None],
            ["func_ptr", "stop",                                    None,      None],
            ["func_ptr", "start",                                   None,      None],
            ["func_ptr", "hangup",                                  None,      None],
            ["func_ptr", "break_ctl",                               None,      None],
            ["func_ptr", "flush_buffer",                            None,      None],
            ["func_ptr", "set_ldisc",                               None,      None],
            ["func_ptr", "wait_until_sent",                         None,      None],
            ["func_ptr", "send_xchar",                              None,      None],
            ["func_ptr", "tiocmget",                                None,      None],
            ["func_ptr", "tiocmset",                                None,      None],
            ["func_ptr", "resize",                                  None,      None],
            ["func_ptr", "set_termiox",                             None,      "5.9.16"],
            ["func_ptr", "get_icount",                              None,      None],
            ["func_ptr", "get_serial",                              "4.19.0",  None],
            ["func_ptr", "set_serial",                              "4.19.0",  None],
            ["func_ptr", "show_fdinfo",                             "4.14.0",  None],
            ["func_ptr", "poll_init (CONFIG_CONSOLE_POLL=y)",       None,      None],
            ["func_ptr", "poll_get_char (CONFIG_CONSOLE_POLL=y)",   None,      None],
            ["func_ptr", "poll_put_char (CONFIG_CONSOLE_POLL=y)",   None,      None],
            ["func_ptr", "proc_show",                               "4.18.0",  None],
            ["ptr",      "proc_fops",                               None,      "4.17.19"],
        ]
        self.members["tty"] = adapt_to_kernel_version(tty_operations)

        tty_ldisc_ops = [
            # type,      name                                       minver     maxver       additinoal_flag
            ["int",      "magic",                                   None,      "5.12.19"],
            ["char*",    "name",                                    None,      None],
            ["int",      "num",                                     "5.16.0",  None],
            ["int",      "num",                                     None,      "5.15.120",  is_32bit()],
            ["int",      "flags",                                   None,      "5.15.120",  is_32bit()],
            ["int, int", "flags, num",                              None,      "5.15.120",  is_64bit()],
            ["func_ptr", "open",                                    None,      None],
            ["func_ptr", "close",                                   None,      None],
            ["func_ptr", "flush_buffer",                            None,      None],
            ["func_ptr", "read",                                    None,      None],
            ["func_ptr", "write",                                   None,      None],
            ["func_ptr", "ioctl",                                   None,      None],
            ["func_ptr", "compat_ioctl",                            None,      None],
            ["func_ptr", "set_termios",                             None,      None],
            ["func_ptr", "poll",                                    None,      None],
            ["func_ptr", "hangup",                                  None,      None],
            ["func_ptr", "receive_buf",                             None,      None],
            ["func_ptr", "write_wakeup",                            None,      None],
            ["func_ptr", "dcd_change",                              None,      None],
            ["func_ptr", "fasync",                                  "3.11.0",  "4.5.7"],
            ["func_ptr", "receive_buf2",                            "3.12.0",  None],
            ["func_ptr", "lookahead_buf",                           "5.16.0",  None],
            ["ptr",      "owner",                                   None,      None],
            ["int",      "refcount",                                None,      "5.13.19"],
        ]
        self.members["tty_ldisc"] = adapt_to_kernel_version(tty_ldisc_ops)

        seq_operations = [
            # type,      name                                       minver     maxver
            ["func_ptr", "start",                                   None,      None],
            ["func_ptr", "stop",                                    None,      None],
            ["func_ptr", "next",                                    None,      None],
            ["func_ptr", "show",                                    None,      None],
        ]
        self.members["seq"] = adapt_to_kernel_version(seq_operations)

        inode_operations = [
            # type,      name                                       minver     maxver
            ["func_ptr", "lookup",                                  None,      None],
            ["func_ptr", "get_link",                                "4.5.0",   None],
            ["func_ptr", "follow_link",                             None,      "4.4.302"],
            ["func_ptr", "permission",                              None,      None],
            ["func_ptr", "get_inode_acl",                           "6.2.0",   None],
            ["func_ptr", "get_acl",                                 "3.1.0",   "6.1.38"],
            ["func_ptr", "check_acl",                               None,      "3.0.101"],
            ["func_ptr", "readlink",                                None,      None],
            ["func_ptr", "put_link",                                None,      "4.4.302"],
            ["func_ptr", "create",                                  None,      None],
            ["func_ptr", "link",                                    None,      None],
            ["func_ptr", "unlink",                                  None,      None],
            ["func_ptr", "symlink",                                 None,      None],
            ["func_ptr", "mkdir",                                   None,      None],
            ["func_ptr", "rmdir",                                   None,      None],
            ["func_ptr", "mknod",                                   None,      None],
            ["func_ptr", "rename",                                  None,      None],
            ["func_ptr", "truncate",                                None,      "3.7.10"],
            ["func_ptr", "rename2",                                 "3.15.0",  "4.8.17"],
            ["func_ptr", "setattr",                                 None,      None],
            ["func_ptr", "getattr",                                 None,      None],
            ["func_ptr", "setxattr",                                None,      "4.8.17"],
            ["func_ptr", "getxattr",                                None,      "4.8.17"],
            ["func_ptr", "listxattr",                               None,      None],
            ["func_ptr", "removexattr",                             None,      "4.8.17"],
            ["func_ptr", "fiemap",                                  None,      None],
            ["func_ptr", "update_time",                             "3.5.0",   None],
            ["func_ptr", "atomic_open",                             "3.6.0",   None],
            ["func_ptr", "tmpfile",                                 "3.11.0",  None],
            ["func_ptr", "get_acl",                                 "6.2.0",   None],
            ["func_ptr", "set_acl",                                 "3.14.0",  None],
            ["func_ptr", "dentry_open",                             None,      "4.1.52"],
            ["func_ptr", "fileattr_set",                            "5.13.0",  None],
            ["func_ptr", "fileattr_get",                            "5.13.0",  None],
        ]
        self.members["inode"] = adapt_to_kernel_version(inode_operations)

        pernet_operations = [
            # type,      name                                       minver     maxver
            ["ptr",      "list_head.next",                          None,      None],
            ["ptr",      "list_head.prev",                          None,      None],
            ["func_ptr", "init",                                    None,      None],
            ["func_ptr", "pre_exit",                                "5.3.0",   None],
            ["func_ptr", "exit",                                    None,      None],
            ["func_ptr", "exit_batch",                              None,      None],
            ["ptr",      "id",                                      None,      None],
            ["long",     "size",                                    None,      None],
        ]
        self.members["pernet"] = adapt_to_kernel_version(pernet_operations)

        address_space_operations = [
            # type,      name                                       minver     maxver
            ["func_ptr", "writepage",                               None,      None],
            ["func_ptr", "read_folio",                              "5.19.0",  None],
            ["func_ptr", "readpage",                                None,      "5.18.19"],
            ["func_ptr", "writepages",                              None,      None],
            ["func_ptr", "dirty_folio",                             "5.18.0",  None],
            ["func_ptr", "set_page_dirty",                          None,      "5.17.15"],
            ["func_ptr", "readpages",                               None,      "5.17.15"],
            ["func_ptr", "readahead",                               "5.8.0",   None],
            ["func_ptr", "write_begin",                             None,      None],
            ["func_ptr", "write_end",                               None,      None],
            ["func_ptr", "bmap",                                    None,      None],
            ["func_ptr", "invalidate_folio",                        "5.18.0",  None],
            ["func_ptr", "invalidatepage",                          None,      "5.17.15"],
            ["func_ptr", "release_folio",                           "5.19.0",  None],
            ["func_ptr", "releasepage",                             None,      "5.18.19"],
            ["func_ptr", "free_folio",                              "5.19.0",  None],
            ["func_ptr", "freepage",                                None,      "5.18.19"],
            ["func_ptr", "direct_IO",                               None,      None],
            ["func_ptr", "get_xip_mem",                             None,      "3.19.8"],
            ["func_ptr", "migrate_folio",                           "6.0.0",   None],
            ["func_ptr", "migratepage",                             None,      "5.19.17"],
            ["func_ptr", "isolate_page",                            "4.8.0",   "5.19.17"],
            ["func_ptr", "putback_page",                            "4.8.0",   "5.19.17"],
            ["func_ptr", "launder_folio",                           "5.18.0",  None],
            ["func_ptr", "launder_page",                            None,      "5.17.15"],
            ["func_ptr", "is_partially_uptodate",                   None,      None],
            ["func_ptr", "is_dirty_writeback",                      "3.11.0",  None],
            ["func_ptr", "error_remove_page",                       None,      None],
            ["func_ptr", "swap_activate",                           "3.6.0",   None],
            ["func_ptr", "swap_deactivate",                         "3.6.0",   None],
            ["func_ptr", "swap_rw",                                 "5.19.0",  None],
        ]
        self.members["address_space"] = adapt_to_kernel_version(address_space_operations)

        vm_operations_struct = [
            # type,      name                                       minver     maxver
            ["func_ptr", "open",                                    None,      None],
            ["func_ptr", "close",                                   None,      None],
            ["func_ptr", "may_split",                               "5.11.0",  None],
            ["func_ptr", "split",                                   "4.14.0",  "5.10.186"],
            ["func_ptr", "mremap",                                  "4.3.9",   None],
            ["func_ptr", "mprotect",                                "5.11.0",  None],
            ["func_ptr", "fault",                                   None,      None],
            ["func_ptr", "huge_fault",                              "4.11.0",  None],
            ["func_ptr", "pmd_fault",                               "4.3.0",   "4.10.17"],
            ["func_ptr", "map_pages",                               "3.15.0",  None],
            ["func_ptr", "pagesize",                                "4.17.0",  None],
            ["func_ptr", "page_mkwrite",                            None,      None],
            ["func_ptr", "pfn_mkwrite",                             "4.1.0",   None],
            ["func_ptr", "access",                                  None,      None],
            ["func_ptr", "name",                                    "3.16.0",  None],
            ["func_ptr", "set_policy (CONFIG_NUMA=y)",              None,      None],
            ["func_ptr", "get_policy (CONFIG_NUMA=y)",              None,      None],
            ["func_ptr", "migrate (CONFIG_NUMA=y)",                 None,      "3.18.140"],
            ["func_ptr", "find_special_page",                       "4.0.0",   None],
            ["func_ptr", "remap_pages",                             "3.17.0",  "3.19.8"],
            ["func_ptr", "remap_pages",                             "3.7.0",   "3.16.58"],
        ]
        self.members["vm"] = adapt_to_kernel_version(vm_operations_struct)

        super_operations = [
            # type,      name                                       minver     maxver
            ["func_ptr", "alloc_inode",                             None,      None],
            ["func_ptr", "destroy_inode",                           None,      None],
            ["func_ptr", "free_inode",                              "5.2.0",   None],
            ["func_ptr", "dirty_inode",                             None,      None],
            ["func_ptr", "write_inode",                             None,      None],
            ["func_ptr", "drop_inode",                              None,      None],
            ["func_ptr", "evict_inode",                             None,      None],
            ["func_ptr", "put_super",                               None,      None],
            ["func_ptr", "write_super",                             None,      "3.5.7"],
            ["func_ptr", "sync_fs",                                 None,      None],
            ["func_ptr", "freeze_super",                            "3.19.0",  None],
            ["func_ptr", "freeze_fs",                               None,      None],
            ["func_ptr", "thaw_super",                              "3.19.0",  None],
            ["func_ptr", "unfreeze_fs",                             None,      None],
            ["func_ptr", "statfs",                                  None,      None],
            ["func_ptr", "remount_fs",                              None,      None],
            ["func_ptr", "umount_begin",                            None,      None],
            ["func_ptr", "show_options",                            None,      None],
            ["func_ptr", "show_devname",                            None,      None],
            ["func_ptr", "show_path",                               None,      None],
            ["func_ptr", "show_stats",                              None,      None],
            ["func_ptr", "quota_read (CONFIG_QUOTA=y)",             None,      None],
            ["func_ptr", "quota_write (CONFIG_QUOTA=y)",            None,      None],
            ["func_ptr", "get_dquots (CONFIG_QUOTA=y)",             "3.19.0",  None],
            ["func_ptr", "bdev_try_to_free_page",                   None,      "5.13.19"],
            ["func_ptr", "nr_cached_objects",                       "3.1.0",   None],
            ["func_ptr", "free_cached_objects",                     "3.1.0",   None],
        ]
        self.members["super"] = adapt_to_kernel_version(super_operations)

        dentry_operations = [
            # type,      name                                       minver     maxver
            ["func_ptr", "d_revalidate",                            None,      None],
            ["func_ptr", "d_weak_revalidate",                       "3.9.0",   None],
            ["func_ptr", "d_hash",                                  None,      None],
            ["func_ptr", "d_compare",                               None,      None],
            ["func_ptr", "d_delete",                                None,      None],
            ["func_ptr", "d_init",                                  "4.8.0",   None],
            ["func_ptr", "d_release",                               None,      None],
            ["func_ptr", "d_prune",                                 "3.2.0",   None],
            ["func_ptr", "d_iput",                                  None,      None],
            ["func_ptr", "d_dname",                                 None,      None],
            ["func_ptr", "d_automount",                             None,      None],
            ["func_ptr", "d_manage",                                None,      None],
            ["func_ptr", "d_select_inode",                          "4.1.0",   "4.7.10"],
            ["func_ptr", "d_real",                                  "4.4.0",   None],
            ["func_ptr", "d_select_inode",                          "3.18.23", "3.18.140"],
        ]
        self.members["dentry"] = adapt_to_kernel_version(dentry_operations)

        block_device_operations = [
            # type,      name                                       minver     maxver
            ["func_ptr", "submit_bio",                              "5.9.0",   None],
            ["func_ptr", "poll_bio",                                "5.18.0",  None],
            ["func_ptr", "open",                                    None,      None],
            ["func_ptr", "release",                                 None,      None],
            ["func_ptr", "rw_page",                                 None,      "6.2.16"],
            ["func_ptr", "ioctl",                                   None,      None],
            ["func_ptr", "compat_ioctl",                            None,      None],
            ["func_ptr", "direct_access",                           None,      "4.11.12"],
            ["func_ptr", "check_events",                            None,      None],
            ["func_ptr", "media_changed",                           None,      "5.8.18"],
            ["func_ptr", "unlock_native_capacity",                  None,      None],
            ["func_ptr", "revalidate_disk",                         None,      "5.12.19"],
            ["func_ptr", "getgeo",                                  None,      None],
            ["func_ptr", "set_read_only",                           "5.11.0",  None],
            ["func_ptr", "free_disk",                               "5.18.0",  None],
            ["func_ptr", "swap_slot_free_notify",                   None,      None],
            ["func_ptr", "report_zones",                            "4.20.0",  None],
            ["func_ptr", "devnode",                                 "5.7.0",   None],
            ["func_ptr", "get_unique_id",                           "5.16.0",  None],
            ["ptr",      "owner",                                   None,      None],
            ["ptr",      "pr_ops",                                  "4.4.0",   None],
            ["func_ptr", "alternative_gpt_sector",                  "5.15.0",  None],
        ]
        self.members["block_device"] = adapt_to_kernel_version(block_device_operations)

        pipe_buf_operations = [
            # type,      name                                       minver     maxver
            ["int",      "can_merge",                               None,      "5.0.21"],
            ["func_ptr", "map",                                     None,      "3.14.79"],
            ["func_ptr", "unmap",                                   None,      "3.14.79"],
            ["func_ptr", "confirm",                                 None,      None],
            ["func_ptr", "release",                                 None,      None],
            ["func_ptr", "try_steal",                               None,      None],
            ["func_ptr", "get",                                     None,      None],
        ]
        self.members["pipe_buf"] = adapt_to_kernel_version(pipe_buf_operations)

        smp_operations = [
            # type,      name                                       minver     maxver
            ["func_ptr", "smp_init_cpus (CONFIG_SMP=y)",            "3.7.0",   None],
            ["func_ptr", "smp_prepare_cpus (CONFIG_SMP=y)",         "3.7.0",   None],
            ["func_ptr", "smp_secondary_init (CONFIG_SMP=y)",       "3.7.0",   None],
            ["func_ptr", "smp_boot_secondary (CONFIG_SMP=y)",       "3.7.0",   None],
            ["func_ptr", "cpu_kill (CONFIG_HOTPLUG_CPU=y)",         "3.7.0",   None],
            ["func_ptr", "cpu_die (CONFIG_HOTPLUG_CPU=y)",          "3.7.0",   None],
            ["func_ptr", "cpu_can_disable (CONFIG_HOTPLUG_CPU=y)",  "4.3.0",   None],
            ["func_ptr", "cpu_disable (CONFIG_HOTPLUG_CPU=y)",      "3.7.0",   None],
        ]
        self.members["smp"] = adapt_to_kernel_version(smp_operations)

        dma_buf_ops = [
            # type,        name                                       minver    maxver
            ["bool",       "cache_sgt_mapping",                       "5.7.0",  None],
            ["bool, bool", "cache_sgt_mapping, bool dynamic_mapping", "5.5.0",  "5.6.19"],
            ["bool",       "cache_sgt_mapping",                       "5.3.0",  "5.4.264"],
            ["func_ptr",   "attach",                                  "3.2.0",  None],
            ["func_ptr",   "detach",                                  "3.2.0",  None],
            ["func_ptr",   "pin",                                     "5.7.0",  None],
            ["func_ptr",   "unpin",                                   "5.7.0",  None],
            ["func_ptr",   "map_dma_buf",                             "3.2.0",  None],
            ["func_ptr",   "unmap_dma_buf",                           "3.2.0",  None],
            ["func_ptr",   "release",                                 "3.2.0",  None],
            ["func_ptr",   "begin_cpu_access",                        "3.4.0",  None],
            ["func_ptr",   "end_cpu_access",                          "3.4.0",  None],
            ["func_ptr",   "mmap",                                    "5.3.0",  None],
            ["func_ptr",   "map_atomic",                              "4.12.0", "4.18.20"],
            ["func_ptr",   "unmap_atomic",                            "4.12.0", "4.18.20"],
            ["func_ptr",   "kmap_atomic",                             "3.4.0",  "4.11.12"],
            ["func_ptr",   "kunmap_atomic",                           "3.4.0",  "4.11.12"],
            ["func_ptr",   "map",                                     "4.12.0", "5.5.19"],
            ["func_ptr",   "unmap",                                   "4.12.0", "5.5.19"],
            ["func_ptr",   "kmap",                                    "3.4.0",  "4.11.12"],
            ["func_ptr",   "kunmap",                                  "3.4.0",  "4.11.12"],
            ["func_ptr",   "mmap",                                    "3.5.0",  "5.2.21"],
            ["func_ptr",   "vmap",                                    "3.5.0",  None],
            ["func_ptr",   "vunmap",                                  "3.5.0",  None],
        ]
        self.members["dma_buf"] = adapt_to_kernel_version(dma_buf_ops)
        return True

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        # parse version
        if args.version:
            r = re.search(r"(\d)\.(\d+)(?:\.(\d+))?", args.version)
            if r:
                major, minor, patch = int(r.group(1)), int(r.group(2)), int(r.group(3) or 0)
            else:
                err("Failed to parse version string")
                return
            kversion = Kernel.KernelVersion(None, args.version, major, minor, patch)
        else:
            kversion = Kernel.kernel_version()

        if self.initialize(kversion) is False:
            return

        members = self.members[args.mode]

        if not members:
            warn("Not defined in this version")
            return

        self.out = []
        if args.address:
            try:
                addrs = [read_int_from_memory(args.address + current_arch.ptrsize * i) for i in range(len(members))]
            except gdb.MemoryError:
                if not args.quiet:
                    err("Memory read error")
                return

            if not args.quiet:
                fmt = "{:5s} {:<10s} {:<20s} {:s}"
                legend = ["Index", "Type", "Name", "Value"]
                self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
            width = AddressUtil.get_format_address_width()
            for idx, ((type, name), address) in enumerate(zip(members, addrs)):
                if type == "char*":
                    sym = " {!r}".format(read_cstring_from_memory(address))
                else:
                    sym = Symbol.get_symbol_string(address)
                self.out.append("{:<5d} {:10s} {:20s} {:#0{:d}x}{:s}".format(idx, type, name, address, width, sym))

        else:
            if not args.quiet:
                fmt = "{:5s} {:<10s} {:<20s}"
                legend = ["Index", "Type", "Name"]
                self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
            for idx, (type, name) in enumerate(members):
                self.out.append("{:<5d} {:10s} {:20s}".format(idx, type, name))

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelSysctlCommand(GenericCommand):
    """Dump sysctl parameters."""
    _cmdline_ = "ksysctl"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--filter", action="append", type=re.compile, default=[], help="REGEXP filter.")
    parser.add_argument("-s", "--skip-symlink", action="store_true", help="do not follow symlink (net.* and user.*).")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="enable verbose mode.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    parser.add_argument("--exact", action="store_true", help="use exact match.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -q".format(_cmdline_)

    _note_ = "This command needs CONFIG_RANDSTRUCT=n.\n"
    _note_ += "\n"
    _note_ += "Simplified sysctl_table structure:\n"
    _note_ += "\n"
    _note_ += "   +-sysctl_table_root-+          +----->+-ctl_dir------+\n"
    _note_ += "   | default_set       |          |      | header       |\n"
    _note_ += "   |   ...             |          |      |   ctl_table  |---+\n"
    _note_ += "   |   dir             |          |      |   ...        |   |\n"
    _note_ += "   |     header        |          |      |   parent     |---|-->parent ctl_node\n"
    _note_ += "   |       ctl_table   |          |      |   ...        |   |\n"
    _note_ += "   |       ...         |          |      | root         |   |\n"
    _note_ += "   |       parent      |          |      |   rb_node    |---|-->ctl_node\n"
    _note_ += "   |       ...         |          |      +--------------+   |\n"
    _note_ += "   |     root          |          |                         |\n"
    _note_ += "   |       rb_node     |----+     |   +---------------------+\n"
    _note_ += "   |   ...             |    |     |   |\n"
    _note_ += "   +-------------------+    |     |   +->+-ctl_table(array)-+\n"
    _note_ += "                            |     |      | procname         |-->name[]\n"
    _note_ += "+---------------------------+     |      | data             |-->data[max_len]\n"
    _note_ += "|                                 |      | maxlen           |\n"
    _note_ += "+->+-ctl_node-----+               |      | mode             |\n"
    _note_ += "   | rb_node      |               |      | proc_handler     |\n"
    _note_ += "   |   color      |               |      +------------------+\n"
    _note_ += "   |   right      |--->ctl_node   |      | procname         |-->name[]\n"
    _note_ += "   |   left       |--->ctl_node   |      | data             |-->data[max_len]\n"
    _note_ += "   | header       |---------------+      | maxlen           |\n"
    _note_ += "   +--------------+                      | mode             |\n"
    _note_ += "                                         | proc_handler     |\n"
    _note_ += "                                         +------------------+\n"
    _note_ += "                                         | ...              |\n"
    _note_ += "                                         +------------------+"

    def __init__(self):
        super().__init__()
        self.initialized = False
        return

    def should_be_print(self, procname):
        if self.filter == []:
            return True

        if self.exact:
            for filt in self.filter:
                if filt.pattern == procname:
                    return True
            return False

        else:
            for re_pattern in self.filter:
                if re_pattern.search(procname):
                    return True
            return False

    def sysctl_dump(self, rb_node):
        if self.exact and self.exact_found:
            return

        right = read_int_from_memory(rb_node + current_arch.ptrsize * 1) & ~1 # remove RB_BLACK
        left = read_int_from_memory(rb_node + current_arch.ptrsize * 2) & ~1 # remove RB_BLACK
        ctl_dir = read_int_from_memory(rb_node + current_arch.ptrsize * 3)

        if ctl_dir not in self.seen_ctl_dir:
            self.seen_ctl_dir.append(ctl_dir)

            # parent
            parent = read_int_from_memory(ctl_dir + self.offset_parent)
            parent_path = self.parent_paths.get(parent, "")

            # ctl_table(s)
            ctl_table = read_int_from_memory(ctl_dir)
            while True:
                # procname
                procname = read_int_from_memory(ctl_table)
                if procname == 0:
                    break
                procname_str = read_cstring_from_memory(procname)
                if procname_str is None:
                    break
                param_path = (parent_path + "." + procname_str).lstrip(".")
                self.parent_paths[ctl_dir] = param_path

                # mode
                mode = u32(read_memory(ctl_table + self.offset_mode, 4))

                # `net.*` and `user.*` have a symlink attribute and they are redirected to another location.
                # These must be traced from another root.
                if (mode & 0o0120000) == 0o0120000: # symlink
                    if not self.skip_symlink:
                        ctset = None
                        root = read_int_from_memory(ctl_table + current_arch.ptrsize)
                        if is_valid_addr(root + self.offset_lookup):
                            lookup = read_int_from_memory(root + self.offset_lookup)
                            if lookup == Symbol.get_ksymaddr("net_ctl_header_lookup"): # net.*
                                ctset = self.net_ctset
                            elif lookup == Symbol.get_ksymaddr("set_lookup"): # user.*
                                ctset = self.user_ctset
                        if ctset:
                            symlink_rb_node = read_int_from_memory(ctset + current_arch.ptrsize + self.offset_rb_node)
                            if ctset not in self.seen_ctset:
                                self.seen_ctset.append(ctset)
                                self.sysctl_dump(symlink_rb_node)

                if self.should_be_print(param_path):
                    # If it's not a directory, it should hold data, so dump it.
                    if (mode & 0o0040000) == 0: # not directory
                        maxlen = u32(read_memory(ctl_table + self.offset_maxlen, 4))
                        # data
                        data_addr = read_int_from_memory(ctl_table + current_arch.ptrsize)
                        if data_addr and is_valid_addr(data_addr):
                            # type from handler
                            handler = read_int_from_memory(ctl_table + self.offset_handler)
                            # data length
                            if handler in self.str_types:
                                data_val = read_cstring_from_memory(data_addr)
                                fmt = "{:<56s} {:#018x} {:#07x} {:#010o} {:s}"
                                self.out.append(fmt.format(param_path, data_addr, maxlen, mode, str(data_val))) # allow None
                            elif maxlen == 4:
                                data_val = u32(read_memory(data_addr, 4))
                                fmt = "{:<56s} {:#018x} {:#07x} {:#010o} {:#018x}"
                                self.out.append(fmt.format(param_path, data_addr, maxlen, mode, data_val))
                            elif maxlen == 8:
                                data_val = u64(read_memory(data_addr, 8))
                                fmt = "{:<56s} {:#018x} {:#07x} {:#010o} {:#018x}"
                                self.out.append(fmt.format(param_path, data_addr, maxlen, mode, data_val))
                            elif maxlen == 1:
                                data_val = u8(read_memory(data_addr, 1))
                                fmt = "{:<56s} {:#018x} {:#07x} {:#010o} {:#018x}"
                                self.out.append(fmt.format(param_path, data_addr, maxlen, mode, data_val))
                            elif maxlen == 0:
                                if self.verbose:
                                    fmt = "{:<56s} {:#018x} {:#07x} {:#010o}"
                                    self.out.append(fmt.format(param_path, data_addr, maxlen, mode))
                            else:
                                # type from heuristic
                                data_val = read_cstring_from_memory(data_addr)
                                if data_val and data_val.isprintable() and len(data_val) >= 2:
                                    fmt = "{:<56s} {:#018x} {:#07x} {:#010o} {:s}"
                                    self.out.append(fmt.format(param_path, data_addr, maxlen, mode, data_val))
                                else:
                                    data_val = read_int_from_memory(data_addr)
                                    fmt = "{:<56s} {:#018x} {:#07x} {:#010o} {:#018x}"
                                    self.out.append(fmt.format(param_path, data_addr, maxlen, mode, data_val))
                        else:
                            if self.verbose:
                                fmt = "{:<56s} {:#018x} {:#07x} {:#010o}"
                                self.out.append(fmt.format(param_path, data_addr, maxlen, mode))
                        if self.exact:
                            self.exact_found = True
                            return

                # next array element
                ctl_table += self.sizeof_ctl_table

            rb_node = read_int_from_memory(ctl_dir + self.offset_rb_node) & ~1 # remove RB_BLACK
            if rb_node:
                self.sysctl_dump(rb_node)

        if right:
            self.sysctl_dump(right)
        if left:
            self.sysctl_dump(left)
        return

    def initialize(self):
        if self.initialized:
            return

        """
        struct ctl_table_root {
            struct ctl_table_set {
                int (*is_seen)(struct ctl_table_set *);
                struct ctl_dir dir;
            } default_set;
            struct ctl_table_set *(*lookup)(struct ctl_table_root *root);
            void (*set_ownership)(struct ctl_table_header *head, struct ctl_table *table, kuid_t *uid, kgid_t *gid);
            int (*permissions)(struct ctl_table_header *head, struct ctl_table *table);
        };

        struct ctl_dir {
            struct ctl_table_header {
                union {
                    struct {
                        struct ctl_table *ctl_table;
                        int ctl_table_size;               // 6.6 ~
                        int used;
                        int count;
                        int nreg;
                    };
                    struct rcu_head {
                        struct callback_head *next;
                        void (*func)(struct callback_head *head);
                    } rcu;
                };
                struct completion *unregistering;
                struct ctl_table *ctl_table_arg;
                struct ctl_table_root *root;
                struct ctl_table_set *set;
                struct ctl_dir *parent;
                struct ctl_node *node;
                struct hlist_head inodes;                 // 4.12.2 ~
                struct list_head inodes;                  // 4.11 ~ 4.12.2
                struct hlist_head inodes;                 // 4.9.120 ~ 4.10
                enum {
                    SYSCTL_TABLE_TYPE_DEFAULT,
                    SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY,
                } type;                                   // 6.10 ~
            } header;
            struct rb_root {
                struct rb_node *rb_node;
            } root;
        };

        struct ctl_node {
            struct rb_node {
                unsigned long  __rb_parent_color;
                struct rb_node *rb_right;
                struct rb_node *rb_left;
            } node;
            struct ctl_table_header *header;
        };

        struct ctl_table {
            const char *procname;
            void *data;
            int maxlen;
            umode_t mode;
            struct ctl_table *child;                      // ~ 6.5
            enum {
                SYSCTL_TABLE_TYPE_DEFAULT,
                SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY
            } type;                                       // 6.5 ~ 6.10
            proc_handler *proc_handler;
            struct ctl_table_poll *poll;
            void *extra1;
            void *extra2;
        };
        """

        kversion = Kernel.kernel_version()

        if is_64bit():
            # struct ctl_dir
            if kversion >= "6.10":
                self.offset_rb_node = 0x58
            elif kversion >= "4.9.120" and kversion < "4.10":
                self.offset_rb_node = 0x50
            elif kversion < "4.11":
                self.offset_rb_node = 0x48
            elif kversion < "4.12.2":
                self.offset_rb_node = 0x58
            else:
                self.offset_rb_node = 0x50
            self.offset_parent = 0x38
            # struct ctl_table
            self.offset_maxlen = 0x10
            self.offset_mode = 0x14
            if kversion >= "6.10":
                self.offset_handler = 0x18
                self.sizeof_ctl_table = 0x38
            else:
                self.offset_handler = 0x20
                self.sizeof_ctl_table = 0x40
        else:
            # struct ctl_dir
            if kversion >= "6.10":
                self.offset_rb_node = 0x30
            elif kversion >= "4.9.120" and kversion < "4.10":
                self.offset_rb_node = 0x2c
            elif kversion < "4.11":
                self.offset_rb_node = 0x28
            elif kversion < "4.12.2":
                self.offset_rb_node = 0x30
            else:
                self.offset_rb_node = 0x2c
            self.offset_parent = 0x20
            # struct ctl_table
            self.offset_maxlen = 0x8
            self.offset_mode = 0xc
            if kversion >= "6.10":
                self.offset_handler = 0x10
                self.sizeof_ctl_table = 0x20
            else:
                self.offset_handler = 0x14
                self.sizeof_ctl_table = 0x24

        # struct ctl_table_root
        self.offset_lookup = current_arch.ptrsize + self.offset_rb_node + current_arch.ptrsize

        # the root for `net.*`; init_nsproxy.net_ns.sysctls
        self.net_ctset = None
        init_net = KernelAddressHeuristicFinder.get_init_net()
        if init_net:
            current = init_net
            is_seen = Symbol.get_ksymaddr("is_seen")
            if is_seen:
                while True:
                    v = read_int_from_memory(current)
                    if v == is_seen:
                        self.net_ctset = current
                        break
                    current += current_arch.ptrsize

        # the root for `user.*`; init_user_ns.set
        self.user_ctset = None
        init_user_ns = KernelAddressHeuristicFinder.get_init_user_ns()
        if init_user_ns:
            current = init_user_ns
            # set_is_seen is found in 3 places (v5.19~), so Symbol.get_ksymaddr should not be used.
            set_is_seen = Symbol.get_ksymaddr_multiple("set_is_seen")
            if set_is_seen:
                while True:
                    v = read_int_from_memory(current)
                    if v in set_is_seen:
                        self.user_ctset = current
                        break
                    current += current_arch.ptrsize

        # handle functions
        known_str_types_handlers = [
            "addrconf_sysctl_stable_secret",
            "cdrom_sysctl_info",
            "devkmsg_sysctl_set_loglvl",
            "numa_zonelist_order_handler",
            "proc_allowed_congestion_control",
            "proc_do_uts_string",
            "proc_dostring",
            "proc_dostring_coredump",
            "proc_tcp_available_congestion_control",
            "proc_tcp_available_ulp",
            "seccomp_actions_logged_handler",
            "set_default_qdisc",
        ]
        self.str_types = []
        for handler in known_str_types_handlers:
            handler_addr = Symbol.get_ksymaddr(handler)
            if handler_addr:
                self.str_types.append(handler_addr)

        self.initialized = True
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.filter = args.filter
        self.exact = args.exact
        self.exact_found = False
        self.verbose = args.verbose
        self.skip_symlink = args.skip_symlink

        if self.exact and not self.filter:
            if not args.quiet:
                err("Filter string is needed")
            return

        if not args.quiet:
            info("Wait for memory scan")

        sysctl_table_root = KernelAddressHeuristicFinder.get_sysctl_table_root()
        if sysctl_table_root is None:
            if not args.quiet:
                err("Not found sysctl_table_root")
            return
        if not args.quiet:
            info("sysctl_table_root: {:#x}".format(sysctl_table_root))

        self.initialize()

        root_ctl_dir = sysctl_table_root + current_arch.ptrsize
        root_rb_node = read_int_from_memory(root_ctl_dir + self.offset_rb_node)

        if not args.quiet:
            info("root_ctl_dir: {:#x}".format(root_ctl_dir))
            info("root_rb_node: {:#x}".format(root_rb_node))

        self.out = []
        if not args.quiet:
            fmt = "{:<56s} {:<18s} {:<7s} {:<10s} {:<18s}"
            legend = ["ParamName", "ParamAddress", "MaxLen", "Mode", "ParamValue"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        self.seen_ctl_dir = []
        self.seen_ctset = []
        self.parent_paths = {root_ctl_dir: ""}
        try:
            self.sysctl_dump(root_rb_node)
        except gdb.MemoryError:
            if not args.quiet:
                err("Memory error")
            return

        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class KernelFileSystemsCommand(GenericCommand):
    """Dump filesystems."""
    _cmdline_ = "kfilesystems"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"
    _aliases_ = ["kmounts"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-s", "--skip-mount-path", action="store_true", help="skip resolving path.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _note_ = "This command needs CONFIG_RANDSTRUCT=n.\n"
    _note_ += "\n"
    _note_ += "Simplified file_systems structure:\n"
    _note_ += "\n"
    _note_ += "                  +-->+-file_system_type-+  +-->+-file_system_type-+  +-->...\n"
    _note_ += "                  |   | name             |  |   | name             |  |\n"
    _note_ += "+--------------+  |   | ...              |  |   | ...              |  |\n"
    _note_ += "| file_systems |--+   | next             |--+   | next             |--+\n"
    _note_ += "+--------------+      | fs_supers        |--+   | fs_supers        |\n"
    _note_ += "                      | ...              |  |   | ...              |\n"
    _note_ += "                      +------------------+  |   +------------------+\n"
    _note_ += "                                            |\n"
    _note_ += "   +----------------------------------------+\n"
    _note_ += "   |\n"
    _note_ += "   |   +-super_block-+   +-super_block-+             +-mount--------+\n"
    _note_ += "   |   | s_list      |   | s_list      |             | ...          |\n"
    _note_ += "   |   | ...         |   | ...         |             | mnt          |\n"
    _note_ += "   |   | s_mounts    |   | s_mounts    |---------+   |   mnt_root   |\n"
    _note_ += "   |   | ...         |   | ...         |         |   |   ...        |\n"
    _note_ += "   +-->| s_instances |-->| s_instances |-->...   |   | ...          |\n"
    _note_ += "       | ...         |   | ...         |         +-->| mnt_instance |\n"
    _note_ += "       +-------------+   +-------------+             | ...          |\n"
    _note_ += "                                                     +--------------+"

    def __init__(self):
        super().__init__()
        self.initialized = False
        self.offset_d_iname = None
        self.offset_d_parent = None
        return

    def initialize(self):
        if self.initialized:
            return True

        # file_systems
        self.file_systems = KernelAddressHeuristicFinder.get_file_systems()
        if self.file_systems is None:
            if not self.quiet:
                err("Not found file_systems")
            return
        if not self.quiet:
            info("file_systems: {:#x}".format(self.file_systems))

        """
        struct file_system_type {
            const char *name;
            int fs_flags;
            int (*init_fs_context)(struct fs_context *);
            const struct fs_parameter_spec *parameters;
            struct dentry *(*mount) (struct file_system_type *, int, const char *, void *);
            void (*kill_sb) (struct super_block *);
            struct module *owner;
            struct file_system_type * next;
            struct hlist_head fs_supers;
            struct lock_class_key s_lock_key;
            struct lock_class_key s_umount_key;
            struct lock_class_key s_vfs_rename_key;
            struct lock_class_key s_writers_key[SB_FREEZE_LEVELS];
            struct lock_class_key i_lock_key;
            struct lock_class_key i_mutex_key;
            struct lock_class_key invalidate_lock_key;
            struct lock_class_key i_mutex_dir_key;
        };
        """
        # file_system_type->name
        self.offset_name = 0
        if not self.quiet:
            info("offsetof(file_system_type, name): {:#x}".format(self.offset_name))

        # file_system_type->next
        for i in range(10):
            offset_next = current_arch.ptrsize * i
            valid = True
            current = read_int_from_memory(self.file_systems)
            seen = []
            while current != 0:
                if not is_valid_addr(current):
                    valid = False
                    break
                seen.append(current)
                name_addr = read_int_from_memory(current)
                if not is_valid_addr(name_addr):
                    valid = False
                    break
                name = read_cstring_from_memory(name_addr)
                if len(name) == 0:
                    valid = False
                    break
                current = read_int_from_memory(current + offset_next)
                if current in seen:
                    valid = False
                    break

            if len(seen) == 1:
                valid = False

            if valid:
                self.offset_next = offset_next
                break
        else:
            if not self.quiet:
                err("Not found file_system_type->next")
            return False
        if not self.quiet:
            info("offsetof(file_system_type, next): {:#x}".format(self.offset_next))

        self.offset_fs_supers = self.offset_next + current_arch.ptrsize
        if not self.quiet:
            info("offsetof(file_system_type, fs_supers): {:#x}".format(self.offset_fs_supers))

        """
        struct super_block {
            struct list_head s_list;
            dev_t s_dev;
            unsigned char s_blocksize_bits;
            unsigned long s_blocksize;
            loff_t s_maxbytes;
            struct file_system_type *s_type;
            const struct super_operations *s_op;
            const struct dquot_operations *dq_op;
            const struct quotactl_ops *s_qcop;
            const struct export_operations *s_export_op;
            unsigned long s_flags;
            unsigned long s_iflags;
            unsigned long s_magic;
            struct dentry *s_root;
            struct rw_semaphore s_umount;
            int s_count;
            atomic_t s_active;
        #ifdef CONFIG_SECURITY
            void *s_security;
        #endif
            const struct xattr_handler **s_xattr;
        #ifdef CONFIG_FS_ENCRYPTION
            const struct fscrypt_operations *s_cop;
            struct fscrypt_keyring *s_master_keys;
        #endif
        #ifdef CONFIG_FS_VERITY
            const struct fsverity_operations *s_vop;
        #endif
        #ifdef CONFIG_UNICODE
            struct unicode_map *s_encoding;
            __u16 s_encoding_flags;
        #endif
            struct hlist_bl_head s_roots;
            struct list_head s_mounts;
            struct block_device *s_bdev;
            struct backing_dev_info *s_bdi;
            struct mtd_info *s_mtd;
            struct hlist_node s_instances;  <--- fs_supers points here
            ...
        } __randomize_layout;
        """
        # super_block->{s_instances,s_mounts}
        current = read_int_from_memory(self.file_systems)
        while True:
            if current == 0:
                if not self.quiet:
                    err("Not found file_systems who has valid fs_supers")
                return False
            fs_supers = read_int_from_memory(current + self.offset_fs_supers)
            if is_valid_addr(fs_supers):
                break
            current = read_int_from_memory(current + self.offset_next)

        for i in range(1, 100):
            offset_base = current_arch.ptrsize * i
            """
            0xffff8cb085375800|+0x0000|+000: 0xffff8cb085373000  -> // s_list.next
            0xffff8cb085375808|+0x0008|+001: 0xffff8cb088b77000  -> // s_list.prev
            0xffff8cb085375810|+0x0010|+002: 0x0000000c00000021 // s_blocksize_bits, s_dev
            0xffff8cb085375818|+0x0018|+003: 0x0000000000001000 // s_blocksize
            0xffff8cb085375820|+0x0020|+004: 0x7fffffffffffffff
            0xffff8cb085375828|+0x0028|+005: 0xffffffff8c33f260 <shmem_fs_type>
            0xffff8cb085375830|+0x0030|+006: 0xffffffff8ba36da0 <shmem_ops>
            """
            # check s_list
            a = read_int_from_memory(fs_supers - offset_base)
            if not is_valid_addr(a):
                continue
            b = read_int_from_memory(fs_supers - offset_base + current_arch.ptrsize)
            if not is_valid_addr(b):
                continue

            # check s_blocksize
            c = read_int_from_memory(fs_supers - offset_base + current_arch.ptrsize * 2 + 4 * 2)
            if c == 0x1000:
                self.offset_s_instances = offset_base
                self.offset_s_mounts = self.offset_s_instances - current_arch.ptrsize * 5
                break
        else:
            if not self.quiet:
                err("Not found super_block->s_instances")
            return False
        if not self.quiet:
            info("offsetof(super_block, s_instances): {:#x}".format(self.offset_s_instances))
            info("offsetof(super_block, s_mounts): {:#x}".format(self.offset_s_mounts))

        # super_block->s_dev
        self.offset_s_dev = current_arch.ptrsize * 2
        if not self.quiet:
            info("offsetof(super_block, s_dev): {:#x}".format(self.offset_s_dev))

        """
        struct mount {
            struct hlist_node mnt_hash;
            struct mount *mnt_parent;
            struct dentry *mnt_mountpoint;
            struct vfsmount {
                struct dentry *mnt_root;
                struct super_block *mnt_sb;
                int mnt_flags;
                struct user_namespace *mnt_userns; // v5.12~v6.2
                struct mnt_idmap *mnt_idmap; // v6.2~
            } mnt;
        union {
            struct rcu_head mnt_rcu;
            struct llist_node mnt_llist;
        };
        #ifdef CONFIG_SMP
            struct mnt_pcp __percpu *mnt_pcp;
        #else
            int mnt_count;
            int mnt_writers;
        #endif
            struct list_head mnt_mounts;
            struct list_head mnt_child;
            struct list_head mnt_instance; <-- s_mounts points here
            const char *mnt_devname;
            ...
        } __randomize_layout;
        """
        # mount->mnt_instance
        kversion = Kernel.kernel_version()
        if kversion < "5.12":
            self.offset_mount_mnt_instance = current_arch.ptrsize * 14
        else:
            self.offset_mount_mnt_instance = current_arch.ptrsize * 15

        # mount->{mnt_parent,mnt_mountpoint,mnt}
        self.offset_mount_mnt_parent = current_arch.ptrsize * 2
        self.offset_mount_mnt_mountpoint = current_arch.ptrsize * 3
        self.offset_mount_mnt = current_arch.ptrsize * 4

        # vfsmount->mnt_root
        self.offset_vfsmount_mnt_root = 0

        self.initialized = True
        return True

    def get_dev_num(self, dev):
        major = dev >> 20
        minor = dev & ((1 << 20) - 1)
        name = KernelBlockDevicesCommand.get_bdev_name(major, minor)
        return major, minor, name

    def get_offset_d_iname(self, dentry):
        if self.offset_d_iname:
            return self.offset_d_iname

        """
        struct dentry {
            unsigned int d_flags;
            seqcount_spinlock_t d_seq;
            struct hlist_bl_node d_hash;
            struct dentry *d_parent;
            struct qstr {
                union {
                    struct {
                        HASH_LEN_DECLARE;
                    };
                    u64 hash_len;
                };
                const unsigned char *name; // this points d_iname
            } d_name;
            struct inode *d_inode;
            unsigned char d_iname[DNAME_INLINE_LEN];
            ...
        };
        """
        current = dentry
        while True:
            name = read_int_from_memory(current)
            if 0 < name - current <= 0x20:
                offset_d_iname = name - dentry
                break
            current += current_arch.ptrsize

        self.offset_d_iname = offset_d_iname
        return offset_d_iname

    def get_offset_d_parent(self, dentry, offset_d_iname):
        if self.offset_d_parent:
            return self.offset_d_parent

        offset_dname_name = offset_d_iname - current_arch.ptrsize * 2
        if read_int_from_memory(dentry + offset_dname_name) == 0: # skip if padding
            offset_dname_name -= current_arch.ptrsize
        offset_d_parent = offset_dname_name - 0x8 - current_arch.ptrsize
        if read_int_from_memory(dentry + offset_d_parent) == 0: # skip if padding
            offset_d_parent -= current_arch.ptrsize

        self.offset_d_parent = offset_d_parent
        return offset_d_parent

    def get_mount(self, mnt_instance):
        mount = mnt_instance - self.offset_mount_mnt_instance
        return mount

    def get_mount_point(self, mnt_instance):
        mount = self.get_mount(mnt_instance)
        vfsmnt = mount + self.offset_mount_mnt
        dentry = read_int_from_memory(vfsmnt + self.offset_vfsmount_mnt_root)

        if not is_valid_addr(dentry):
            return None
        offset_d_iname = self.get_offset_d_iname(dentry)
        offset_d_parent = self.get_offset_d_parent(dentry, offset_d_iname)

        def is_root(dentry):
            return dentry == read_int_from_memory(dentry + offset_d_parent)

        filepath = []
        switched = False
        while True:
            if not is_valid_addr(vfsmnt):
                return None
            if not is_valid_addr(dentry):
                return None

            mnt_root = read_int_from_memory(vfsmnt + self.offset_vfsmount_mnt_root)
            if dentry == mnt_root or is_root(dentry):
                parent = read_int_from_memory(mount + self.offset_mount_mnt_parent)

                # Global root?
                if mount != parent:
                    dentry = read_int_from_memory(mount + self.offset_mount_mnt_mountpoint)
                    mount = parent
                    vfsmnt = mount + self.offset_mount_mnt
                    switched = True
                    continue

                name = read_cstring_from_memory(dentry + offset_d_iname)
                if name is None:
                    name_ptr = read_int_from_memory(dentry + offset_d_iname - current_arch.ptrsize * 2)
                    name = read_cstring_from_memory(name_ptr)
                filepath.append(name)
                break

            name = read_cstring_from_memory(dentry + offset_d_iname)
            if name is None:
                name_ptr = read_int_from_memory(dentry + offset_d_iname - current_arch.ptrsize * 2)
                name = read_cstring_from_memory(name_ptr)
            filepath.append(name)

            parent = read_int_from_memory(dentry + offset_d_parent)
            dentry = parent

        filepath = os.path.join(*filepath[::-1])

        # I don't know why but it works
        if switched is False and filepath == "/":
            next_mnt_instance = read_int_from_memory(mnt_instance)
            if next_mnt_instance:
                ret = self.get_mount_point(next_mnt_instance)
                if ret:
                    return ret
            return "-", "-"

        mount = self.get_mount(mnt_instance)
        return mount, filepath

    def get_dev_name(self, mnt_instance):
        offset_mount_mnt_instance = current_arch.ptrsize * 14
        offset_mount_mnt_devname = current_arch.ptrsize * 16

        mnt = mnt_instance - offset_mount_mnt_instance
        devname_p = read_int_from_memory(mnt + offset_mount_mnt_devname)
        devname = read_cstring_from_memory(devname_p)
        return devname

    def parse_file_systems(self, skip_mount_path):
        if not self.quiet:
            fmt = "{:18s} {:12s} {:18s} {:20s} {:6s} {:6s} {:18s} {:18s} {:s}"
            legend = ["file_system_type", "fsname", "super_block", "devname", "major", "minor", "s_mount", "(parsed) mount", "mount_point"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        fst = read_int_from_memory(self.file_systems)
        while fst != 0:
            # parse name
            name_addr = read_int_from_memory(fst + self.offset_name)
            name = read_cstring_from_memory(name_addr)

            # parse suber_block
            fs_supers = read_int_from_memory(fst + self.offset_fs_supers)
            if fs_supers == 0:
                self.out.append("{:#018x} {:12s} {:18s} {:20s} {:6s} {:6s} {:18s} {:18s} {:s}".format(
                    fst, name, "-", "-", "-", "-", "-", "-", "-",
                ))

            else:
                s_instances = fs_supers
                while s_instances:
                    super_block = s_instances - self.offset_s_instances

                    # dev
                    dev = u32(read_memory(super_block + self.offset_s_dev, 4))
                    major, minor, devname = self.get_dev_num(dev)

                    # mount
                    s_mounts = read_int_from_memory(super_block + self.offset_s_mounts)
                    mount = self.get_mount(s_mounts)

                    # mount points
                    if skip_mount_path:
                        parsed_mount, mount_point = "-", "???"
                    else:
                        ret = self.get_mount_point(s_mounts)
                        if ret is None:
                            parsed_mount, mount_point = "-", "???"
                        else:
                            parsed_mount, mount_point = ret
                            if isinstance(parsed_mount, int):
                                parsed_mount = "{:#018x}".format(parsed_mount)

                    # devname
                    if devname == "???":
                        devname = self.get_dev_name(s_mounts)
                    else:
                        devname += " (guessed)"

                    # dump
                    self.out.append("{:#018x} {:12s} {:#018x} {:20s} {:<6d} {:<6d} {:#018x} {:18s} {:s}".format(
                        fst, name, super_block, devname, major, minor, mount, parsed_mount, mount_point,
                    ))
                    # go to next
                    s_instances = read_int_from_memory(s_instances)

            # go to next
            fst = read_int_from_memory(fst + self.offset_next)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if not args.quiet:
            info("Wait for memory scan")

        self.quiet = args.quiet

        if not self.initialize():
            return

        self.out = []
        self.parse_file_systems(args.skip_mount_path)

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelClockSourceCommand(GenericCommand):
    """Dump clock sources."""
    _cmdline_ = "kclock-source"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _note_ = "Simplified clocksource structure:\n"
    _note_ += "\n"
    _note_ += "                        +-clocksource-+\n"
    _note_ += "                        | read        |\n"
    _note_ += "+-clocksource_list-+    | ...         |\n"
    _note_ += "| list_head        |--->| list        |--->...\n"
    _note_ += "+------------------+    | ...         |\n"
    _note_ += "                        +-------------+"

    def get_offset_list(self, clocksource):
        """
        struct clocksource {
            u64 (*read)(struct clocksource *cs);
            u64 mask;
            u32 mult;
            u32 shift;
            u64 max_idle_ns;
            u32 maxadj;
            u32 uncertainty_margin;
        #ifdef CONFIG_ARCH_CLOCKSOURCE_DATA
            struct arch_clocksource_data archdata;
        #endif
            u64 max_cycles;
            const char *name;
            struct list_head list;
            int rating;
            enum clocksource_ids id;
            enum vdso_clock_mode vdso_clock_mode;
            unsigned long flags;
            int (*enable)(struct clocksource *cs);
            void (*disable)(struct clocksource *cs);
            void (*suspend)(struct clocksource *cs);
            void (*resume)(struct clocksource *cs);
            void (*mark_unstable)(struct clocksource *cs);
            void (*tick_stable)(struct clocksource *cs);
        #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
            struct list_head wd_list;
            u64 cs_last;
            u64 wd_last;
        #endif
            struct module *owner;
        };
        """
        current = read_int_from_memory(clocksource)
        for i in range(7, 20):
            candidate_offset = i * current_arch.ptrsize
            v = read_int_from_memory(current - candidate_offset)
            if is_valid_addr(v):
                return candidate_offset
        return None

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if not args.quiet:
            info("Wait for memory scan")

        clocksource_list = KernelAddressHeuristicFinder.get_clocksource_list()
        if clocksource_list is None:
            if not args.quiet:
                err("Not found clocksource_list")
            return
        if not args.quiet:
            info("clocksource_list: {:#x}".format(clocksource_list))

        offset_list = self.get_offset_list(clocksource_list)
        if offset_list is None:
            return
        if not args.quiet:
            info("offsetof(clocksource, list): {:#x}".format(offset_list))

        self.out = []
        width = AddressUtil.get_format_address_width()
        if not args.quiet:
            fmt = "{:<{:d}s} {:20s} {:<{:d}s}"
            legend = ["address", width, "name", "read", width]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
        current = read_int_from_memory(clocksource_list)
        while current != clocksource_list:
            cs = current - offset_list
            read = read_int_from_memory(cs)
            read_sym = Symbol.get_symbol_string(read, nosymbol_string=" <NO_SYMBOL>")
            name_addr = read_int_from_memory(current - current_arch.ptrsize)
            name = read_cstring_from_memory(name_addr)
            self.out.append("{:#0{:d}x} {:20s} {:#0{:d}x}{:s}".format(cs, width, name, read, width, read_sym))
            current = read_int_from_memory(current)

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelTimerCommand(GenericCommand):
    """Dump timer."""
    _cmdline_ = "ktimer"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _note_ = "Simplified timer structure (per-cpu):\n"
    _note_ += "\n"
    _note_ += "+-timer_bases[0]----+    +-timer_list--+    +-timer_list--+\n"
    _note_ += "| ...               |    | entry       |    | entry       |\n"
    _note_ += "| vectors[0]        |--->|   next      |--->|   next      |--->...\n"
    _note_ += "| ...               |    |   pprev     |    |   pprev     |\n"
    _note_ += "| vectors[512or576] |    | expires     |    | expires     |\n"
    _note_ += "| ...               |    | function    |    | function    |\n"
    _note_ += "+-timer_bases[1]----+    | ...         |    | ...         |\n"
    _note_ += "| ...               |    +-------------+    +-------------+\n"
    _note_ += "| vectors[0]        |\n"
    _note_ += "| ...               |\n"
    _note_ += "| vectors[512or576] |\n"
    _note_ += "| ...               |\n"
    _note_ += "+-------------------+\n"
    _note_ += "\n"
    _note_ += "Simplified hrtimer structure (per-cpu):\n"
    _note_ += "\n"
    _note_ += "+-hrtimer_cpu_bases-+\n"
    _note_ += "| ...               |\n"
    _note_ += "| clock_bases[0]    |   +--->+-hrtimer------+\n"
    _note_ += "|   ...             |   |    | node         |\n"
    _note_ += "|   clockid         |   |    |   node       |\n"
    _note_ += "|   ...             |   |    |     color    |\n"
    _note_ += "|   active          |   |    |     right    |--->hrtimer\n"
    _note_ += "|      rb_root      |   |    |     left     |--->hrtimer\n"
    _note_ += "|        rb_root    |---+    |   expires    |\n"
    _note_ += "|        ...        |        | ...          |\n"
    _note_ += "|   get_time        |        | function     |\n"
    _note_ += "|   ...             |        | ...          |\n"
    _note_ += "| ...               |        +--------------+\n"
    _note_ += "| clock_bases[8]    |\n"
    _note_ += "|   ...             |\n"
    _note_ += "+-------------------+"

    def __init__(self):
        super().__init__()
        self.initialized = False
        return

    def initialize(self):
        if self.initialized:
            return True

        # resolve __per_cpu_offset
        __per_cpu_offset = KernelAddressHeuristicFinder.get_per_cpu_offset()
        if __per_cpu_offset is None:
            if not self.quiet:
                info("__per_cpu_offset: Not found")
            self.cpu_offset = []
        else:
            if not self.quiet:
                info("__per_cpu_offset: {:#x}".format(__per_cpu_offset))
            self.cpu_offset = KernelCurrentCommand.get_each_cpu_offset(__per_cpu_offset)

        ### classic timer (unit: tick)

        # timer_bases
        self.timer_bases = KernelAddressHeuristicFinder.get_timer_bases()
        if not self.timer_bases:
            if not self.quiet:
                err("timer_bases: Not found")
            return False
        if not self.quiet:
            info("timer_bases: {:#x}".format(self.timer_bases))

        # per_cpu_timer_bases
        if self.cpu_offset == []:
            self.per_cpu_timer_bases = [self.timer_bases]
        else:
            self.per_cpu_timer_bases = [AddressUtil.align_address(x + self.timer_bases) for x in self.cpu_offset]

        # len(timer_bases)
        if Symbol.get_ksymaddr("sysctl_timer_migration"):
            self.nr_bases = 2
        else:
            self.nr_bases = 1
        if not self.quiet:
            info("nr_bases: {:d}".format(self.nr_bases))

        # sizeof(struct timer_base)
        """
        struct timer_base {
            raw_spinlock_t lock;
            struct timer_list *running_timer;
        #ifdef CONFIG_PREEMPT_RT
            spinlock_t expiry_lock;
            atomic_t timer_waiters;
        #endif
            unsigned long clk;
            unsigned long next_expiry;
            unsigned int cpu;
            bool next_expiry_recalc;
            bool is_idle;
            bool timers_pending;
            DECLARE_BITMAP(pending_map, WHEEL_SIZE);
            struct hlist_head vectors[WHEEL_SIZE];
        } ____cacheline_aligned;
        """
        self.roughly_sizeof_timer_base = 0
        if self.nr_bases == 2:
            timer_base = self.per_cpu_timer_bases[0]

            i = 512
            while True:
                v = read_int_from_memory(timer_base + current_arch.ptrsize * i)
                if v != 0 and not is_valid_addr(v):
                    self.roughly_sizeof_timer_base = current_arch.ptrsize * i
                    break
                i += 1

        # jiffies
        self.jiffies = KernelAddressHeuristicFinder.get_jiffies()
        if not self.jiffies:
            if not self.quiet:
                err("jiffies: Not found")
            return False
        if not self.quiet:
            info("jiffies: {:#x}".format(self.jiffies))

        ### High-resolution kernel timer (unit: nano seconds)

        # hrtimer_bases
        self.hrtimer_bases = KernelAddressHeuristicFinder.get_hrtimer_bases()
        if not self.hrtimer_bases:
            if not self.quiet:
                err("hrtimer_bases: Not found")
            return False
        if not self.quiet:
            info("hrtimer_bases: {:#x}".format(self.hrtimer_bases))

        # per_cpu_hrtimer_bases
        if self.cpu_offset == []:
            self.per_cpu_hrtimer_cpu_bases = [self.hrtimer_bases]
        else:
            self.per_cpu_hrtimer_cpu_bases = [AddressUtil.align_address(x + self.hrtimer_bases) for x in self.cpu_offset]

        """
        struct hrtimer_cpu_base {
            raw_spinlock_t lock;
            unsigned int cpu;
            unsigned int active_bases;
            unsigned int clock_was_set_seq;
            unsigned int hres_active : 1,
                         in_hrtirq : 1,
                         hang_detected : 1,
                         softirq_activated : 1;
        #ifdef CONFIG_HIGH_RES_TIMERS
            unsigned int nr_events;
            unsigned short nr_retries;
            unsigned short nr_hangs;
            unsigned int max_hang_time;
        #endif
        #ifdef CONFIG_PREEMPT_RT
            spinlock_t softirq_expiry_lock;
            atomic_t timer_waiters;
        #endif
            ktime_t expires_next;
            struct hrtimer *next_timer;
            ktime_t softirq_expires_next;
            struct hrtimer *softirq_next_timer;
            struct hrtimer_clock_base {
                struct hrtimer_cpu_base *cpu_base;
                unsigned int index;
                clockid_t clockid;
                seqcount_raw_spinlock_t seq; // v4.16~
                struct hrtimer *running; // v4.16~
                struct timerqueue_head {
                    struct rb_root_cached {          // v5.4~
                        struct rb_root rb_root;      // v5.4~
                        struct rb_node *rb_leftmost; // v5.4~
                    } rb_root;                       // v5.4~
                    struct rb_root head;             // ~v5.3
                    struct timerqueue_node *next;    // ~v5.3
                } active;
                ktime_t (*get_time)(void);
                ktime_t offset;
            } __hrtimer_clock_base_align clock_base[HRTIMER_MAX_CLOCK_BASES];
        } ____cacheline_aligned;

        DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
        {
            .lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
            .clock_base =
            {
                {
                    .index = HRTIMER_BASE_MONOTONIC,
                    .clockid = CLOCK_MONOTONIC,
                    .get_time = &ktime_get,               -------
                },                                              ^
                {                                               | calc this
                    .index = HRTIMER_BASE_REALTIME,             |
                    .clockid = CLOCK_REALTIME,                  v
                    .get_time = &ktime_get_real,          -------
                },
                {
                    .index = HRTIMER_BASE_BOOTTIME,
                    .clockid = CLOCK_BOOTTIME,
                    .get_time = &ktime_get_boottime,
                },
                {
                    .index = HRTIMER_BASE_TAI,
                    .clockid = CLOCK_TAI,
                    .get_time = &ktime_get_clocktai,
                },
                {                                         // v4.16~
                    .index = HRTIMER_BASE_MONOTONIC_SOFT,
                    .clockid = CLOCK_MONOTONIC,
                    .get_time = &ktime_get,
                },
                {                                         // v4.16~
                    .index = HRTIMER_BASE_REALTIME_SOFT,
                    .clockid = CLOCK_REALTIME,
                    .get_time = &ktime_get_real,
                },
                {                                         // v4.16~
                    .index = HRTIMER_BASE_BOOTTIME_SOFT,
                    .clockid = CLOCK_BOOTTIME,
                    .get_time = &ktime_get_boottime,
                },
                {                                         // v4.16~
                    .index = HRTIMER_BASE_TAI_SOFT,
                    .clockid = CLOCK_TAI,
                    .get_time = &ktime_get_clocktai,
                },
            }
        };
        """

        hrtimer_cpu_base = self.per_cpu_hrtimer_cpu_bases[0]

        ktime_get = Symbol.get_ksymaddr("ktime_get")
        ktime_get_real = Symbol.get_ksymaddr("ktime_get_real")
        ktime_get_ofs = None
        ktime_get_real_ofs = None
        i = 0
        while True:
            ofs = current_arch.ptrsize * i
            v = read_int_from_memory(hrtimer_cpu_base + ofs)
            if v == ktime_get:
                ktime_get_ofs = ofs
            elif v == ktime_get_real:
                ktime_get_real_ofs = ofs
            if ktime_get_ofs and ktime_get_real_ofs:
                break
            i += 1
        self.sizeof_hrtimer_clock_base = ktime_get_real_ofs - ktime_get_ofs

        clock_base_1 = ktime_get_ofs + current_arch.ptrsize + 8 # get_time, offset
        self.offset_clock_base = clock_base_1 - self.sizeof_hrtimer_clock_base
        self.offset_clockid = current_arch.ptrsize + 4 # cpu_base, index
        self.offset_get_time = ktime_get_ofs - self.offset_clock_base
        self.offset_rb_root = self.offset_get_time - current_arch.ptrsize * 2

        kversion = Kernel.kernel_version()
        if kversion < "4.16":
            self.num_of_clock_base = 4
        else:
            self.num_of_clock_base = 8

        self.initialized = True
        return True

    def parse_rb_node(self, rb_node):
        if not rb_node or not is_valid_addr(rb_node):
            return []

        right = read_int_from_memory(rb_node + current_arch.ptrsize * 1) & ~1 # remove RB_BLACK
        left = read_int_from_memory(rb_node + current_arch.ptrsize * 2) & ~1 # remove RB_BLACK

        ret = [rb_node]
        if right:
            ret += self.parse_rb_node(right)
        if left:
            ret += self.parse_rb_node(left)
        return ret

    def dump_hrtimer(self):
        """
        struct hrtimer {
            struct timerqueue_node {
                struct rb_node {
                    unsigned long __rb_parent_color;
                    struct rb_node *rb_right;
                    struct rb_node *rb_left;
                } node;
                ktime_t expires;
            } node;
            ktime_t _softexpires;
            enum hrtimer_restart (*function)(struct hrtimer *);
            struct hrtimer_clock_base *base;
            u8 state;
            u8 is_rel;
            u8 is_soft;
            u8 is_hard;
        };
        """

        clockid_dict = {
            0: "CLOCK_REALTIME",
            1: "CLOCK_MONOTONIC",
            2: "CLOCK_PROCESS_CPUTIME_ID",
            3: "CLOCK_THREAD_CPUTIME_ID",
            4: "CLOCK_MONOTONIC_RAW",
            5: "CLOCK_REALTIME_COARSE",
            6: "CLOCK_MONOTONIC_COARSE",
            7: "CLOCK_BOOTTIME",
            8: "CLOCK_REALTIME_ALARM",
            9: "CLOCK_BOOTTIME_ALARM",
            10: "CLOCK_SGI_CYCLE",
            11: "CLOCK_TAI",
        }

        for cpu, hrtimer_cpu_base in enumerate(self.per_cpu_hrtimer_cpu_bases):
            clock_base = hrtimer_cpu_base + self.offset_clock_base
            for base_n in range(self.num_of_clock_base):
                htb = clock_base + self.sizeof_hrtimer_clock_base * base_n
                clockid = u32(read_memory(htb + self.offset_clockid, 4))
                clockid_s = clockid_dict.get(clockid, "UNKNOWN")
                get_time = read_int_from_memory(htb + self.offset_get_time)
                sym = Symbol.get_symbol_string(get_time, nosymbol_string=" <NO_SYMBOL>")
                fmt = "cpu{:d} hrtimer_clock_base[{:d}]: {:#x}  [{:s}; get_time: {:#x}{:s}]"
                self.out.append(titlify(fmt.format(cpu, base_n, htb, clockid_s, get_time, sym)))

                # print legend
                if not self.quiet:
                    fmt = "{:18s}  {:18s}  {:23s}  {:18s} {:s}"
                    legend = ["hrtimer", "expires", "time_to_expired", "function", "symbol"]
                    self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

                rb_node = read_int_from_memory(htb + self.offset_rb_root)
                for hrtimer in self.parse_rb_node(rb_node):
                    expires = u64(read_memory(hrtimer + current_arch.ptrsize * 3, 8))
                    function = read_int_from_memory(hrtimer + current_arch.ptrsize * 3 + 8 * 2)
                    if is_32bit() and not is_valid_addr(function):
                        expires = u64(read_memory(hrtimer + current_arch.ptrsize * 3 + 4, 8))
                        function = read_int_from_memory(hrtimer + current_arch.ptrsize * 3 + 4 + 8 * 2)
                    sym = Symbol.get_symbol_string(function, nosymbol_string=" <NO_SYMBOL>")
                    tte = "? (too hard to calc)"
                    self.out.append("{:#018x}  {:#018x}  {:23s}  {:#018x}{:s}".format(hrtimer, expires, tte, function, sym))
        return

    def dump_timer(self):
        """
        struct timer_list {
            struct hlist_node entry;
            unsigned long expires;
            void (*function)(struct timer_list *);
            u32 flags;
        #ifdef CONFIG_LOCKDEP
            struct lockdep_map lockdep_map;
        #endif
        };
        """

        jiffies = read_int_from_memory(self.jiffies)

        for cpu, timer_base in enumerate(self.per_cpu_timer_bases):
            # dump timer_list
            for base_n in range(self.nr_bases):
                tb = timer_base + self.roughly_sizeof_timer_base * base_n
                self.out.append(titlify("cpu{:d} timer_base[{:d}]: {:#x}".format(cpu, base_n, tb)))

                # print legend
                if not self.quiet:
                    fmt = "{:18s}  {:18s}  {:23s}  {:18s} {:s}"
                    legend = ["timer_list", "expires", "time_to_expired", "function", "symbol"]
                    self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

                i = 0
                while True:
                    addr = tb + current_arch.ptrsize * i
                    v = read_int_from_memory(addr)

                    if v == 0:
                        i += 1
                        continue

                    if i < 512:
                        if not is_valid_addr(v):
                            i += 1
                            continue
                        if read_int_from_memory(v + current_arch.ptrsize) != addr:
                            i += 1
                            continue
                    else:
                        if not is_valid_addr(v):
                            break
                        if read_int_from_memory(v + current_arch.ptrsize) != addr:
                            break

                    timer_list = v
                    expires = read_int_from_memory(timer_list + current_arch.ptrsize * 2)
                    function = read_int_from_memory(timer_list + current_arch.ptrsize * 3)
                    sym = Symbol.get_symbol_string(function, nosymbol_string=" <NO_SYMBOL>")
                    tte = expires - jiffies
                    self.out.append("{:#018x}  {:#018x}  {:#018x} tick  {:#018x}{:s}".format(v, expires, tte, function, sym))
                    i += 1
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        kversion = Kernel.kernel_version()
        if kversion < "4.8":
            err("Unsupported v4.8 or before")
            return

        if not args.quiet:
            info("Wait for memory scan")

        self.quiet = args.quiet

        if not self.initialize():
            return

        self.out = []
        self.dump_timer()
        self.dump_hrtimer()

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelPciDeviceCommand(GenericCommand):
    """Dump PCI devices."""
    _cmdline_ = "kpcidev"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="enable verbose mode.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__()
        self.initialized = False
        self.pci_ids = None
        return

    def initialize(self):
        if self.initialized:
            return True

        # pci_root_buses
        self.pci_root_buses = KernelAddressHeuristicFinder.get_pci_root_buses()
        if not self.pci_root_buses:
            if not self.quiet:
                err("Not found pci_root_buses (maybe, CONFIG_PCI is not set)")
            return False
        if not self.quiet:
            info("pci_root_buses: {:#x}".format(self.pci_root_buses))

        first_root_bus = read_int_from_memory(self.pci_root_buses)
        if self.pci_root_buses == first_root_bus:
            warn("Nothing to dump")
            return False

        # pci_bus->{node,children,devices}
        """
        struct pci_bus {
            struct list_head node;
            struct pci_bus *parent;
            struct list_head children;
            struct list_head devices;
            struct pci_dev *self;
            struct list_head slots;
            struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
            struct list_head resources;
            struct resource busn_res;
            struct pci_ops *ops;
            struct msi_controller *msi;
            void *sysdata;
            struct proc_dir_entry *procdir;
            unsigned char number;
            unsigned char primary;
            unsigned char max_bus_speed;
            unsigned char cur_bus_speed;
        #ifdef CONFIG_PCI_DOMAINS_GENERIC
            int domain_nr;
        #endif
            char name[48];
            unsigned short bridge_ctl;
            pci_bus_flags_t bus_flags;
            struct device *bridge;
            struct device {
                struct kobject {
                    const char *name; <--- search this
                    ...
                } kobj;
                ...
            } dev;
            struct bin_attribute *legacy_io;
            struct bin_attribute *legacy_mem;
            unsigned int is_added:1;
        };
        """

        self.offset_pci_bus_node = 0
        self.offset_pci_bus_children = current_arch.ptrsize * 3
        self.offset_pci_bus_devices = current_arch.ptrsize * 5

        # pci_bus->dev
        for i in range(100):
            v = read_int_from_memory(first_root_bus + current_arch.ptrsize * i)
            if is_valid_addr(v):
                if read_cstring_from_memory(v) == "0000:00":
                    self.offset_pci_bus_dev = current_arch.ptrsize * i
                    if not self.quiet:
                        info("offsetof(pci_bus, dev): {:#x}".format(self.offset_pci_bus_dev))
                    break
        else:
            if not self.quiet:
                err("Not found pci_bus->dev")
            return False

        # pci_dev->{bus_list,vendor,device,subsystem_vendor,subsystem_device,class,revision}
        """
        struct pci_dev {
            struct list_head bus_list;
            struct pci_bus *bus;
            struct pci_bus *subordinate;
            void *sysdata;
            struct proc_dir_entry *procent;
            struct pci_slot *slot;
            unsigned int devfn;
            unsigned short vendor;
            unsigned short device;
            unsigned short subsystem_vendor;
            unsigned short subsystem_device;
            unsigned int class;
            u8 revision;
            u8 hdr_type;
            ...
            struct device {
                struct kobject {
                    const char *name; <--- search this
                    ...
                } kobj;
                ...
            } dev;
            int cfg_size;
            unsigned int irq;
            struct resource resource[DEVICE_COUNT_RESOURCE];
            ...
        };
        """

        self.offset_pci_dev_bus_list = 0
        self.offset_pci_dev_vendor = current_arch.ptrsize * 7 + 4
        self.offset_pci_dev_device = self.offset_pci_dev_vendor + 2
        self.offset_pci_dev_subsystem_vendor = self.offset_pci_dev_device + 2
        self.offset_pci_dev_subsystem_device = self.offset_pci_dev_subsystem_vendor + 2
        self.offset_pci_dev_class = self.offset_pci_dev_subsystem_device + 2
        self.offset_pci_dev_revision = self.offset_pci_dev_class + 4

        # pci_dev->dev
        first_dev = read_int_from_memory(first_root_bus + self.offset_pci_bus_devices)
        for i in range(100):
            v = read_int_from_memory(first_dev + current_arch.ptrsize * i)
            if is_valid_addr(v):
                if read_cstring_from_memory(v) == "0000:00:00.0":
                    self.offset_pci_dev_dev = current_arch.ptrsize * i
                    if not self.quiet:
                        info("offsetof(pci_dev, dev): {:#x}".format(self.offset_pci_dev_dev))
                    break
        else:
            if not self.quiet:
                err("Not found pci_dev->dev")
            return False

        # pci_dev->resource
        """
        struct resource {
            resource_size_t start;
            resource_size_t end;
            const char *name;
            unsigned long flags;
            unsigned long desc;
            struct resource *parent, *sibling, *child;
        };
        """

        ofs_base = self.offset_pci_dev_dev + current_arch.ptrsize
        for i in range(200):
            v = read_int_from_memory(first_dev + ofs_base + current_arch.ptrsize * i)
            if is_valid_addr(v):
                if read_cstring_from_memory(v) == "0000:00:00.0":
                    self.offset_pci_dev_resource = ofs_base + current_arch.ptrsize * i - 0x10
                    self.sizeof_resource = 0x10 + current_arch.ptrsize * 6
                    if not self.quiet:
                        info("offsetof(pci_dev, resource): {:#x}".format(self.offset_pci_dev_resource))
                    break
        else:
            if not self.quiet:
                err("Not found pci_dev->resource")
            return False

        # pci.ids
        pci_ids_file_name = "/usr/share/misc/pci.ids"
        if os.path.exists(pci_ids_file_name):
            if not self.quiet:
                info("use {:s}".format(pci_ids_file_name))
            content = open(pci_ids_file_name).read()
        else:
            pci_ids_file_name = os.path.join(GEF_TEMP_DIR, "pci.ids")
            if os.path.exists(pci_ids_file_name):
                if not self.quiet:
                    info("use {:s}".format(pci_ids_file_name))
                content = open(pci_ids_file_name).read()
            else:
                url = "https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids"
                if not self.quiet:
                    info("use {:s}".format(url))
                content = String.bytes2str(http_get(url) or "")
                if not content:
                    if not self.quiet:
                        info("Connection timed out: {:s}".format(url))
                open(pci_ids_file_name, "w").write(content)
        self.pci_ids = self.parse_pci_ids(content)

        self.initialized = True
        return True

    def parse_pci_ids(self, content):
        dic = {}
        class_mode = False
        for line in content.splitlines():
            if not line or line.startswith("#"):
                continue

            if class_mode is False and line.startswith("C"):
                class_mode = True

            if class_mode is False:
                # device mode
                if not line.startswith("\t"):
                    vendor, *desc = line.split("  ")
                    vendor = int(vendor, 16)
                    dic[vendor] = " ".join(desc)
                    continue

                if line.startswith("\t") and not line.startswith("\t\t"):
                    device, *desc = line[1:].split("  ")
                    device = int(device, 16)
                    dic[vendor, device] = " ".join(desc) # Use the previous value for `vendor`.
                    continue

                if line.startswith("\t\t"):
                    subsystem, *desc = line[2:].split("  ")
                    subv, subd = subsystem.split()
                    subv = int(subv, 16)
                    subd = int(subd, 16)
                    dic[vendor, device, subv, subd] = " ".join(desc) # Use the previous value for `vendor` and `device`.
                    continue

            else:
                # class mode
                if not line.startswith("\t"):
                    base_class, *desc = line.split("  ")
                    base_class = int(base_class[2:], 16)
                    dic["C", base_class] = " ".join(desc)
                    continue

                if line.startswith("\t") and not line.startswith("\t\t"):
                    sub_class, *desc = line[1:].split("  ")
                    sub_class = int(sub_class, 16)
                    dic["C", base_class, sub_class] = " ".join(desc) # Use the previous value for `base_class`.
                    continue

                if line.startswith("\t\t"):
                    prgif, *desc = line[2:].split("  ")
                    prgif = int(prgif, 16)
                    dic["C", base_class, sub_class, prgif] = " ".join(desc) # Use the previous value for `base_class` and `sub_class`.
                    continue
        return dic

    def get_description(self, base_class, sub_class, prgif, vendor, device, subv, subd):
        # The information provided by the programming interface (prgif) is too detailed,
        # so I decided not to use it.
        class_str = self.pci_ids.get(("C", base_class, sub_class), None)
        if class_str is None:
            class_str = self.pci_ids.get(("C", base_class), None)
        if class_str is None:
            class_str = "???"

        device_str = self.pci_ids.get((vendor, device, subv, subd), None)
        if device_str is None:
            device_str = self.pci_ids.get((vendor, device), None)
        if device_str is None:
            device_str = self.pci_ids.get(vendor, None)
        if device_str is None:
            device_str = "???"

        qemu_monitor_out = ""
        if is_qemu_system():
            dev = ""
            res = gdb.execute("monitor info qtree", to_string=True)
            target = "pci id {:04x}:{:04x} (sub {:04x}:{:04x})".format(vendor, device, subv, subd)
            for line in res.splitlines():
                m = re.search('dev: (.+), id ".*"', line)
                if m:
                    dev = m.group(1)
                    continue
                if target in line:
                    qemu_monitor_out = " ({:s})".format(Color.boldify(dev))
                    break

        return "{:s} / {:s}".format(class_str, device_str) + qemu_monitor_out

    def get_flags_str(self, flags_value):
        _flags = {
            "IORESOURCE_BUSY":                  0x80000000,
            "IORESOURCE_AUTO":                  0x40000000,
            "IORESOURCE_UNSET":                 0x20000000,
            "IORESOURCE_DISABLED":              0x10000000,
            "IORESOURCE_EXCLUSIVE":             0x08000000,
            "IORESOURCE_SYSRAM_MERGEABLE":      0x04000000,
            "IORESOURCE_SYSRAM_DRIVER_MANAGED": 0x02000000,
            "IORESOURCE_SYSRAM":                0x01000000,
            "IORESOURCE_MUXED":                 0x00400000,
            "IORESOURCE_WINDOW":                0x00200000,
            "IORESOURCE_MEM_64":                0x00100000,
            "IORESOURCE_STARTALIGN":            0x00080000,
            "IORESOURCE_SIZEALIGN":             0x00040000,
            "IORESOURCE_SHADOWABLE":            0x00020000,
            "IORESOURCE_RANGELENGTH":           0x00010000,
            "IORESOURCE_CACHEABLE":             0x00008000,
            "IORESOURCE_READONLY":              0x00004000,
            "IORESOURCE_PREFETCH":              0x00002000,
            "IORESOURCE_BUS":                   0x00001000,
            "IORESOURCE_DMA":                   0x00000800,
            "IORESOURCE_IRQ":                   0x00000400,
            "IORESOURCE_MEM":                   0x00000200,
            "IORESOURCE_IO":                    0x00000100,
        }
        flags = []
        for k, v in _flags.items():
            if flags_value & v:
                flags.append(k)

        if "IORESOURCE_IO" in flags and "IORESOURCE_MEM" in flags:
            flags.remove("IORESOURCE_IO")
            flags.remove("IORESOURCE_MEM")
            flags.append("IORESOURCE_REG")

        flags_str = " | ".join(flags)
        if flags_str == "":
            flags_str = "none"
        return flags_str.replace("IORESOURCE_", "")

    def search_label(self, start, end):
        if not is_qemu_system():
            return []

        label_list = []
        res = gdb.execute("monitor info mtree -f", to_string=True)
        for line in res.splitlines():
            if not line.startswith("  "):
                continue

            m = re.search(r"  ([0-9a-f]+)-([0-9a-f]+)", line)
            if not m:
                continue

            s = int(m.group(1), 16)
            e = int(m.group(2), 16)
            if not (start <= s and e <= end):
                continue

            line = "      -> " + line.lstrip()
            if line not in label_list:
                label_list.append(line)

        if label_list == []:
            label_list.append("      -> Not found from `monitor info mtree -f")
        return label_list

    def walk_devices(self, dev):
        if not self.quiet:
            fmt = "{:18s} {:12s} {:7s} {:10s} {:10s} {:3s} {:s}"
            legend = ["pci_dev", "name", "class", "vendor:dev", "subsystem", "rev", "description"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        if not dev:
            return

        while dev not in self.seen_dev:
            self.seen_dev.append(dev)

            # parse device info
            dev_name = read_cstring_from_memory(read_int_from_memory(dev + self.offset_pci_dev_dev))
            vendor = u16(read_memory(dev + self.offset_pci_dev_vendor, 2))
            device = u16(read_memory(dev + self.offset_pci_dev_device, 2))
            sub_vendor = u16(read_memory(dev + self.offset_pci_dev_subsystem_vendor, 2))
            sub_device = u16(read_memory(dev + self.offset_pci_dev_subsystem_device, 2))
            revision = u8(read_memory(dev + self.offset_pci_dev_revision, 1))

            # u32:class = u8:unused || u8:base_class || u8:sub_class || u8:programming-interface
            class_val = u32(read_memory(dev + self.offset_pci_dev_class, 4))
            prgif = class_val & 0xff
            sub_class = (class_val >> 8) & 0xff
            base_class = (class_val >> 16) & 0xff

            desc = self.get_description(base_class, sub_class, prgif, vendor, device, sub_vendor, sub_device)
            fmt = "{:#018x} {:s} {:02x}{:02x}:{:02x} {:04x}:{:04x}  {:04x}:{:04x}  {:02x}  {:s}"
            self.out.append(fmt.format(dev, dev_name, base_class, sub_class, prgif, vendor, device, sub_vendor, sub_device, revision, desc))

            if self.verbose:
                # parse resource
                i = 0
                while True:
                    resource_i = dev + self.offset_pci_dev_resource + self.sizeof_resource * i

                    # parse resource name
                    resource_i_name = read_int_from_memory(resource_i + 8 * 2)
                    if not is_valid_addr(resource_i_name):
                        break
                    if read_cstring_from_memory(resource_i_name) != dev_name:
                        break

                    # parse resource address
                    resource_i_start = read_int_from_memory(resource_i + 8 * 0)
                    resource_i_end = read_int_from_memory(resource_i + 8 * 1)
                    resource_i_size = resource_i_end - resource_i_start

                    if resource_i_start != 0 and resource_i_end != 0:
                        # parse resource flags
                        resource_i_flags = read_int_from_memory(resource_i + 8 * 2 + current_arch.ptrsize)
                        flag_str = self.get_flags_str(resource_i_flags)
                        if (resource_i_flags & 0x300) == 0x300:
                            type_str = "RegOffs"
                        elif resource_i_flags & 0x100:
                            type_str = "I/O-Mem"
                        elif resource_i_flags & 0x200:
                            type_str = "PhysMem"
                        else:
                            type_str = "???"

                        fmt = "  [{:d}] {:7s}: {:#010x}-{:#010x} ({:#010x}) flags:{:#x} ({:s})"
                        self.out.append(fmt.format(i, type_str, resource_i_start, resource_i_end, resource_i_size, resource_i_flags, flag_str))

                        # add more details
                        ret = self.search_label(resource_i_start, resource_i_end)
                        self.out.extend(ret)
                    i += 1

            # goto next
            dev = read_int_from_memory(dev + self.offset_pci_dev_bus_list)
        return

    def walk_pci_bus(self, bus):
        if not bus:
            return

        while bus not in self.seen_bus:
            self.seen_bus.append(bus)
            bus_name = read_cstring_from_memory(read_int_from_memory(bus + self.offset_pci_bus_dev))
            self.out.append(titlify("Bus {:s}: {:#x}".format(bus_name, bus)))

            # parse device
            self.seen_dev.append(bus + self.offset_pci_bus_devices)
            dev = read_int_from_memory(bus + self.offset_pci_bus_devices)
            self.walk_devices(dev)

            # parse child
            self.seen_bus.append(bus + self.offset_pci_bus_children)
            first_child_bus = read_int_from_memory(bus + self.offset_pci_bus_children)
            self.walk_pci_bus(first_child_bus)

            # goto next
            bus = read_int_from_memory(bus + self.offset_pci_bus_node)
        return

    def dump_pci(self):
        first_root_bus = read_int_from_memory(self.pci_root_buses)
        self.seen_bus = [self.pci_root_buses]
        self.seen_dev = []
        self.walk_pci_bus(first_root_bus)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if not args.quiet:
            info("Wait for memory scan")

        self.quiet = args.quiet
        self.verbose = args.verbose

        if not self.initialize():
            return

        self.out = []
        self.dump_pci()

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelConfigCommand(GenericCommand):
    """Dump kernel config if available."""
    _cmdline_ = "kconfig"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--filter", action="append", type=re.compile, default=[], help="REGEXP include filter.")
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__()
        self.configs = None
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if args.reparse:
            self.configs = None

        if self.configs is None:
            if not args.quiet:
                info("Wait for memory scan")

            kinfo = Kernel.get_kernel_base()
            if kinfo.ro_base is None:
                err("Not recognized .rodata")
                return
            ro_data = read_memory(kinfo.ro_base, kinfo.ro_size)

            start_pos = ro_data.find(b"IKCFG_ST")
            if start_pos == -1:
                err("Not found IKCFG_ST. This kernel is built as CONFIG_IKCONFIG_PROC=n.")
                return
            end_pos = ro_data.find(b"IKCFG_ED")

            info("IKCFG_ST: {:#x}".format(kinfo.ro_base + start_pos))
            info("IKCFG_ED: {:#x}".format(kinfo.ro_base + end_pos))
            configz = ro_data[start_pos + len("IKCFG_ST"):end_pos]

            import gzip
            try:
                self.configs = String.bytes2str(gzip.decompress(configz))
            except gzip.BadGzipFile:
                err("Gzip decompress error")
                return

        if args.filter:
            out = []
            for line in self.configs.splitlines():
                for filt in args.filter:
                    if filt.search(line):
                        out.append(line)
                        break
            out = "\n".join(out)
        else:
            out = self.configs

        gef_print(out, less=not args.no_pager)
        return


@register_command
class KernelSearchCodePtrCommand(GenericCommand):
    """Search the code pointer in kernel data area."""
    _cmdline_ = "ksearch-code-ptr"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-d", "--depth", default=1, type=int, help="depth of reference. (default: %(default)s)")
    parser.add_argument("-r", "--max-range", default=0, type=lambda x: int(x, 16),
                        help="allowable offset range for each reference. (default: %(default)s)")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def read_int_from_memory_cache(self, addr):
        if addr in self.cache:
            return self.cache[addr]
        out = read_int_from_memory(addr)
        self.cache[addr] = out
        return out

    def get_permission(self, addr):
        for vaddr, size, perm in self.kinfo.maps:
            if vaddr <= addr and addr < vaddr + size:
                return perm
        return "???"

    def search(self, backtrack_info, addr, max_range, depth):
        if depth == 0:
            if not (self.ktext_start <= addr < self.ktext_end):
                return False

            # backtrack
            new_backtrack_info = backtrack_info + [(addr, 0)]
            msg = []
            for addr, offset in new_backtrack_info:
                addr_sym = Symbol.get_symbol_string(addr + offset, nosymbol_string=" <NO_SYMBOL>")
                m = "{:#x}+{:#x}{:s} [{:s}]".format(addr, offset, addr_sym, self.get_permission(addr + offset))
                msg.append(m)

            # create message
            self.out.append("\n  -> ".join(msg) + "\n")
            return True

        valid = False
        if depth not in self.invalid_addrs:
            self.invalid_addrs[depth] = []

        for offset in range(0, max_range + current_arch.ptrsize, current_arch.ptrsize):
            # align to 32bit / 64bit
            cur = AddressUtil.align_address(addr + offset)
            # is aligned?
            if cur & 0x7 != 0:
                continue
            # is kernel address?
            # TODO: more suitable check for kernel address
            if (cur >> (current_arch.ptrsize * 8 - 1)) == 0:
                continue
            # is accessible?
            if not is_valid_addr(cur):
                continue
            # check result of previous recursive
            v = self.read_int_from_memory_cache(cur)
            if v in self.invalid_addrs[depth]:
                continue
            # add to backtrack
            new_backtrack_info = backtrack_info + [(addr, offset)]
            # recursive
            ret = self.search(new_backtrack_info, v, max_range, depth - 1)
            if ret is False:
                self.invalid_addrs[depth].append(v)
            valid |= ret
        return valid

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if args.max_range and args.max_range % current_arch.ptrsize:
            err("range must be a multiple of the pointer size.")
            return

        if args.depth <= 0:
            err("depth must be larger than 0.")
            return

        info("Wait for memory scan")

        self.kinfo = Kernel.get_kernel_base()
        if self.kinfo.has_none or self.kinfo.rwx:
            err("Unsupported environment which has RWX data area")
            return
        self.ktext_start = self.kinfo.text_base
        self.ktext_end = self.kinfo.text_end

        self.invalid_addrs = {}
        self.out = []
        self.cache = {}
        rw_data = read_memory(self.kinfo.rw_base, self.kinfo.rw_size)
        rw_data = slice_unpack(rw_data, current_arch.ptrsize)

        tqdm = GefUtil.get_tqdm()
        for i, rw_d in tqdm(enumerate(rw_data), leave=False, total=len(rw_data)):
            rw_addr = self.kinfo.rw_base + i * current_arch.ptrsize
            backtrack_info = [(rw_addr, 0)]
            self.search(backtrack_info, rw_d, args.max_range, args.depth - 1)

        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class KernelDmesgCommand(GenericCommand):
    """Dump the ring buffer of dmesg area."""
    _cmdline_ = "kdmesg"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -q".format(_cmdline_)

    _note_ = "The information such as [T1] is the thread ID.\n"
    _note_ += "Originally, this information is displayed when CONFIG_PRINTK_CALLER=y.\n"
    _note_ += "However it is always displayed because it is useful.\n"
    _note_ += "\n"
    _note_ += "Simplified dmesg structure (5.10~):\n"
    _note_ += "\n"
    _note_ += "+-----+\n"
    _note_ += "| prb |--+\n"
    _note_ += "+-----+  |\n"
    _note_ += "         |\n"
    _note_ += "+--------+\n"
    _note_ += "|\n"
    _note_ += "+->+-printk_rb_static-+  +-------------------------->+-prb_desc[]----+\n"
    _note_ += "   | desc_ring        |  |                       +---| state_var     |---+\n"
    _note_ += "   |   count_bits     |  | +->+-printk_info[]-+  |   | ...           |   |\n"
    _note_ += "   |   descs          |--+ |  | seq           |  |   +---------------+   |\n"
    _note_ += "   |   infos          |----+  | ts_nsec       |  |   | state_var     |   |\n"
    _note_ += "   |   head_id        |       | text_len      |  |   | ...           |   |\n"
    _note_ += "   |   tail_id        |       | facility      |  |   +---------------+   |\n"
    _note_ += "   |   ...            |       | flags, level  |  |   | ...           |   |\n"
    _note_ += "   | text_data_ring   |       | caller_id     |  |   +---------------+<--+\n"
    _note_ += "   |   size_bits      |       | dev_info      |  |   | state_var     |\n"
    _note_ += "   |   data           |--+    +---------------+  |   | text_blk_lpos |\n"
    _note_ += "   |   head_lpos      |  |    | seq           |  |   |   begin       |(=text block start offset)\n"
    _note_ += "   |   tail_lpos      |  |    | ts_nsec       |  |   |   next        |(=text block end offset)\n"
    _note_ += "   | fail             |  |    | text_len      |  |   +---------------+\n"
    _note_ += "   +------------------+  |    | facility      |  |   | state_var     |\n"
    _note_ += "                         |    | flags, level  |  |   | text_blk_lpos |\n"
    _note_ += "+------------------------+    | caller_id     |  |   |   begin       |\n"
    _note_ += "|                             | dev_info      |  |   |   next        |\n"
    _note_ += "+->+-printk_record-+          +---------------+  |   +---------------+\n"
    _note_ += "   | info          |          | ...           |  |\n"
    _note_ += "   | text_buf      |-->text   +---------------+<-+\n"
    _note_ += "   | text_buf_size |          | seq           |\n"
    _note_ += "   +---------------+          | ...           |\n"
    _note_ += "                              +---------------+\n"
    _note_ += "* prb_desc and printk_info are accessed in two ways. One is seq number based access which is simply incremented\n"
    _note_ += "  and the other is id number based access by lower bit of state_var.\n"
    _note_ += "  1-A. (Seq-based prb_desc): Preserving entry state and entry index (=id).\n"
    _note_ += "  1-B. (Id-based prb_desc): Preserving begin and next.\n"
    _note_ += "  2-A. (Seq-based printk_info): Preserving text data length, time, thread ID, etc. for each entry.\n"
    _note_ += "  2-B. (Id-based printk_info): Preserving seq for ring buffer reuse.\n"
    _note_ += "\n"
    _note_ += "Simplified dmesg structure (~5.10):\n"
    _note_ += "\n"
    _note_ += "+-----------+\n"
    _note_ += "| __log_buf |-------->+-log_buffer-----+   ^     ^\n"
    _note_ += "+-----------+         | ts_nsec        |   |     |\n"
    _note_ += "                      | len            |-->|     |\n"
    _note_ += "                      | text_len       |   |     |\n"
    _note_ += "                      | ...            |   |     |\n"
    _note_ += "                      | text[text_len] |   |     |\n"
    _note_ += "                      +----------------+   v     |\n"
    _note_ += "+---------------+     | ...            |         |\n"
    _note_ += "| log_first_idx |---->+----------------+         |\n"
    _note_ += "+---------------+     | ts_nsec        |         |\n"
    _note_ += " =start               | len            |         |    +-------------+\n"
    _note_ += "                      | text_len       |         |<---| log_buf_len |\n"
    _note_ += "                      | ...            |         |    +-------------+\n"
    _note_ += "                      | text[text_len] |         |\n"
    _note_ += "                      +----------------+         |\n"
    _note_ += "+---------------+     | ...            |         |\n"
    _note_ += "| log_next_idx  |---->+----------------+         |\n"
    _note_ += "+---------------+     | ts_nsec        |         |\n"
    _note_ += " =end                 | len            |         |\n"
    _note_ += "                      | text_len       |         |\n"
    _note_ += "                      | ...            |         |\n"
    _note_ += "                      | text[text_len] |         |\n"
    _note_ += "                      +----------------+         v"

    def dump_printk_ringbuffer(self, ring_buffer_name, ring_buffer_address):
        """
        # linux 5.10.x ~
        struct printk_ringbuffer {
            struct prb_desc_ring {
                unsigned int count_bits;
                struct prb_desc* descs;
                struct printk_info* infos;
                atomic_long_t head_id;
                atomic_long_t tail_id;
                atomic_long_t last_finalized_id; // v5.18~
            } desc_ring;
            struct prb_data_ring {
                unsigned int size_bits;
                char* data;
                atomic_long_t head_lpos;
                atomic_long_t tail_lpos;
            } text_data_ring;
            atomic_long_t fail;
        };
        """

        current = ring_buffer_address
        rb = {}
        rb["desc_ring"] = {}
        rb["desc_ring"]["count_bits"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        rb["desc_ring"]["descs"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        rb["desc_ring"]["infos"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        rb["desc_ring"]["head_id"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        rb["desc_ring"]["tail_id"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        rb["text_data_ring"] = {}
        size_bits = read_int_from_memory(current)
        if size_bits > current_arch.ptrsize * 8:
            current += current_arch.ptrsize # last_finalized_id
            size_bits = read_int_from_memory(current)
        rb["text_data_ring"]["size_bits"] = size_bits
        current += current_arch.ptrsize
        rb["text_data_ring"]["data"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        rb["text_data_ring"]["head_lpos"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        rb["text_data_ring"]["tail_lpos"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        rb["fail"] = read_int_from_memory(current)

        if not self.quiet:
            info("name: {:s}".format(ring_buffer_name))
            info("address: {:#x}".format(ring_buffer_address))
            info("desc_ring.count_bits: {:#x}".format(rb["desc_ring"]["count_bits"]))
            info("desc_ring.descs: {:#x}".format(rb["desc_ring"]["descs"]))
            info("desc_ring.infos: {:#x}".format(rb["desc_ring"]["infos"]))
            info("desc_ring.head_id: {:#x}".format(rb["desc_ring"]["head_id"]))
            info("desc_ring.tail_id: {:#x}".format(rb["desc_ring"]["tail_id"]))
            info("text_data_ring.size_bits: {:#x}".format(rb["text_data_ring"]["size_bits"]))
            info("text_data_ring.data: {:#x}".format(rb["text_data_ring"]["data"]))
            info("text_data_ring.head_lpos: {:#x}".format(rb["text_data_ring"]["head_lpos"]))
            info("text_data_ring.tail_lpos: {:#x}".format(rb["text_data_ring"]["tail_lpos"]))
            info("fail: {:#x}".format(rb["fail"]))

        def read_desc_i(descs_addr, seq):
            """
            struct prb_desc {
                atomic_long_t state_var;
                struct prb_data_blk_lpos {
                    unsigned long begin;
                    unsigned long next;
                } text_blk_lpos;
            };
            """
            sizeof_desc = current_arch.ptrsize * 3
            current = descs_addr + sizeof_desc * seq
            if not is_valid_addr(current):
                return False
            desc = {}
            desc["state_var"] = read_int_from_memory(current)
            desc["text_blk_lpos"] = {}
            current += current_arch.ptrsize
            desc["text_blk_lpos"]["begin"] = read_int_from_memory(current)
            current += current_arch.ptrsize
            desc["text_blk_lpos"]["next"] = read_int_from_memory(current)
            current += current_arch.ptrsize
            return desc

        def read_info_i(infos_addr, seq):
            """
            struct printk_info {
                u64 seq;        /* sequence number */
                u64 ts_nsec;    /* timestamp in nanoseconds */
                u16 text_len;   /* length of text message */
                u8 facility;    /* syslog facility */
                u8 flags:5;     /* internal record flags */
                u8 level:3;     /* syslog level */
                u32 caller_id;  /* thread id or processor id */
                struct dev_printk_info dev_info;
            };
            """
            sizeof_info = 8 + 8 + 2 + 1 + 1 + 4 + 16 + 48
            current = infos_addr + sizeof_info * seq
            if not is_valid_addr(current):
                return False
            info = {}
            info["seq"] = u64(read_memory(current, 8))
            current += 8
            info["ts_nsec"] = u64(read_memory(current, 8))
            current += 8
            info["text_len"] = u16(read_memory(current, 2))
            current += 2
            info["facility"] = u8(read_memory(current, 1))
            current += 1
            info["flags"] = u8(read_memory(current, 1)) & 0b11111
            info["level"] = (u8(read_memory(current, 1)) >> 5) & 0b111
            current += 1
            info["caller_id"] = u32(read_memory(current, 4))
            current += 4
            info["dev_info"] = {}
            info["dev_info"]["subsystem"] = read_memory(current, 16)
            current += 16
            info["dev_info"]["device"] = read_memory(current, 48)
            current += 48
            return info

        seq_mask = (1 << rb["desc_ring"]["count_bits"]) - 1
        state_var_id_mask = ~(3 << (current_arch.ptrsize * 8 - 2))
        get_desc_state = lambda sv: (sv >> (current_arch.ptrsize * 8 - 2)) & 3
        size_bits = rb["text_data_ring"]["size_bits"]
        data_size_mask = (1 << size_bits) - 1

        info("Wait for reading records...")

        seq = 0
        while True:
            # prb_read
            # - Read prb_desc and printk_info based on seq number.
            seq_based_desc = read_desc_i(rb["desc_ring"]["descs"], seq & seq_mask)
            seq_based_info = read_info_i(rb["desc_ring"]["infos"], seq & seq_mask)

            # desc_read_finalized_seq, desc_read
            # - Read prb_desc and printk_info based on id number.
            id = seq_based_desc["state_var"] & state_var_id_mask
            id_based_desc = read_desc_i(rb["desc_ring"]["descs"], id & seq_mask)
            id_based_info = read_info_i(rb["desc_ring"]["infos"], id & seq_mask)
            # - Determine whether it is the last entry based on the state and seq values.
            if (id_based_desc["state_var"] & state_var_id_mask) != id: # desc_miss
                break
            if get_desc_state(id_based_desc["state_var"]) in [0, 1]: # desc_reserved, desc_commited
                break
            if id_based_info["seq"] != seq:
                if seq == 0:
                    # ring buffer is already looping
                    seq = id_based_info["seq"]
                else:
                    break
            if get_desc_state(id_based_desc["state_var"]) == 2: # desc_reusable
                if (id_based_desc["text_blk_lpos"]["begin"], id_based_desc["text_blk_lpos"]["next"]) == (1, 1):
                    break

            # copy_data, get_data
            # - Calculates the start address of text data from the begin and next values.
            begin = id_based_desc["text_blk_lpos"]["begin"]
            next = id_based_desc["text_blk_lpos"]["next"]
            if (begin >> size_bits) == (next >> size_bits) and (begin < next):
                src = rb["text_data_ring"]["data"] + (begin & data_size_mask)
            elif ((begin + (1 << size_bits)) >> size_bits) == (next >> size_bits):
                src = rb["text_data_ring"]["data"]
            else:
                raise
            size = seq_based_info["text_len"]
            src += current_arch.ptrsize
            if size:
                entry = String.bytes2str(read_memory(src, size))
            else:
                entry = ""

            # timestamp
            sec = seq_based_info["ts_nsec"] // 1000 // 1000 // 1000
            nsec = seq_based_info["ts_nsec"] % (1000 * 1000 * 1000)
            nsec_str = "{:09d}".format(nsec)[:6]
            # thread id. This is displayed when CONFIG_PRINTK_CALLER=y, but always displayed because it is useful.
            caller_id_str = "T{:d}".format(seq_based_info["caller_id"])
            # output
            formatted_entry = "[{:5d}.{:s}] [{:>6s}] {:s}".format(sec, nsec_str, caller_id_str, entry)
            self.out.append(formatted_entry)

            seq += 1
        return

    def dump_printk_log_buffer(self, log_first_idx, log_end_idx, buf_start, buf_end):
        """
        # ~ linux 5.9.x
        struct printk_log {
            u64 ts_nsec;        /* timestamp in nanoseconds */
            u16 len;            /* length of entire record */
            u16 text_len;       /* length of text buffer */
            u16 dict_len;       /* length of dictionary buffer */
            u8 facility;        /* syslog facility */
            u8 flags:5;         /* internal record flags */
            u8 level:3;         /* syslog level */
        #ifdef CONFIG_PRINTK_CALLER
            u32 caller_id;      /* thread id or processor id */
        #endif
        };
        """

        CONFIG_PRINTK_CALLER = Symbol.get_ksymaddr("print_caller") is not None
        length_of_caller_id = 4 if CONFIG_PRINTK_CALLER else 0
        sizeof_printk_log = 16 + length_of_caller_id

        pos = buf_start + log_first_idx
        log_end_pos = buf_start + log_end_idx

        while pos != log_end_pos:
            x = read_memory(pos, 16)
            ts_nsec = u64(x[:8])
            rec_len = u16(x[8:10])

            if rec_len == 0:
                pos = buf_start
                continue

            text_len = u16(x[10:12])
            #dict_len = u16(x[12:14])
            #facility = u8(x[14:15])
            #flags = (u8(x[15:16]) >> 0) & 0b11111
            #level = (u8(x[15:16]) >> 5) & 0b111
            text = read_memory(pos + sizeof_printk_log, text_len)

            sec = ts_nsec // 1000 // 1000 // 1000
            nsec = ts_nsec % (1000 * 1000 * 1000)
            nsec_str = "{:09d}".format(nsec)[:6]

            # split from multi-line message
            for t in String.bytes2str(text).splitlines():
                formatted_entry = "[{:5d}.{:s}] {:s}".format(sec, nsec_str, t)
                self.out.append(formatted_entry)

            pos += rec_len
            if pos >= buf_end:
                break # something is wrong
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if not args.quiet:
            info("Wait for memory scan")

        self.quiet = args.quiet
        self.out = []
        kversion = Kernel.kernel_version()

        if kversion >= "5.10":
            # new structure
            printk_rb_static = KernelAddressHeuristicFinder.get_printk_rb_static()
            if printk_rb_static is None:
                err("Not found printk_rb_static")
                return
            self.dump_printk_ringbuffer("printk_rb_static", printk_rb_static)

        else:
            # old structure
            log_first_idx_ptr = KernelAddressHeuristicFinder.get_log_first_idx()
            if log_first_idx_ptr is None:
                err("Not found log_first_idx")
                return
            if not self.quiet:
                info("log_first_idx: {:#x}".format(log_first_idx_ptr))

            log_next_idx_ptr = KernelAddressHeuristicFinder.get_log_next_idx()
            if log_next_idx_ptr is None:
                err("Not found log_next_idx")
                return
            if not self.quiet:
                info("log_next_idx: {:#x}".format(log_next_idx_ptr))

            log_buf_start = KernelAddressHeuristicFinder.get___log_buf()
            if log_buf_start is None:
                err("Not found __log_buf")
                return
            if not self.quiet:
                info("__log_buf: {:#x}".format(log_buf_start))

            log_buf_len_ptr = KernelAddressHeuristicFinder.get_log_buf_len()
            if log_buf_len_ptr is None:
                err("Not found log_buf_len")
                return
            if not self.quiet:
                info("log_buf_len: {:#x}".format(log_buf_len_ptr))

            log_first_idx = u32(read_memory(log_first_idx_ptr, 4))
            log_next_idx = u32(read_memory(log_next_idx_ptr, 4))
            log_buf_len = u32(read_memory(log_buf_len_ptr, 4))
            log_buf_end = log_buf_start + log_buf_len
            if not self.quiet:
                info("*log_first_idx: {:#x}".format(log_first_idx))
                info("*log_next_idx: {:#x}".format(log_next_idx))
                info("*log_buf_len: {:#x}".format(log_buf_len))
            self.dump_printk_log_buffer(log_first_idx, log_next_idx, log_buf_start, log_buf_end)

        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class StringsCommand(GenericCommand):
    """Search ASCII string (recursively) from specific location."""
    _cmdline_ = "strings"
    _category_ = "03-a. Memory - Search"
    _aliases_ = ["ascii-search"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="the location to search from.")
    parser.add_argument("end_location", metavar="END_LOCATION", type=AddressUtil.parse_address, nargs="?",
                        help="the end location to search from. (default: 64)")
    parser.add_argument("-f", "--filter", action="append", type=re.compile, default=[], help="REGEXP include filter.")
    parser.add_argument("-e", "--exclude", action="append", type=re.compile, default=[], help="REGEXP exclude filter.")
    parser.add_argument("-d", "--depth", default=3, type=int, help="recursive depth. (default: %(default)s)")
    parser.add_argument("-r", "--range", default=0x40, type=lambda x: int(x, 16),
                        help="search range for recursively. (default: %(default)s)")
    parser.add_argument("-m", "--minlen", default=8, type=int, help="minimum string length (default: %(default)s)")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0x00007ffffffde000 0x00007ffffffff000              # detect all\n".format(_cmdline_)
    _example_ += "{:s} --minlen 10 0x00007ffffffde000 0x00007ffffffff000  # filter by length\n".format(_cmdline_)
    _example_ += '{:s} -f "GLIBC" 0x00007ffffffde000 0x00007ffffffff000   # filter by keywords (-f, -e). need double-escape'.format(_cmdline_)

    def strings(self, data, len_threshold):
        string_printable = bytes(range(0x20, 0x7f))
        strings_result = []
        current_str = ""
        i = 0
        while i < len(data):
            if data[i] in string_printable:
                current_str += chr(data[i])
            else:
                if len(current_str) >= len_threshold:
                    strings_result.append((i - len(current_str), current_str))
                current_str = ""
            i += 1
        if len(current_str) >= len_threshold:
            strings_result.append((i - len(current_str), current_str))
        return strings_result

    def search_ascii(self, queue):
        seen_addr = []
        seen_cstr = []

        while queue:
            location, search_range, depth = queue.pop(0)

            # get data
            data = b""
            try:
                # read range
                data += read_memory(location, search_range)
                # read extra
                while data and data[-1] in range(0x20, 0x7f):
                    data += read_memory(location + len(data), 1)
            except gdb.MemoryError:
                pass

            # search string
            for offset, cstr in self.strings(data, self.minlen):
                address = location + offset

                seen = False
                for seen_addr_start, seen_addr_end in seen_cstr:
                    if seen_addr_start <= address < seen_addr_end:
                        seen = True
                        break
                if seen:
                    continue

                if not self.filter or any(filt.search(cstr) for filt in self.filter):
                    if not self.exclude or not any(ex.search(cstr) for ex in self.exclude):
                        self.out.append("{:s}: {:s}".format(str(ProcessMap.lookup_address(address)), cstr))
                seen_cstr.append((address, address + len(cstr) + 1))

            # search pointer for recursive search
            if depth == 0:
                continue
            aligned_data = data[current_arch.ptrsize - location % current_arch.ptrsize:]
            if len(aligned_data) % 8:
                aligned_data = aligned_data[:-(len(aligned_data) % current_arch.ptrsize)]
            for addr in slice_unpack(aligned_data, current_arch.ptrsize):
                if addr in seen_addr:
                    continue
                if is_valid_addr(addr):
                    queue.append((addr, self.search_range, depth - 1))
                    seen_addr.append(addr)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        self.filter = args.filter
        self.exclude = args.exclude
        self.minlen = args.minlen
        self.search_range = args.range
        if args.end_location:
            first_range = args.end_location - args.location
        else:
            first_range = args.range
        self.out = []
        queue = [(args.location, first_range, args.depth)]
        self.search_ascii(queue)

        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class SyscallTableViewCommand(GenericCommand):
    """Display syscall_table entries."""
    _cmdline_ = "syscall-table-view"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--filter", action="append", type=re.compile, default=[], help="REGEXP filter.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}\n".format(_cmdline_)
    _example_ += "{:s} --filter write".format(_cmdline_)

    def __init__(self):
        super().__init__()
        self.cached_table = {}
        return

    @switch_to_intel_syntax
    def parse_syscall_table(self, sys_call_table_addr):
        # scan
        cached_table = []
        i = 0
        while True:
            addr = sys_call_table_addr + i * current_arch.ptrsize
            if not is_valid_addr(addr):
                break
            syscall_function_addr = read_int_from_memory(addr)
            if (is_arm32() or is_arm64()) and syscall_function_addr % 4: # should be aligned
                break
            if not is_valid_addr(syscall_function_addr): # if entry is valid, no error
                break

            # check symbol
            symbol = Symbol.get_symbol_string(syscall_function_addr)
            if symbol is None:
                symbol = Symbol.get_ksymaddr_symbol(syscall_function_addr)
                if symbol is None:
                    symbol = " <NO_SYMBOL>"
            elif "+" in symbol:
                break

            # check if valid insn or not
            insn = get_insn(syscall_function_addr)
            insn2 = get_insn_next(syscall_function_addr)
            if insn is None or insn2 is None:
                break

            if is_x86():
                # detect endbr, so slide
                if insn.mnemonic in ["endbr64", "endbr32"]:
                    codelen = len(insn.opcodes)
                    insn2 = get_insn_next(insn.address + codelen)
                    insn = get_insn(insn.address + codelen)

                # detect `call non-essential-function` e.g.: perf, trace, debug, ...
                while insn and insn2 and insn.mnemonic == "call":
                    codelen = len(insn.opcodes)
                    insn2 = get_insn_next(insn.address + codelen)
                    insn = get_insn(insn.address + codelen)

            elif is_arm64():
                # detect bti, so slide
                if insn.mnemonic in ["bti"]:
                    codelen = len(insn.opcodes)
                    insn2 = get_insn_next(insn.address + codelen)
                    insn = get_insn(insn.address + codelen)

                # detect `bl non-essential-function` e.g.: perf, trace, debug, ...
                while insn and insn2 and insn.mnemonic == "bl":
                    codelen = len(insn.opcodes)
                    insn2 = get_insn_next(insn.address + codelen)
                    insn = get_insn(insn.address + codelen)

            elif is_arm32():
                # detect `bl non-essential-function` e.g.: perf, trace, debug, ...
                while insn and insn2 and insn.mnemonic in ["bl", "blx"]:
                    codelen = len(insn.opcodes)
                    insn2 = get_insn_next(insn.address + codelen)
                    insn = get_insn(insn.address + codelen)

            # check again
            if insn is None or insn2 is None:
                break

            # check if the target system call is disabled
            is_valid = True
            if is_x86():
                if is_x86_64():
                    err = "0xffffffffffffffda"
                else:
                    err = "0xffffffda"
                if len(insn.operands) == 2 and insn.operands[-1] == err:
                    if insn2.mnemonic == "ret":
                        is_valid = False
                    elif insn2.mnemonic == "jmp":
                        try:
                            insn3 = get_insn(AddressUtil.parse_address(insn2.operands[-1]))
                            if insn3 and insn3.mnemonic == "ret":
                                is_valid = False
                        except (gdb.error, ValueError):
                            pass
            elif is_arm64():
                if len(insn.operands) == 2 and insn.operands[-1].split("\t")[0].strip() == "#0xffffffffffffffda":
                    is_valid = False
                elif len(insn.operands) == 3 and insn.operands[-1] == "// #-38":
                    is_valid = False

            cached_table.append([i, addr, syscall_function_addr, symbol, is_valid])
            i += 1
        return cached_table

    def syscall_table_view(self, orig_tag, sys_call_table_addr, syscall_list, nr_base=0):
        if sys_call_table_addr is None:
            if not self.quiet:
                self.out.append("{} {}".format(Color.colorify("[+]", "bold red"), "Not found symbol"))
            return

        # It maintains the cache both when running with and without symbols.
        try:
            AddressUtil.parse_address("_stext")
            tag = "symboled_" + orig_tag
        except gdb.error:
            tag = orig_tag

        # parse
        if tag not in self.cached_table:
            self.cached_table[tag] = self.parse_syscall_table(sys_call_table_addr)

        # print legend
        if not self.quiet:
            fmt = "{:8s} {:5s} {:7s} {:30s} {:18s} {:18s} {:s}"
            legend = ["Tag", "Index", "IsValid", "Syscall Name", "Table Address", "Function Address", "Symbol"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        # for duplication check
        seen_count = {}
        for _, _, syscall_function_addr, _, _ in self.cached_table[tag]:
            seen_count[syscall_function_addr] = seen_count.get(syscall_function_addr, 0) + 1

        # print
        for i, addr, syscall_function_addr, symbol, is_valid in self.cached_table[tag]:
            if i + nr_base in syscall_list.table:
                expected_name = syscall_list.table[i + nr_base].name
            else:
                expected_name = "<UNDEFINED_IN_THIS_ARCH>"

            fmt = "{:8s} [{:03d}] {:7s} {:30s} {:#018x} {:#018x}{:s}"
            if seen_count[syscall_function_addr] == 1 and is_valid: # valid entry
                msg = fmt.format(orig_tag, i, "valid", expected_name, addr, syscall_function_addr, symbol)
            if seen_count[syscall_function_addr] > 1 or not is_valid: # invalid entry
                msg = fmt.format(orig_tag, i, "invalid", expected_name, addr, syscall_function_addr, symbol)
                msg = Color.grayify(msg)

            if not self.filter:
                self.out.append(msg)
            else:
                for re_pattern in self.filter:
                    if re_pattern.search(msg):
                        self.out.append(msg)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet
        self.filter = args.filter
        self.out = []

        if is_x86_32():
            if not self.quiet:
                self.out.append(titlify("sys_call_table (x86)"))
            sys_call_table_addr = KernelAddressHeuristicFinder.get_sys_call_table_x86()
            self.syscall_table_view("x86", sys_call_table_addr, get_syscall_table("X86", "N32"))

        elif is_x86_64():
            if not self.quiet:
                self.out.append(titlify("sys_call_table (x64)"))
            sys_call_table_addr = KernelAddressHeuristicFinder.get_sys_call_table_x64()
            self.syscall_table_view("x86_64", sys_call_table_addr, get_syscall_table("X86", "64"))

            kversion = Kernel.kernel_version()

            if not self.quiet:
                self.out.append(titlify("ia32_sys_call_table"))
            if kversion < "6.6.26":
                sys_call_table_addr = KernelAddressHeuristicFinder.get_sys_call_table_x86()
                self.syscall_table_view("x86_32", sys_call_table_addr, get_syscall_table("X86", "32"))
            else:
                if not self.quiet:
                    self.out.append("ia32_sys_call_table is removed from 6.6.26.")
                    self.out.append("each entry is embedded in `ia32_sys_call()` as call instruction.")

            if not self.quiet:
                self.out.append(titlify("x32_sys_call_table"))
            if kversion < "6.6.26":
                sys_call_table_addr = KernelAddressHeuristicFinder.get_sys_call_table_x32()
                self.syscall_table_view("x86_x32", sys_call_table_addr, get_syscall_table("X86", "64"), nr_base=0x40000000)
            else:
                if not self.quiet:
                    self.out.append("x32_sys_call_table is removed from 6.6.26.")
                    self.out.append("each entry is embedded in `x32_sys_call()` as call instruction.")

        elif is_arm32():
            if not self.quiet:
                self.out.append(titlify("sys_call_table (arm32)"))
            sys_call_table_addr = KernelAddressHeuristicFinder.get_sys_call_table_arm32()
            self.syscall_table_view("arm32", sys_call_table_addr, get_syscall_table("ARM", "N32"))

        elif is_arm64():
            if not self.quiet:
                self.out.append(titlify("sys_call_table (arm64)"))
            sys_call_table_addr = KernelAddressHeuristicFinder.get_sys_call_table_arm64()
            self.syscall_table_view("arm64", sys_call_table_addr, get_syscall_table("ARM64", "ARM"))

            if not self.quiet:
                self.out.append(titlify("compat_sys_call_table (arm32)"))
            sys_call_table_addr = KernelAddressHeuristicFinder.get_sys_call_table_arm64_compat()
            self.syscall_table_view("arm64_32", sys_call_table_addr, get_syscall_table("ARM", "32"))

        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


class ExecAsm:
    """Execute embedded asm. e.g.: ExecAsm(asm_op_list).exec_code().
    WARNING: Disable `-enable-kvm` option for qemu-system; If set, this code will crash the guest OS."""
    def __init__(self, target_codes, regs=None, step=None, debug=False):
        self.stdout = 1
        self.debug = debug
        self.regs = regs
        self.step = step or 1

        codes = []
        if target_codes:
            # to stop another thread
            codes += [current_arch.infloop_insn]
            if current_arch.has_delay_slot:
                codes += [current_arch.nop_insn]
            codes += target_codes

        # list to bytes
        if Endian.is_big_endian():
            self.code = b"".join(code[::-1] for code in codes)
        else:
            self.code = b"".join(codes)
        return

    def get_state(self):
        d = {}

        # pc
        # This value is used to point to the code location. It is not used to restore registers.
        d["pc"] = current_arch.pc
        if is_arm32():
            if current_arch.is_thumb():
                d["pc"] -= 1

        # code
        d["code"] = read_memory(d["pc"], len(self.code))

        # reg
        d["reg"] = {}
        for reg in current_arch.all_registers:
            d["reg"][reg] = get_register(reg)
        return d

    def revert_state(self, d):
        # code
        write_memory(d["pc"], d["code"])

        # reg
        for reg, v in d["reg"].items():
            if get_register(reg) == v:
                continue
            if (is_hppa32() or is_hppa64()) and reg == "$pc":
                continue
            if is_sh4() and reg in ["$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7"]:
                reg = reg + "b0" # since r0-r7 cannot be changed directly, use bank 0
            try:
                gdb.execute("set {:s} = {:#x}".format(reg, v), to_string=True)
            except Exception as e:
                if str(e).startswith("Cannot access memory at address"):
                    pass
                else:
                    info("set {:s} = {:#x} is failed".format(reg, v))
        return

    def close_stdout(self):
        if self.debug:
            return

        self.stdout_bak = os.dup(self.stdout)
        f = open("/dev/null")
        os.dup2(f.fileno(), self.stdout)
        f.close()
        EventHooking.gef_on_stop_unhook(EventHandler.hook_stop_handler)
        return

    def revert_stdout(self):
        if self.debug:
            return
        EventHooking.gef_on_stop_hook(EventHandler.hook_stop_handler)
        os.dup2(self.stdout_bak, self.stdout)
        os.close(self.stdout_bak)
        return

    def modify_regs(self):
        if not self.regs:
            return

        for reg, v in self.regs.items():
            if get_register(reg) == v:
                continue
            try:
                gdb.execute("set {:s} = {:#x}".format(reg, v), to_string=True)
            except Exception as e:
                if str(e).startswith("Cannot access memory at address"):
                    pass
                else:
                    info("set {:s} = {:#x} is failed".format(reg, v))
        return

    def exec_code(self):
        # backup
        d = self.get_state()

        # modify code, regs
        self.modify_regs()
        write_memory(d["pc"], self.code)
        if self.debug:
            gdb.execute("context")

        # skip infloop
        if self.code:
            dst = d["pc"] + len(current_arch.infloop_insn)
            if current_arch.has_delay_slot:
                dst += len(current_arch.nop_insn)
            if is_hppa32() or is_hppa64():
                gdb.execute("set $pcoqh = {:#x}".format(dst), to_string=True)
                dst2 = dst + len(current_arch.syscall_insn)
                gdb.execute("set $pcoqt = {:#x}".format(dst2), to_string=True)
            elif is_sparc32() or is_sparc32plus() or is_sparc64():
                gdb.execute("set $pc = {:#x}".format(dst), to_string=True)
                dst2 = dst + len(current_arch.syscall_insn)
                gdb.execute("set $npc = {:#x}".format(dst2), to_string=True)
            else:
                gdb.execute("set $pc = {:#x}".format(dst), to_string=True)
            if self.debug:
                gdb.execute("context")

        # exec
        self.close_stdout()
        if self.debug:
            gdb.execute("context")
        try:
            gdb.execute("stepi {:d}".format(self.step), to_string=True)
        except gdb.MemoryError:
            pass
        if self.debug:
            gdb.execute("context")
        self.revert_stdout()

        # get result
        ret = self.get_state()

        # revert
        self.revert_state(d)
        return ret


class ExecSyscall(ExecAsm):
    """Execute embedded asm for syscall. e.g.: ExecSyscall(nr, args).exec_code().
    WARNING: Disable `-enable-kvm` option for qemu-system; If set, this code will crash the guest OS."""
    def __init__(self, nr, args, debug=False):
        self.stdout = 1
        self.debug = debug
        self.syscall_nr = nr
        self.syscall_args = args

        if is_hppa32() or is_hppa64():
            self.step = 3 # syscall, delay slot, trampoline
        else:
            self.step = 1

        codes = []

        # to stop another thread
        codes += [current_arch.infloop_insn]
        if current_arch.has_delay_slot:
            codes += [current_arch.nop_insn]

        # syscall opcodes
        syscall_insn = current_arch.syscall_insn
        if is_s390x() and nr <= 127:
            syscall_insn = syscall_insn[:-1] + bytes([nr])

        codes += [syscall_insn]
        if current_arch.has_syscall_delay_slot:
            codes += [current_arch.nop_insn]

        # list to bytes
        if Endian.is_big_endian():
            self.code = b"".join(code[::-1] for code in codes)
        else:
            self.code = b"".join(codes)
        return

    def get_state(self):
        d = super().get_state()

        # mem
        if is_mips32():
            d["mem"] = {}
            for offset in [0x10, 0x14, 0x18, 0x1c]:
                d["mem"][offset] = read_memory(current_arch.sp + offset, 4)
        if is_cris():
            d["mem"] = {}
            for offset in [0x1c]:
                d["mem"][offset] = read_memory(current_arch.sp + offset, 4)
        return d

    def revert_state(self, d):
        super().revert_state(d)

        # mem
        if is_mips32():
            for offset in [0x10, 0x14, 0x18, 0x1c]:
                if read_memory(current_arch.sp + offset, 4) == d["mem"][offset]:
                    continue
                write_memory(current_arch.sp + offset, d["mem"][offset])
        if is_cris():
            for offset in [0x1c]:
                if read_memory(current_arch.sp + offset, 4) == d["mem"][offset]:
                    continue
                write_memory(current_arch.sp + offset, d["mem"][offset])
        return

    def modify_regs(self):
        # modify syscall args
        if is_mips32():
            syscall_parameters = current_arch.syscall_parameters_o32
        else:
            syscall_parameters = current_arch.syscall_parameters
        for reg, val in zip(syscall_parameters, self.syscall_args):
            if is_mips32() and "+" in reg:
                reg, off = reg.split("+")
                write_memory(get_register(reg) + int(off, 16), p32(val))
            else:
                if is_sh4() and reg in ["$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7"]:
                    reg = reg + "b0" # since r0-r7 cannot be changed directly, use bank 0
                gdb.execute("set {:s} = {:#x}".format(reg, val), to_string=True)

        # modify syscall register
        if is_s390x():
            if self.syscall_nr > 127: # embedded in instruction
                reg = current_arch.syscall_register[1]
                gdb.execute("set {:s} = {:#x}".format(reg, self.syscall_nr), to_string=True)
        else:
            reg = current_arch.syscall_register
            if is_sh4() and reg in ["$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7"]:
                reg = reg + "b0" # since r0-r7 cannot be changed directly, use bank 0
            gdb.execute("set {:s} = {:#x}".format(reg, self.syscall_nr), to_string=True)
        return


@register_command
class TlsCommand(GenericCommand):
    """Display TLS base address. Requires glibc."""
    _cmdline_ = "tls"
    _category_ = "02-b. Process Information - Base Address"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-a", "--all", action="store_true", help="show all TLS address.")
    parser.add_argument("-v", "--verbose", action="count", default=1, help="show more entries.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def print_all_tls(self):
        selected_thread = gdb.selected_thread()
        threads = gdb.selected_inferior().threads()
        threads = sorted(threads, key=lambda th: th.num)

        if not threads:
            err("No thread is detected")
            return

        for thread in threads:
            msg = "Thread Id:{:d}".format(thread.num)
            try:
                thread.switch()
            except gdb.error:
                msg += " - Failed to switch to this thread"
                continue
            tls = current_arch.get_tls()
            msg += " - {:#x}".format(tls)
            gef_print(msg)

        selected_thread.switch() # revert
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        if not current_arch.tls_supported:
            warn("This command cannot work under this architecture.")
            return

        if args.all:
            self.print_all_tls()
            return

        tls = current_arch.get_tls()
        if tls is None:
            err("Failed to get TLS address")
            return

        if not is_valid_addr(tls):
            err("Cannot access memory at address {:#x}".format(tls))
            return

        self.out = []
        self.out.append("$tls = {:#x}".format(tls))
        gdb.execute("p $tls = {:#x}".format(tls), to_string=True)

        n_entries = 16 * args.verbose
        self.out.append(titlify("TLS-{:#x}".format(current_arch.ptrsize * n_entries)))
        r = gdb.execute("dereference $tls-{:#x} {:d} --no-pager".format(current_arch.ptrsize * n_entries, n_entries), to_string=True)
        self.out.extend(r.rstrip().splitlines())
        self.out.append(titlify("TLS"))
        r = gdb.execute("dereference $tls {:d} --no-pager".format(n_entries), to_string=True)
        self.out.extend(r.rstrip().splitlines())

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class FsbaseCommand(GenericCommand):
    """Display fsbase address."""
    _cmdline_ = "fsbase"
    _category_ = "02-b. Process Information - Base Address"
    _aliases_ = ["fs"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    _note_ = "This command overwrites original \"fs (=tui focus)\" command."

    @parse_args
    @only_if_gdb_running
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    @exclude_specific_gdb_mode(mode=("qiling", "kgdb"))
    def do_invoke(self, args):
        fsbase = current_arch.get_fs()
        if fsbase is not None:
            gef_print("$fs_base: {:#x}".format(fsbase))
        return


@register_command
class GsbaseCommand(GenericCommand):
    """Display gsbase address."""
    _cmdline_ = "gsbase"
    _category_ = "02-b. Process Information - Base Address"
    _aliases_ = ["gs"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qiling", "kgdb"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        gsbase = current_arch.get_gs()
        if gsbase is not None:
            gef_print("$gs_base: {:#x}".format(gsbase))
        return


@register_command
class GdtInfoCommand(GenericCommand):
    """Print GDT/LDT entries. If user-land, show sample entries."""
    _cmdline_ = "gdtinfo"
    _category_ = "04-a. Register - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--only-gdt", action="store_true", help="show only GDT entries (qemu-system only).")
    parser.add_argument("--only-ldt", action="store_true", help="show only LDT entries (qemu-system only).")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    parser.add_argument("-v", "--verbose", action="store_true", help="also display bit information of gdt entries.")
    _syntax_ = parser.format_help()

    # arch/x86/include/asm/segment.h
    SEGMENT_DESCRIPTION_64 = {
        0: "NULL",
        1: "KERNEL32_CS",
        2: "KERNEL_CS",
        3: "KERNEL_DS",
        4: "DEFAULT_USER32_CS",
        5: "DEFAULT_USER_DS",
        6: "DEFAULT_USER_CS",
        7: "???",
        8: "TSS-part1",
        9: "TSS-part2",
        10: "LDT-part1",
        11: "LDT-part2",
        12: "TLS_#1",
        13: "TLS_#2",
        14: "TLS_#3",
        15: "CPUNODE",
    }
    SEGMENT_DESCRIPTION_32 = {
        0: "NULL",
        1: "RESERVED",
        2: "RESERVED",
        3: "RESERVED",
        4: "UNUSED",
        5: "UNUSED",
        6: "TLS_#1",
        7: "TLS_#2",
        8: "TLS_#3",
        9: "RESERVED",
        10: "RESERVED",
        11: "RESERVED",
        12: "KERNEL_CS",
        13: "KERNEL_DS",
        14: "DEFAULT_USER_CS",
        15: "DEFAULT_USER_DS",
        16: "TSS",
        17: "LDT",
        18: "PNPBIOS_CS32",
        19: "PNPBIOS_CS16",
        20: "PNPBIOS_DS",
        21: "PNPBIOS_TS1",
        22: "PNPBIOS_TS2",
        23: "APMBIOS_BASE",
        24: "APMBIOS",
        25: "APMBIOS",
        26: "ESPFIX_SS",
        27: "PERCPU",
        28: "STACK_CANARY",
        29: "UNUSED",
        30: "UNUSED",
        31: "DOUBLEFAULT_TSS",
    }

    def print_seg_info(self):
        if not is_alive():
            return
        gef_print(titlify("Current register values"))
        for k in ["cs", "ds", "es", "fs", "gs", "ss"]:
            v = get_register(k)
            rpl = v & 0b11
            ti = (v >> 2) & 0b1
            index = (v >> 3)
            red_k = Color.colorify("{:4s}".format(k), "bold red")
            gef_print("{:s}: {:#4x} (=rpl:{:d}, ti:{:d}, index:{:d})".format(red_k, v, rpl, ti, index))
        gef_print(" * rpl: Requested Privilege Level (0:Ring0, 3:Ring3)")
        gef_print(" * ti: Table Indicator (0:GDT, 1:LDT)")
        gef_print(" * index: Index of GDT/LDT")
        gef_print(" * segment register value = (index << 3) | (ti << 2) | rpl")
        gef_print(" * commonly used cs values:")
        gef_print("   * x64 code: 0x33")
        gef_print("   * x86 code (on x64): 0x23")
        gef_print("   * x86 code (native): 0x73")
        return

    def entry_unpack(self, vals):
        if isinstance(vals, list):
            val = vals[0] # for 64bit SYSTEM segment
        else:
            val = vals

        # parse
        _entry = {}
        _entry["value"] = val

        _entry["type_bytes"] = (val >> 40) & 0b1111
        _entry["p"] = (val >> 47) & 0b1
        _entry["dpl"] = (val >> 45) & 0b11

        _entry["s"] = (val >> 44) & 0b1
        _entry["s_s"] = ["SYSTEM", "CODE/DATA"][_entry["s"]]

        if _entry["s"] == 0:
            # SYSTEM segment
            _entry["type_bytes_s"] = Color.boldify({
                0b0000: ["Reserved", "Reserved"],
                0b0001: ["Available 16bit TSS", "Reserved"],
                0b0010: ["LDT", "LDT"],
                0b0011: ["Busy 16bit TSS", "Reserved"],
                0b0100: ["16bit call gate", "Reserved"],
                0b0101: ["16/32bit task gate", "Reserved"],
                0b0110: ["16bit interrupt gate", "Reserved"],
                0b0111: ["16bit trap gate", "Reserved"],
                0b1000: ["Reserved", "Reserved"],
                0b1001: ["Available 32bit TSS", "64bit TSS"],
                0b1010: ["Reserved", "Reserved"],
                0b1011: ["Busy 32bit TSS", "Busy 64bit TSS"],
                0b1100: ["32bit call gate", "64bit call gate"],
                0b1101: ["Reserved", "Reserved"],
                0b1110: ["32bit interrupt gate", "64bit interrupt gate"],
                0b1111: ["32bit trap gate", "64bit trap gate"],
            }[_entry["type_bytes"]][is_x86_64()])

        if _entry["s"] == 0 and _entry["type_bytes"] == 0b1100:
            # SYSTEM segment (call gate)
            _entry["offseg0"] = val & 0xffff
            _entry["segsel"] = (val >> 16) & 0xffff
            _entry["offseg1"] = (val >> 48) & 0xffff
            _entry["offseg"] = (_entry["offseg1"] << 16) | _entry["offseg0"]

            if isinstance(vals, list):
                # for 64bit SYSTEM segment (call gate)
                _entry["value"] = vals[1] # overwrite
                _entry["offseg2"] = vals[1] & 0xffffffff
                _entry["offseg"] |= _entry["offseg2"] << 32

        else:
            # CODE/DATA segment or SYSTEM segment (not call gate)
            _entry["g"] = (val >> 54) & 0x01
            grsize = {0: 1, 1: 4096}[_entry["g"]]

            _entry["limit0"] = val & 0xffff
            _entry["base0"] = (val >> 16) & 0xffff
            _entry["base1"] = (val >> 32) & 0xff
            _entry["limit1"] = (val >> 48) & 0x0f
            _entry["base2"] = (val >> 56) & 0xff

            _entry["limit"] = ((_entry["limit1"] << 16) | _entry["limit0"]) * grsize
            _entry["base"] = (_entry["base2"] << 24) | (_entry["base1"] << 16) | _entry["base0"]

            if isinstance(vals, list):
                # for 64bit SYSTEM segment (not call gate)
                _entry["value"] = vals[1] # overwrite
                _entry["base3"] = vals[1] & 0xffffffff
                _entry["base"] |= _entry["base3"] << 32

            if _entry["s"] == 1:
                # CODE/DATA segment
                _entry["db"] = (val >> 53) & 0x01
                _entry["l"] = (val >> 52) & 0x01
                dbl = (_entry["db"] << 1) | _entry["l"]
                _entry["dbl"] = "{:d}".format(dbl)
                _entry["dbl_s"] = ["16bit", "64bit", "32bit", "(N/A)"][dbl]

                _entry["avl"] = (val >> 51) & 0x01

                _entry["e"] = (val >> 43) & 0x01
                _entry["dc"] = (val >> 42) & 0x01
                _entry["rw"] = (val >> 41) & 0x01
                _entry["ac"] = (val >> 40) & 0x01
                if _entry["e"] == 0:
                    # DATA segment
                    _entry["e_s"] = Color.boldify("DATA")
                    _entry["rw_s"] = ["RO", "RW"][_entry["rw"]]
                    _entry["dc_s"] = ["EXPAND-UP", "EXPAND-DOWN"][_entry["dc"]]
                else:
                    # CODE segment
                    _entry["e_s"] = Color.boldify("CODE")
                    _entry["rw_s"] = ["RO", "RX"][_entry["rw"]]
                    _entry["dc_s"] = ["NON-CONFORMING", "CONFORMING"][_entry["dc"]]
                _entry["ac_s"] = ["NotAccessed", "Accessed"][_entry["ac"]]

        Entry = collections.namedtuple("Entry", _entry.keys())
        return Entry(*_entry.values())

    def entry2str(self, value, value_only=False):
        if value_only:
            return "{:#018x}".format(value)

        if value == 0: # and not list
            return "{:#018x}".format(value)

        entry = self.entry_unpack(value)
        out = ""
        out += "{:#018x} ".format(entry.value)
        if entry.s == 0 and entry.type_bytes == 0b1100: # SYSTEM - call gate
            out += "{:#018x} ".format(entry.segsel)
            out += "{:#010x} ".format(entry.offseg)
            out += "{:15s}".format("")

            out += "{:<1d} ".format(entry.p)
            out += "{:<3d} ".format(entry.dpl)
            out += "{:<1d}{:11s} ".format(entry.s, "({:s})".format(entry.s_s))

            out += "{:#06b}({:s})".format(entry.type_bytes, entry.type_bytes_s)

        else:
            out += "{:#018x} ".format(entry.base)
            out += "{:#010x} ".format(entry.limit)
            out += "{:<1d} ".format(entry.g)

            if entry.s == 0: # SYSTEM - Other
                out += "{:13s}".format("")
            else: # CODE/DATA
                out += "{:<1s}({:5s}) ".format(entry.dbl, entry.dbl_s)
                out += "{:<3d} ".format(entry.avl)

            out += "{:<1d} ".format(entry.p)
            out += "{:<3d} ".format(entry.dpl)
            out += "{:<1d}{:11s} ".format(entry.s, "({:s})".format(entry.s_s))

            if entry.s == 0: # SYSTEM - Other
                out += "{:#06b}({:s})".format(entry.type_bytes, entry.type_bytes_s)
            else: # CODE/DATA
                type_bytes_s = []
                type_bytes_s.append(entry.e_s)
                type_bytes_s.append(entry.dc_s)
                type_bytes_s.append(entry.rw_s)
                type_bytes_s.append(entry.ac_s)
                type_bytes_s = ",".join(type_bytes_s)
                out += "{:#06b}({:s})".format(entry.type_bytes, type_bytes_s)
        return out

    def get_segreg_list(self):
        regs = {}
        if is_alive():
            for k in ["cs", "ds", "es", "fs", "gs", "ss"]:
                v = get_register(k)
                ti = (v >> 2) & 0b1
                index = int(v >> 3)
                if v != 0 and ti == 0:
                    regs[index] = regs.get(index, []) + [k]
        return regs

    def print_entries(self, entries, segm_desc=None, skip_null=False):
        regs = self.get_segreg_list()

        # print legend
        fmt = "{:2s} {:20s} {:18s} {:18s} {:10s} {:1s} {:8s} {:3s} {:1s} {:3s} {:12s} {:s}"
        legs = ["#", "SegmentName", "Value", "BASE", "LIMIT", "G", "D/B,L", "AVL", "P", "DPL", "S", "TYPE"]
        gef_print(Color.colorify(fmt.format(*legs), Config.get_gef_setting("theme.table_heading")))

        # print entry
        i = 0
        concat_prev = False
        while i < len(entries):
            # check null entry
            if entries[i] == 0 and skip_null:
                if not concat_prev:
                    i += 1
                    continue

            # segment name
            if segm_desc:
                segname = segm_desc.get(i, "Undefined")
            else:
                segname = "???"

            # parse and make string
            entry = self.entry_unpack(entries[i])
            if concat_prev:
                # lower half of 64bit SYSTEM entries
                estr = self.entry2str([entries[i - 1], entries[i]])
                concat_prev = False

                if not segname.endswith("-part2"):
                    segname += "-part2"

            elif entry.s == 0 and entry.type_bytes != 0 and (is_x86_64() or is_emulated32()):
                # upper half of 64bit SYSTEM entries
                estr = self.entry2str(entries[i], value_only=True)
                concat_prev = True

                if not segname.endswith("-part1"):
                    segname += "-part1"

            else:
                # CODE/DATA segment or 16/32bit SYSTEM entries
                estr = self.entry2str(entries[i])
                concat_prev = False

            # extra info
            reglist = regs.get(i, [])
            if reglist:
                reglist = "{:s}{:s}".format(LEFT_ARROW, " ,".join(reglist))
                regstr = Color.colorify(reglist, Config.get_gef_setting("theme.dereference_register_value"))
            else:
                regstr = ""

            # print
            gef_print("{:<2d} {:20s} {:s} {:s}".format(i, segname, estr, regstr))

            i += 1
        return

    def print_gdt_example(self):
        # print title
        if is_x86_64() or is_emulated32():
            gef_print(titlify("GDT Entry (x64 sample)"))
            segm_desc = self.SEGMENT_DESCRIPTION_64
        else:
            gef_print(titlify("GDT Entry (x86 sample)"))
            segm_desc = self.SEGMENT_DESCRIPTION_32

        # print legend
        info("*** This is an {:s} ***".format(Color.boldify("EXAMPLE")))

        # print entry
        if is_x86_64() or is_emulated32():
            entries = [
                0x0000000000000000,
                0x00cf9b000000ffff,
                0x00af9b000000ffff,
                0x00cf93000000ffff,
                0x00cffb000000ffff,
                0x00cff3000000ffff,
                0x00affb000000ffff,
                0x0000000000000000,
                0x00008b000000206f,
                0x00000000fffffe00,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0040f50000000000,
            ]
        else:
            entries = [
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0x00cf9a000000ffff,
                0x00cf93000000ffff,
                0x00cffa000000ffff,
                0x00cff3000000ffff,
                0xff008b804000206b,
                0x0000000000000000,
                0x00409a000000ffff,
                0x00009a000000ffff,
                0x000092000000ffff,
                0x0000920000000000,
                0x0000920000000000,
                0x00409a000000ffff,
                0x00009a000000ffff,
                0x004092000000ffff,
                0x00cf92000000ffff,
                0x038f93708000ffff,
                0x0000000000000000,
                0x0000000000000000,
                0x0000000000000000,
                0xc40089706000206b,
            ]

        if is_x86_64():
            segm_desc = self.SEGMENT_DESCRIPTION_64
        else:
            segm_desc = self.SEGMENT_DESCRIPTION_32
        self.print_entries(entries, segm_desc)
        return

    def print_gdt_real(self):
        # parse real value
        if is_qemu_system():
            res = gdb.execute("monitor info registers", to_string=True)
            gdtr = re.search(r"GDT\s*=\s*(\S+) (\S+)", res)
            base, limit = [int(gdtr.group(i), 16) for i in range(1, 3)]

        elif is_vmware():
            res = gdb.execute("monitor r gdtr", to_string=True)
            r = re.search(r"gdtr base=(\S+) limit=(\S+)", res)
            base, limit = int(r.group(1), 16), int(r.group(2), 16)

        # print title
        gef_print(titlify("GDT Entry: {:#x}".format(base)))

        # check initialized or not
        if (base == 0x0 and limit == 0xffff) or limit == 0x0:
            err("GDT is uninitialized")
            return

        entries = slice_unpack(read_memory(base, limit + 1), 8)
        if is_x86_64():
            segm_desc = self.SEGMENT_DESCRIPTION_64
        else:
            segm_desc = self.SEGMENT_DESCRIPTION_32
        self.print_entries(entries, segm_desc)
        return

    def print_ldt_real(self):
        # parse real value
        if is_qemu_system():
            res = gdb.execute("monitor info registers", to_string=True)
            ldtr = re.search(r"LDT=\S+ (\S+) (\S+)", res)
            base, limit = [int(ldtr.group(i), 16) for i in range(1, 3)]

        elif is_vmware():
            res = gdb.execute("monitor r ldtr", to_string=True)
            r = re.search(r"ldtr base=(\S+) limit=(\S+)", res)
            base, limit = int(r.group(1), 16), int(r.group(2), 16)

        # print title
        gef_print(titlify("LDT Entry: {:#x}".format(base)))

        # check initialized or not
        if (base == 0x0 and limit == 0xffff) or limit == 0x0:
            err("LDT is uninitialized")
            return

        entries = slice_unpack(read_memory(base, limit + 1), 8)
        self.print_entries(entries, skip_null=True)
        return

    def print_gdt_entry_legend(self):
        gef_print(titlify("legend (GDT/LDT entry for S=1)"))
        gef_print("              <Flag bytes->        <----- Access bytes----->")
        gef_print("                                          <---Type bytes--->")
        gef_print(" 31            23 22 21 20 19       15 14  12   11 10 9  8  7            0bit")
        gef_print("-------------------------------------------------------------------------- 8byte")
        gef_print("|             |  |D |  |A |        |  |   |    |  |D |R |A |             |")
        gef_print("| BASE2 31:24 |G |/ |L |V | LIMIT1 |P |DPL|S(1)|E |  |  |  | BASE1 23:16 |")
        gef_print("|             |  |B |  |L | 19:16  |  |   |    |  |C |W |C |             |")
        gef_print("-------------------------------------------------------------------------- 4byte")
        gef_print("|            BASE0 15:0            |             LIMIT0 15:0             |")
        gef_print("-------------------------------------------------------------------------- 0byte")
        gef_print(" * BASE                 : Start address")
        gef_print(" * LIMIT                : Segment size (4KB unit if G=1)")
        gef_print(" * Flag bytes")
        gef_print("   * G                  : Granularity flag (0:SegLimitAsByte, 1:SegLimitAs4KB)")
        gef_print("   * D/B                : Segment flag (0:16bitSeg, 1:32bitSeg)")
        gef_print("   * L (if code seg)    : 64-bit code segment flag (0:32bitSeg, 1:64bitSeg)")
        gef_print("   * L (if data seg)    : Reserved (0)")
        gef_print("   * AVL                : Used by system software")
        gef_print(" * Access bytes")
        gef_print("   * P                  : Segment present flag (0:SegmentNotInMemory, 1:SegmentInMemory)")
        gef_print("   * DPL                : Descriptor privilege level (0:Ring0, 3:Ring3)")
        gef_print("   * S                  : Descriptor type flag (0:SystemSegment, 1:Code/DataSegment)")
        gef_print("   * Type bytes (if S=1)")
        gef_print("     * E                : Executable bit (0:Unexecutable/DataSegment, 1:Executable/CodeSegment)")
        gef_print("     * DC (if code seg) : Conforming bit (0:NoConforming, 1:Conforming)")
        gef_print("     * DC (if data seg) : Direction bit (0:ExpandUp, 1:ExpandDown)")
        gef_print("     * RW (if code seg) : Read/Exec bit (0:ExecOnly, 1:Read/Exec)")
        gef_print("     * RW (if data seg) : Read/Write bit (0:ReadOnly, 1:Read/Write)")
        gef_print("     * AC               : Access bit (0:NotAccessed, 1:Accessed)")
        gef_print(titlify("legend (GDT/LDT entry for S=0, not call gate)"))
        gef_print("                                          <---Type bytes--->")
        gef_print(" 31            23 22       19       15 14  12   11          7            0bit")
        gef_print("-------------------------------------------------------------------------- 16byte")
        gef_print("|                             ZERO1 (only x64)                           |")
        gef_print("-------------------------------------------------------------------------- 12byte")
        gef_print("|                          BASE3 47:32 (only x64)                        |")
        gef_print("-------------------------------------------------------------------------- 8byte")
        gef_print("|             |  |        |        |  |   |    |           |             |")
        gef_print("| BASE2 31:24 |G | ZERO0  | LIMIT1 |P |DPL|S(0)|   type    | BASE1 23:16 |")
        gef_print("|             |  |        | 19:16  |  |   |    |           |             |")
        gef_print("-------------------------------------------------------------------------- 4byte")
        gef_print("|            BASE0 15:0            |             LIMIT0 15:0             |")
        gef_print("-------------------------------------------------------------------------- 0byte")
        gef_print(" * LIMIT (if TSS Entry) : __KERNEL_TSS_LIMIT")
        gef_print(" * LIMIT (if LDT Entry) : (LDT entries * 8) - 1")
        gef_print(" * Access bytes")
        gef_print("   * Type bytes (if S=0)  16bit/32bit          / 64bit")
        gef_print("     * 0000             : Reserved             / Reserved")
        gef_print("     * 0001             : Available 16bit TSS  / Reserved")
        gef_print("     * 0010             : LDT                  / LDT")
        gef_print("     * 0011             : Busy 16bit TSS       / Reserved")
        gef_print("     * 0100             : 16bit call gate      / Reserved")
        gef_print("     * 0101             : 16/32bit task gate   / Reserved")
        gef_print("     * 0110             : 16bit interrupt gate / Reserved")
        gef_print("     * 0111             : 16bit trap gate      / Reserved")
        gef_print("     * 1000             : Reserved             / Reserved")
        gef_print("     * 1001             : Available 32bit TSS  / 64bit TSS")
        gef_print("     * 1010             : Reserved             / Reserved")
        gef_print("     * 1011             : Busy 32bit TSS       / Busy 64bit TSS")
        gef_print("     * 1100             : 32bit call gate      / 64bit call gate")
        gef_print("     * 1101             : Reserved             / Reserved")
        gef_print("     * 1110             : 32bit interrupt gate / 64bit interrupt gate")
        gef_print("     * 1111             : 32bit trap gate      / 64bit trap gate")
        gef_print(titlify("legend (GDT/LDT entry for S=0, call gate)"))
        gef_print("                                          <---Type bytes--->")
        gef_print(" 31                        19       15 14  12   11          7      4     0bit")
        gef_print("-------------------------------------------------------------------------- 16byte")
        gef_print("|                              ZERO (only x64)                           |")
        gef_print("-------------------------------------------------------------------------- 12byte")
        gef_print("|                   OffsetInSegment2 63:32 (only x64)                    |")
        gef_print("-------------------------------------------------------------------------- 8byte")
        gef_print("|                                  |  |   |    |           |      |      |")
        gef_print("|      OffsetInSegment1 31:16      |P |DPL|S(0)|   type    |0 0 0 |Param |")
        gef_print("|                                  |  |   |    | (1 1 0 0) |      |Count |")
        gef_print("-------------------------------------------------------------------------- 4byte")
        gef_print("|       SegmentSelector 15:0       |        OffsetInSegment0 15:0        |")
        gef_print("-------------------------------------------------------------------------- 0byte")
        return

    @parse_args
    @exclude_specific_gdb_mode(mode=("wine",))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "x86_16"))
    def do_invoke(self, args):
        if not args.quiet:
            self.print_seg_info()

        if is_qemu_system() or is_vmware():
            if not args.only_ldt:
                self.print_gdt_real()
            if not args.only_gdt:
                self.print_ldt_real()
        else:
            self.print_gdt_example()

        if args.verbose:
            self.print_gdt_entry_legend()
        else:
            if not args.quiet:
                info("for flags description, use `-v`")
        return


@register_command
class IdtInfoCommand(GenericCommand):
    """Print IDT entries. If user-land, show sample entries."""
    _cmdline_ = "idtinfo"
    _category_ = "04-a. Register - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    parser.add_argument("-v", "--verbose", action="store_true", help="also display bit information of idt entries.")
    _syntax_ = parser.format_help()

    # arch/x86/include/asm/trapnr.h
    INTERRUPT_DESCRIPTION = {
        0: "#DE: Divide-by-zero",
        1: "#DB: Debug",
        2: "#NMI: Non-maskable Interrupt",
        3: "#BP: Breakpoint",
        4: "#OF: Overflow" ,
        5: "#BR: BOUND Range Exceeded",
        6: "#UD: Invalid Opcode",
        7: "#NM: Device Not Available",
        8: "#DF: Double Fault",
        9: "#OLD_MF: Coprocessor Segment Overrun",
        10: "#TS: Invalid TSS",
        11: "#NP: Segment Not Present",
        12: "#SS: Stack Segment Fault",
        13: "#GP: General Protection Fault",
        14: "#PF: Page Fault",
        15: "#SPRIOUS: Sprious Interrupt",
        16: "#MF: x87 Floating-Point Exception",
        17: "#AC: Alignment Check",
        18: "#MC: Machine-Check",
        19: "#XF: SIMD Floating-Point Exception",
        20: "#VE: Virtualization Exception",
        21: "#CP: Control Protection Exception",
        29: "#VC: VMM Communication Exception",
        32: "#IRET: IRET Exception",
    }

    @staticmethod
    def idt_unpack(val):
        _idt = {}
        _idt["value"] = val

        _idt["offset"] = val & 0xffff
        _idt["offset"] = _idt["offset"] | ((val >> 32) & (0xffff0000))
        _idt["offset"] = ((val >> 32) & (0xffffffff00000000)) | _idt["offset"]
        _idt["segment"] = (val >> 16) & 0xffff
        _idt["ist"] = (val >> 32) & 0b111
        _idt["gate_type"] = (val >> 40) & (0b1111)
        _idt["dpl"] = (val >> 45) & (0b11)
        _idt["present"] = (val >> 47) & (0b1)

        Idt = collections.namedtuple("Idt", _idt.keys())
        return Idt(*_idt.values())

    @staticmethod
    def idtval2str(value):
        val_width = current_arch.ptrsize * 4 + 2
        ofs_width = current_arch.ptrsize * 2 + 2

        idt = IdtInfoCommand.idt_unpack(value)
        if idt.present == 0:
            return "(none)"

        out = ""
        out += "{:#0{:d}x} ".format(idt.value, val_width)
        out += "{:#03x} ".format(idt.gate_type)
        out += "{:#03x} ".format(idt.ist)
        out += "{:#03x} ".format(idt.dpl)
        out += "{:#03x} ".format(idt.present)
        out += "{:#06x}:{:#0{:d}x}".format(idt.segment, idt.offset, ofs_width)
        return out

    @staticmethod
    def idtval2str_legend():
        val_width = current_arch.ptrsize * 4 + 2
        ofs_width = current_arch.ptrsize * 2 + 2
        fmt = "{:3s} {:36s} {:{:d}s} {:3s} {:3s} {:3s} {:3s} {:6s}:{:{:d}s}"
        return fmt.format("#", "name", "value", val_width, "typ", "ist", "dpl", "p", "segm", "offset", ofs_width)

    def print_idt_example(self):
        # print title
        if is_x86_64() or is_emulated32():
            gef_print(titlify("IDT Entry (x64 sample)"))
        else:
            gef_print(titlify("IDT Entry (x86 sample)"))

        # print legend
        info("*** This is an {:s} ***".format(Color.boldify("EXAMPLE")))
        gef_print(Color.colorify(self.idtval2str_legend(), Config.get_gef_setting("theme.table_heading")))

        # print entry
        if is_x86_64() or is_emulated32():
            entries = [
                # idx, value
                [0,    0x0000000000ffffffff81608e0000100c30],
                [1,    0x0000000000ffffffff81608e0300100f00],
                [2,    0x0000000000ffffffff81608e02001012f0],
                [3,    0x0000000000ffffffff8160ee0000100f60],
                [4,    0x0000000000ffffffff8160ee0000100c60],
                [5,    0x0000000000ffffffff81608e0000100c90],
                [6,    0x0000000000ffffffff81608e0000100cc0],
                [7,    0x0000000000ffffffff81608e0000100cf0],
                [8,    0x0000000000ffffffff81608e0100100d20],
                [9,    0x0000000000ffffffff81608e0000100d50],
                [10,   0x0000000000ffffffff81608e0000100d80],
                [11,   0x0000000000ffffffff81608e0000100db0],
                [12,   0x0000000000ffffffff81608e0000100fb0],
                [13,   0x0000000000ffffffff81608e0000100fe0],
                [14,   0x0000000000ffffffff81608e0000101010],
                [15,   0x0000000000ffffffff81608e0000100de0],
                [16,   0x0000000000ffffffff81608e0000100e10],
                [17,   0x0000000000ffffffff81608e0000100e40],
                [18,   0x0000000000ffffffff81608e0400101090],
                [19,   0x0000000000ffffffff81608e0000100e70],
                [20,   0x0000000000ffffffff81c98e000010f0b4],
                [21,   0x0000000000ffffffff81c98e000010f0bd],
                [29,   0x0000000000ffffffff81c98e000010f105],
                [32,   0x0000000000ffffffff81608e0000100b90],
            ]
        else:
            entries = [
                # idx, value
                [0,    0x00c3788e0000605974],
                [1,    0x00c3788e0000605c4c],
                [2,    0x00c3788e0000605c5c],
                [3,    0x00c378ee0000605ef8],
                [4,    0x00c378ee00006058f4],
                [5,    0x00c3788e0000605904],
                [6,    0x00c3788e0000605914],
                [7,    0x00c3788e00006058e0],
                [8,    0x000000850000f80000],
                [9,    0x00c3788e0000605924],
                [10,   0x00c3788e0000605934],
                [11,   0x00c3788e0000605944],
                [12,   0x00c3788e0000605954],
                [13,   0x00c3788e0000605ffc],
                [14,   0x00c3788e00006059a4],
                [15,   0x00c3788e0000605994],
                [16,   0x00c3788e00006058c0],
                [17,   0x00c3788e0000605964],
                [18,   0x00c3788e0000605984],
                [19,   0x00c3788e00006058d0],
                [20,   0x00c3958e00006030bc],
                [21,   0x00c3958e00006030c5],
                [29,   0x00c3958e000060310d],
                [32,   0x00c3788e0000604b90],
            ]

        for i, value in entries:
            if value != 0:
                int_name = self.INTERRUPT_DESCRIPTION.get(i, "User defined Interrupt {:#x}".format(i))
                gef_print("{:<3d} {:36s} {:s}".format(i, int_name, self.idtval2str(value)))
        return

    def print_idt_real(self):
        # parse real value
        if is_qemu_system():
            res = gdb.execute("monitor info registers", to_string=True)
            idtr = re.search(r"IDT\s*=\s*(\S+) (\S+)", res)
            base, limit = [int(idtr.group(i), 16) for i in range(1, 3)]
        elif is_vmware():
            res = gdb.execute("monitor r idtr", to_string=True)
            r = re.search(r"idtr base=(\S+) limit=(\S+)", res)
            base, limit = int(r.group(1), 16), int(r.group(2), 16)

        # print title
        gef_print(titlify("IDT Entry"))

        # print legend
        gef_print(Color.colorify(self.idtval2str_legend(), Config.get_gef_setting("theme.table_heading")))

        # check initialized or not
        if (base == 0x0 and limit == 0xffff) or limit == 0x0:
            err("IDT is uninitialized")
            return

        idtinfo = slice_unpack(read_memory(base, limit + 1), max(current_arch.ptrsize * 2, 4))

        # print entry
        for i, b in enumerate(idtinfo):
            int_name = self.INTERRUPT_DESCRIPTION.get(i, "User defined Interrupt {:#x}".format(i))
            valstr = self.idtval2str(b)
            sym = Symbol.get_symbol_string(self.idt_unpack(b).offset, nosymbol_string=" <NO_SYMBOL>")
            gef_print("{:<3d} {:36s} {:s}{:s}".format(i, int_name, valstr, sym))
        return

    def print_idt_entry_legend(self):
        gef_print(titlify("legend (Normal IDT entry)"))
        gef_print(" 31                                 15  14    13  12     8       3     0bit")
        gef_print("------------------------------------------------------------------------")
        gef_print("|                              RESERVED                                | 12byte")
        gef_print("------------------------------------------------------------------------")
        gef_print("|                            OFFSET2 63:32                             | 8byte")
        gef_print("------------------------------------------------------------------------")
        gef_print("|         OFFSET1 31:16            | P | DPL | 0 | Type | 00000 | IST  | 4byte")
        gef_print("------------------------------------------------------------------------")
        gef_print("|         Segment Selector         |           OFFSET0 15:0            | 0byte")
        gef_print("------------------------------------------------------------------------")
        gef_print(" * segment selector : Segment selector for destination code segment")
        gef_print(" * offset           : Offset to handler procedure entry point")
        gef_print(" * ist              : Interrupt stack table")
        gef_print(" * type             : One of following")
        gef_print("                        0x5: Task gate")
        gef_print("                        0xC: Call gate")
        gef_print("                        0xE: 32/64-bit interrupt gate")
        gef_print("                        0xF: 32/64-bit trap gate")
        gef_print(" * dpl              : Descriptor privilege level")
        gef_print(" * p                : Segment present flag")
        return

    @parse_args
    @exclude_specific_gdb_mode(mode=("wine",))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "x86_16"))
    def do_invoke(self, args):
        if is_qemu_system() or is_vmware():
            self.print_idt_real()
        else:
            self.print_idt_example()

        if args.verbose:
            self.print_idt_entry_legend()
        else:
            if not args.quiet:
                info("for flags description, use `-v`")
        return


@register_command
class MemoryCompareCommand(GenericCommand):
    """Compare the memory contents of two locations."""
    _cmdline_ = "memcmp"
    _category_ = "03-b. Memory - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys1", action="store_true", help="treat LOCATION1 as a physical address.")
    parser.add_argument("location1", metavar="LOCATION1", type=AddressUtil.parse_address,
                        help="first address for comparison.")
    parser.add_argument("--phys2", action="store_true", help="treat LOCATION2 as a physical address.")
    parser.add_argument("location2", metavar="LOCATION2", type=AddressUtil.parse_address,
                        help="second address for comparison.")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address, help="the size for comparison.")
    parser.add_argument("-f", "--full", action="store_true", help="display the same line without omitting.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def memcmp(self, from1_phys, from1, from2_phys, from2, size):
        try:
            if from1_phys:
                from1data = read_physmem(from1, size)
            else:
                from1data = read_memory(from1, size)
        except (gdb.MemoryError, ValueError, OverflowError):
            err("Read error {:#x}".format(from1))
            return

        try:
            if from2_phys:
                from2data = read_physmem(from2, size)
            else:
                from2data = read_memory(from2, size)
        except (gdb.MemoryError, ValueError, OverflowError):
            err("Read error {:#x}".format(from2))
            return

        diff_found = False
        asterisk = True
        for pos in range(0, size, 16):
            f1_bin = from1data[pos : pos + 16]
            f2_bin = from2data[pos : pos + 16]
            if not self.full:
                if f1_bin == f2_bin:
                    if asterisk is False:
                        self.out.append("*")
                        asterisk = True
                    continue

            addr1 = from1 + pos
            addr2 = from2 + pos

            diff_found = True
            asterisk = False
            f1_hex = []
            f2_hex = []
            f1_ascii = []
            f2_ascii = []
            for i in range(min(len(f1_bin), 16)):
                if f1_bin[i] == f2_bin[i]:
                    color_func = lambda x: x
                else:
                    color_func = Color.boldify
                f1_hex.append(color_func("{:02x}".format(f1_bin[i])))
                f2_hex.append(color_func("{:02x}".format(f2_bin[i])))
                f1_ascii.append(color_func(chr(f1_bin[i]) if 0x20 <= f1_bin[i] < 0x7f else "."))
                f2_ascii.append(color_func(chr(f2_bin[i]) if 0x20 <= f2_bin[i] < 0x7f else "."))
            f1_hex_s = " ".join(f1_hex) + " " * ((16 - len(f1_hex)) * 3)
            f2_hex_s = " ".join(f2_hex) + " " * ((16 - len(f2_hex)) * 3)
            f1_ascii_s = "".join(f1_ascii) + " " * (16 - len(f1_ascii))
            f2_ascii_s = "".join(f2_ascii) + " " * (16 - len(f2_ascii))
            fmt = "{:#018x}: {:s} | {:s} | {:#018x}: {:s} | {:s} |"
            self.out.append(fmt.format(addr1, f1_hex_s, f1_ascii_s, addr2, f2_hex_s, f2_ascii_s))

        if diff_found is False:
            info("Not found diff")
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.phys1 or args.phys2:
            if not is_qemu_system():
                err("Unsupported `--phys` option in this gdb mode")
                return

        if args.size == 0:
            info("The size is zero, maybe wrong.")

        self.full = args.full

        self.out = []
        self.memcmp(args.phys1, args.location1, args.phys2, args.location2, args.size)
        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class MemorySetCommand(GenericCommand):
    """Set the value to the memory range."""
    _cmdline_ = "memset"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true", help="treat TO_ADDRESS as a physical address.")
    parser.add_argument("to_addr", metavar="TO_ADDRESS", type=AddressUtil.parse_address, help="destination of memset.")
    parser.add_argument("value", metavar="VALUE", type=AddressUtil.parse_address, help="the value to write.")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address, help="the size for memset.")
    _syntax_ = parser.format_help()

    _note_ = "If you want to specify a large value for `VALUE`, use the `patch string` command."

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def memset(self, to_phys, to_addr, value, size):
        data = bytes([value]) * size
        try:
            if to_phys:
                before = read_physmem(to_addr, size)
                written = write_physmem(to_addr, data)
            else:
                before = read_memory(to_addr, size)
                written = write_memory(to_addr, data)
        except (gdb.MemoryError, ValueError, OverflowError):
            err("Write error {:#x}".format(to_addr))
            return

        info("Write count: {:#x}".format(written))

        history_info = {"addr": to_addr, "before_data": before, "after_data": data, "physmode": to_phys}
        PatchCommand.patch_insert(history_info)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.phys:
            if not is_qemu_system():
                err("Unsupported `--phys` option in this gdb mode")
                return

        if args.size == 0:
            info("The size is zero, maybe wrong.")

        if args.value < 0 or 256 <= args.value:
            err("Wrong value (it must be 0x00-0xff)")
            return

        self.memset(args.phys, args.to_addr, args.value, args.size)
        return


@register_command
class MemoryCopyCommand(GenericCommand):
    """Copy the contents of one memory to another."""
    _cmdline_ = "memcpy"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys1", action="store_true", help="treat TO_ADDRESS as a physical address.")
    parser.add_argument("to_addr", metavar="TO_ADDRESS", type=AddressUtil.parse_address, help="destination of memcpy.")
    parser.add_argument("--phys2", action="store_true", help="treat FROM_ADDRESS as a physical address.")
    parser.add_argument("from_addr", metavar="FROM_ADDRESS", type=AddressUtil.parse_address, help="source of memcpy.")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address, help="the size for memcpy.")
    _syntax_ = parser.format_help()

    _note_ = "memcpy dst src 8\n"
    _note_ += "                                 <--size-->\n"
    _note_ += "            dst                   src\n"
    _note_ += "  Before: [ AAAAAAAA | BBBBBBBB | CCCCCCCC ]\n"
    _note_ += "  After : [ CCCCCCCC | BBBBBBBB | CCCCCCCC ]\n"
    _note_ += "\n"
    _note_ += "memswap dst src 8\n"
    _note_ += "                                 <--size-->\n"
    _note_ += "            dst                   src\n"
    _note_ += "  Before: [ AAAAAAAA | BBBBBBBB | CCCCCCCC ]\n"
    _note_ += "  After : [ CCCCCCCC | BBBBBBBB | AAAAAAAA ]\n"
    _note_ += "\n"
    _note_ += "meminsert dst src 16 8\n"
    _note_ += "           <-------size1-------> <--size2->\n"
    _note_ += "            dst                   src\n"
    _note_ += "  Before: [ AAAAAAAA | BBBBBBBB | CCCCCCCC ]\n"
    _note_ += "  After : [ CCCCCCCC | AAAAAAAA | BBBBBBBB ]\n"

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def memcpy(self, to_phys, to_addr, from_phys, from_addr, size):
        try:
            if from_phys:
                data = read_physmem(from_addr, size)
            else:
                data = read_memory(from_addr, size)
        except (gdb.MemoryError, ValueError, OverflowError):
            err("Read error {:#x}".format(from_addr))
            return

        info("Read count: {:#x}".format(len(data)))

        try:
            if to_phys:
                before = read_physmem(to_addr, len(data))
                written = write_physmem(to_addr, data)
            else:
                before = read_memory(to_addr, len(data))
                written = write_memory(to_addr, data)
        except (gdb.MemoryError, ValueError, OverflowError):
            err("Write error {:#x}".format(to_addr))
            return

        info("Write count: {:#x}".format(written))

        history_info = {"addr": to_addr, "before_data": before, "after_data": data, "physmode": to_phys}
        PatchCommand.patch_insert(history_info)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.phys1 or args.phys2:
            if not is_qemu_system():
                err("Unsupported `--phys` option in this gdb mode")
                return

        if args.size == 0:
            info("The size is zero, maybe wrong.")

        self.memcpy(args.phys1, args.to_addr, args.phys2, args.from_addr, args.size)
        return


@register_command
class MemorySwapCommand(GenericCommand):
    """Swap the contents of one memory to another."""
    _cmdline_ = "memswap"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys1", action="store_true", help="treat SWAP_ADDRESS1 as a physical address.")
    parser.add_argument("swap_addr1", metavar="SWAP_ADDRESS1", type=AddressUtil.parse_address,
                        help="swap target address.")
    parser.add_argument("--phys2", action="store_true", help="treat SWAP_ADDRESS2 as a physical address.")
    parser.add_argument("swap_addr2", metavar="SWAP_ADDRESS2", type=AddressUtil.parse_address,
                        help="another swap target address.")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address, help="the size for memory swap.")
    _syntax_ = parser.format_help()

    _note_ = MemoryCopyCommand._note_

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def memswap(self, phys1, addr1, phys2, addr2, size):
        try:
            if phys1:
                data1 = read_physmem(addr1, size)
            else:
                data1 = read_memory(addr1, size)
        except (gdb.MemoryError, ValueError, OverflowError):
            err("Read error {:#x}".format(addr1))
            return

        info("Read count: {:#x}".format(len(data1)))

        try:
            if phys2:
                data2 = read_physmem(addr2, size)
            else:
                data2 = read_memory(addr2, size)
        except (gdb.MemoryError, ValueError, OverflowError):
            err("Read error {:#x}".format(addr2))
            return

        info("Read count: {:#x}".format(len(data2)))

        try:
            if phys2:
                written2 = write_physmem(addr2, data1)
            else:
                written2 = write_memory(addr2, data1)
        except Exception:
            err("Write error {:#x}".format(addr2))
            return

        info("Write count: {:#x}".format(written2))

        try:
            if phys1:
                written1 = write_physmem(addr1, data2)
            else:
                written1 = write_memory(addr1, data2)
        except Exception:
            err("Write error {:#x}".format(addr1))
            return

        info("Write count: {:#x}".format(written1))

        history_info = {"addr": addr2, "before_data": data2, "after_data": data1, "physmode": phys2}
        PatchCommand.patch_insert(history_info)
        history_info = {"addr": addr1, "before_data": data1, "after_data": data2, "physmode": phys1}
        PatchCommand.patch_insert(history_info)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.phys1 or args.phys2:
            if not is_qemu_system():
                err("Unsupported `--phys` option in this gdb mode")
                return

        if args.size == 0:
            info("The size is zero, maybe wrong.")

        self.memswap(args.phys1, args.swap_addr1, args.phys2, args.swap_addr2, args.size)
        return


@register_command
class MemoryInsertCommand(GenericCommand):
    """Insert the contents of one memory to another."""
    _cmdline_ = "meminsert"
    _category_ = "03-c. Memory - Patch"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys1", action="store_true", help="treat TO_ADDRESS as a physical address.")
    parser.add_argument("to_addr", metavar="TO_ADDRESS", type=AddressUtil.parse_address,
                        help="destination of meminsert.")
    parser.add_argument("--phys2", action="store_true", help="treat FROM_ADDRESS as a physical address.")
    parser.add_argument("from_addr", metavar="FROM_ADDRESS", type=AddressUtil.parse_address,
                        help="source of meminsert.")
    parser.add_argument("size1", metavar="SIZE1", type=AddressUtil.parse_address,
                        help="the pushed back size for meminsert.")
    parser.add_argument("size2", metavar="SIZE2", type=AddressUtil.parse_address,
                        help="the inserted(slided) size for meminsert.")
    _syntax_ = parser.format_help()

    _note_ = MemoryCopyCommand._note_

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def meminsert(self, phys1, addr1, size1, phys2, addr2, size2):
        try:
            if phys1:
                before = read_physmem(addr1, size1 + size2)
                data1 = before[:size1]
            else:
                before = read_memory(addr1, size1 + size2)
                data1 = before[:size1]
        except (gdb.MemoryError, ValueError, OverflowError):
            err("Read error {:#x}".format(addr1))
            return

        info("Read count: {:#x}".format(len(data1)))

        try:
            if phys2:
                data2 = read_physmem(addr2, size2)
            else:
                data2 = read_memory(addr2, size2)
        except (gdb.MemoryError, ValueError, OverflowError):
            err("Read error {:#x}".format(addr2))
            return

        info("Read count: {:#x}".format(len(data2)))

        to_write_data = data2 + data1

        try:
            if phys1:
                written = write_physmem(addr1, to_write_data)
            else:
                written = write_memory(addr1, to_write_data)
        except Exception:
            err("Write error {:#x}".format(addr1))
            return

        info("Write count: {:#x}".format(written))

        history_info = {"addr": addr1, "before_data": before, "after_data": to_write_data, "physmode": phys1}
        PatchCommand.patch_insert(history_info)
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.phys1 or args.phys2:
            if not is_qemu_system():
                err("Unsupported `--phys` option in this gdb mode")
                return

        if args.size2 == 0:
            info("The size2 is zero, maybe wrong.")

        self.meminsert(args.phys1, args.to_addr, args.size1, args.phys2, args.from_addr, args.size2)
        return


@register_command
class HashMemoryCommand(GenericCommand):
    """Calculate memory hash and CRC."""
    _cmdline_ = "hash-memory"
    _category_ = "03-d. Memory - Calculation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", type=AddressUtil.parse_address,
                        help="start address for hash calculation.")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address,
                        help="the size for hash calculation.")
    parser.add_argument("-v", "--verbose", action="store_true", help="also print crc.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def calc_hash(self, type, h, start_address, end_address):
        step = 0x400 * gef_getpagesize()
        if is_qemu_system():
            step = gef_getpagesize()

        for chunk_addr in range(start_address, end_address, step):
            if chunk_addr + step > end_address:
                chunk_size = end_address - chunk_addr
            else:
                chunk_size = step

            try:
                mem = read_memory(chunk_addr, chunk_size)
            except gdb.MemoryError:
                err("Memory read error")
                return False

            try:
                if type == 1:
                    h.update(mem)
                elif type == 2:
                    h.process(mem)
            except ValueError:
                return None

            del mem
        if type == 1:
            return h.hexdigest()
        elif type == 2:
            return h.finalhex()
        return None

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        gef_print("Address: {:#x}".format(args.location))
        gef_print("Size: {:#x}".format(args.size))

        # common
        hash_dic = {
            "md5": hashlib.md5(),
            "sha1": hashlib.sha1(),
            "sha224": hashlib.sha224(),
            "sha256": hashlib.sha256(),
            "sha384": hashlib.sha384(),
            "sha512": hashlib.sha512(),
            "sha3-224": hashlib.sha3_224(),
            "sha3-256": hashlib.sha3_256(),
            "sha3-384": hashlib.sha3_384(),
            "sha3-512": hashlib.sha3_512(),
            "blake2s": hashlib.blake2s(),
            "blake2b": hashlib.blake2b(),
        }
        for hname, hfunc in hash_dic.items():
            h = self.calc_hash(1, hfunc, args.location, args.location + args.size)
            if h is False:
                return
            if h is None:
                continue
            gef_print("{:20s}: {:s} ({:d}-bit)".format(hname, h, len(h) * 4))

        if not args.verbose:
            return

        # crc
        try:
            crccheck = __import__("crccheck")
        except ImportError as err:
            msg = "Missing `crccheck` package for Python, install with: `pip install crccheck`."
            raise ImportWarning(msg) from err

        for name in crccheck.crc.__dict__:
            if not name.startswith("Crc"):
                continue
            if name.startswith("Crccheck"):
                continue
            try:
                hfunc = getattr(crccheck.crc, name)()
            except TypeError:
                continue
            h = self.calc_hash(2, hfunc, args.location, args.location + args.size)
            if h is False:
                return
            if h is None:
                continue
            gef_print("{:20s}: {:s} ({:d}-bit)".format(name, h, len(h) * 4))
        return


@register_command
class IsMemoryZeroCommand(GenericCommand):
    """Check if all the memory in the specified range is 0x00, 0xff."""
    _cmdline_ = "is-mem-zero"
    _category_ = "03-d. Memory - Calculation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true", help="treat ADDRESS as a physical address.")
    parser.add_argument("addr", metavar="ADDRESS", type=AddressUtil.parse_address, help="target address for checking.")
    parser.add_argument("size", metavar="SIZE", type=AddressUtil.parse_address, help="the size for checking.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def memcheck(self, phys_mode, addr, size):
        start = addr
        end = addr + size
        is_zero = True
        is_ff = True
        current = addr
        while current < end:
            read_size = min(end - current, 0x1000)
            try:
                if phys_mode:
                    data = read_physmem(current, read_size)
                else:
                    data = read_memory(current, read_size)
            except (gdb.MemoryError, ValueError, OverflowError):
                err("Read error {:#x}".format(addr))
                return
            if data == b"\0" * len(data):
                is_ff = False
            elif data == b"\xff" * len(data):
                is_zero = False
            else:
                is_zero = False
                is_ff = False
            if is_zero is False and is_ff is False:
                end = current + read_size
                break
            current += 0x1000

        if is_zero:
            info("{:#x} - {:#x} is {:s}".format(start, end, Color.colorify("All 0x00", "bold yellow")))
        elif is_ff:
            info("{:#x} - {:#x} is {:s}".format(start, end, Color.colorify("All 0xFF", "bold yellow")))
        else:
            info("{:#x} - {:#x} is {:s}".format(start, end, Color.colorify("NON-ZERO", "bold red")))
        info("If data is non-zero, it will be fast return.")
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.phys:
            if not is_qemu_system():
                err("Unsupported `--phys` option in this gdb mode")
                return

        if args.size == 0:
            info("The size is zero, maybe wrong.")

        self.memcheck(args.phys, args.addr, args.size)
        return


@register_command
class SequenceLengthCommand(GenericCommand):
    """Detect consecutive lengths of the same sequence."""
    _cmdline_ = "seq-length"
    _category_ = "03-d. Memory - Calculation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--phys", action="store_true", help="treat ADDRESS as a physical address.")
    parser.add_argument("addr", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="target address for checking.")
    parser.add_argument("unit", metavar="UNIT", nargs="?", type=AddressUtil.parse_address, default=1,
                        help="the size for a target value (default: %(default)s).")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def check(self, phys_mode, addr, unit):
        target = None
        data = b""
        count = 0
        current = addr
        while True:
            # calc read_size
            if current & 0xfff:
                read_size = AddressUtil.align_address_to_size(current, 0x1000) - current
            else:
                read_size = 0x1000
            while read_size < unit:
                read_size += 0x1000
            # read
            try:
                if phys_mode:
                    data += read_physmem(current, read_size)
                else:
                    data += read_memory(current, read_size)
            except (gdb.MemoryError, ValueError, OverflowError):
                err("Read error {:#x}".format(addr))
                return None
            # init target
            if target is None:
                target = data[:unit]
            # count
            for elem in slicer(data, unit):
                if elem == target:
                    # Equal in length and content
                    count += 1
                elif len(elem) == len(target):
                    # The length is sufficient, but the content is different.
                    return count, target
            # Consider the case where the length of the final element is insufficient
            if len(elem) != len(target):
                data = elem
            else:
                data = b""
            # goto next
            current += read_size
        return None

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.phys:
            if not is_qemu_system():
                err("Unsupported `--phys` option in this gdb mode")
                return

        if args.unit >= 0x100000:
            err("Too large unit size")
            return

        colored_addr = str(ProcessMap.lookup_address(args.addr))
        colored_unit = Color.boldify("{:#x}".format(args.unit))
        info("Check from {:s} in units of {:s} bytes".format(colored_addr, colored_unit))

        ret = self.check(args.phys, args.addr, args.unit)
        if ret is None:
            return

        count, target = ret
        size = args.unit * count
        end = args.addr + size
        if len(target) > 0x100:
            target = target[:0x100] + b"..."
        colored_count = Color.boldify("{:#x}".format(count))
        colored_size = Color.boldify("{:#x}".format(size))
        colored_end = str(ProcessMap.lookup_address(end))
        gef_print("{:s} - {:s} is same value".format(colored_addr, colored_end))
        gef_print("{} is found {:s} times, {:s} bytes".format(target, colored_count, colored_size))
        return


@register_command
class MultiLineCommand(GenericCommand):
    """Execute multiple GDB commands in sequence."""
    _cmdline_ = "multi-line"
    _category_ = "01-c. Debugging Support - Basic Command Extension"
    _aliases_ = ["ml"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("cmd", metavar="GDB_CMD;", nargs="+", help="semicolon-separated gdb command.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_COMMAND)
        return

    def do_command(self, commands):
        if commands == []:
            return True

        # make comnand string
        cmd = ""
        for c in commands:
            if "\\" in c or " " in c:
                cmd += " " + repr(c)
            else:
                cmd += " " + c
        cmd = cmd.strip()

        # blank command, so skip
        if cmd.replace(" ", "") == "":
            return True

        gef_print(titlify(cmd))
        try:
            gdb.execute(cmd)
        except gdb.error as e:
            gef_print(e)
            return False # fail
        return True

    # Need not @parse_args because argparse can't stop interpreting options for user specified command.
    def do_invoke(self, argv):
        if len(argv) == 1 and argv[0] == "-h":
            self.usage()
            return

        commands = []
        for arg in argv:
            if arg.endswith(";"):
                commands.append(arg.rstrip(";").lstrip(";"))
                if self.do_command(commands) is False:
                    break
                commands = []
            elif arg.startswith(";"):
                if self.do_command(commands) is False:
                    break
                commands = []
                commands.append(arg.lstrip(";"))
            elif arg == ";":
                if self.do_command(commands) is False:
                    break
                commands = []
            else:
                commands.append(arg)
        else:
            self.do_command(commands)
        return


@register_command
class TimeCommand(GenericCommand):
    """Measure the time of the GDB command."""
    _cmdline_ = "time"
    _category_ = "01-c. Debugging Support - Basic Command Extension"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("cmd", metavar="GDB_CMD", help="gdb command.")
    parser.add_argument("arg", metavar="ARG", nargs="*", help="arguments of gdb command.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_COMMAND)
        return

    # Need not @parse_args because argparse can't stop interpreting options for user specified command.
    def do_invoke(self, argv):
        if len(argv) == 1 and argv[0] == "-h":
            self.usage()
            return

        start_time_real = time.perf_counter()
        start_time_proc = time.process_time()

        cmd = ""
        for c in argv:
            if "\\" in c or " " in c:
                cmd += " " + repr(c)
            else:
                cmd += " " + c
        cmd = cmd.strip()

        gef_print(titlify(cmd))
        try:
            gdb.execute(cmd)
        except gdb.error:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            gef_print(exc_value)
            return

        end_time_real = time.perf_counter()
        end_time_proc = time.process_time()
        gef_print(titlify("time elapsed"))
        gef_print("Real: {:.3f} s".format(end_time_real - start_time_real))
        gef_print("CPU:  {:.3f} s".format(end_time_proc - start_time_proc))
        return


@register_command
class SaveOutputCommand(GenericCommand):
    """Save the command outputs."""
    _cmdline_ = "saveo"
    _category_ = "09-g. Misc - Diff"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("cmd", metavar="GDB_CMD", help="gdb command.")
    parser.add_argument("arg", metavar="ARG", nargs="*", help="arguments of gdb command.")
    _syntax_ = parser.format_help()

    _note_ = "Saving the output of external commands is unsupported (e.g.: pipe, !ls)."

    def __init__(self):
        super().__init__(prefix=False, complete=gdb.COMPLETE_COMMAND)
        return

    # Need not @parse_args because argparse can't stop interpreting options for user specified command.
    def do_invoke(self, argv):
        if len(argv) == 1 and argv[0] == "-h":
            self.usage()
            return

        # get settings
        always_no_pager = Config.get_gef_setting("gef.always_no_pager")

        # parse command
        cmd = ""
        for c in argv:
            if "\\" in c or " " in c:
                cmd += " " + repr(c)
            else:
                cmd += " " + c
        cmd = cmd.strip()
        if not cmd:
            self.usage()
            return

        # do the command
        try:
            Config.set_gef_setting("gef.always_no_pager", True) # change temporarily
            current_output = Color.remove_color(gdb.execute(cmd, to_string=True))
            Config.set_gef_setting("gef.always_no_pager", always_no_pager) # revert settings
        except gdb.error:
            Config.set_gef_setting("gef.always_no_pager", always_no_pager) # revert settings
            exc_type, exc_value, exc_traceback = sys.exc_info()
            gef_print(exc_value)
            return

        # save
        tmp_fd, tmp_path = tempfile.mkstemp(dir=GEF_TEMP_DIR, suffix=".txt", prefix="diff_saved_output_")
        os.fdopen(tmp_fd, "w").write(current_output)
        open(tmp_path[:-4] + ".cmd", "w").write(cmd)
        info("The output is saved to {:s}.(txt|cmd)".format(tmp_path[:-4]))

        # print
        gef_print(current_output, less=not always_no_pager)
        return


@register_command
class DiffOutputCommand(GenericCommand):
    """The base command to diff of the command outputs."""
    _cmdline_ = "diffo"
    _category_ = "09-g. Misc - Diff"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("colordiff")
    subparsers.add_parser("git-diff")
    subparsers.add_parser("list")
    subparsers.add_parser("clear")
    _syntax_ = parser.format_help()

    def __init__(self, *args, **kwargs):
        prefix = kwargs.get("prefix", True)
        super().__init__(prefix=prefix)
        self.add_setting("colordiff_output_width", 200, "Used as NUM when `colordiff -y -W NUM`")
        return

    def get_saved_files(self):
        saved_files = []
        for cur, _dirs, files in os.walk(GEF_TEMP_DIR):
            for f in files:
                if not f.startswith("diff_saved_output_"):
                    continue
                if not f.endswith(".txt"):
                    continue
                path = os.path.join(cur, f)
                saved_files.append(path)

        return sorted(saved_files, key=lambda x:os.path.getmtime(x[:-4] + ".cmd"))

    @parse_args
    def do_invoke(self, args):
        self.usage()
        return


@register_command
class DiffOutputColordiffCommand(DiffOutputCommand):
    """Diff the two outputs by colordiff."""
    _cmdline_ = "diffo colordiff"
    _category_ = "09-g. Misc - Diff"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("n1", metavar="N", type=int, help="first diff target got from `diffo list`.")
    parser.add_argument("n2", metavar="M", type=int, help="second diff target got from `diffo list`.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0 1   # diff between 0 and 1".format(_cmdline_)

    _note_ = "You can check the available indexes with `diffo list`."

    def __init__(self):
        super().__init__(prefix=False)
        return

    def make_diff(self, path1, path2):
        width = Config.get_gef_setting("diffo.colordiff_output_width")
        cmd = "{:s} -y -W {:d} '{:s}' '{:s}'".format(self.colordiff, width, path1, path2)
        result = subprocess.getoutput(cmd)
        return result

    @parse_args
    def do_invoke(self, args):
        try:
            self.colordiff = GefUtil.which("colordiff")
        except FileNotFoundError as e:
            err("{}".format(e))
            return

        saved_files = self.get_saved_files()
        try:
            f1 = saved_files[args.n1]
            f2 = saved_files[args.n2]
        except IndexError:
            err("Out of index error")
            return

        if not os.path.exists(f1):
            err("{:s} is not found".format(f1))
            return
        if not os.path.exists(f1):
            err("{:s} is not found".format(f2))
            return

        output = self.make_diff(f1, f2)

        if output:
            gef_print(output, less=not args.no_pager)
        else:
            gef_print("No difference")
        return


@register_command
class DiffOutputGitDiffCommand(DiffOutputCommand):
    """Diff the two outputs by git."""
    _cmdline_ = "diffo git-diff"
    _category_ = "09-g. Misc - Diff"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("n1", metavar="N", type=int, help="first diff target got from `diffo list`.")
    parser.add_argument("n2", metavar="M", type=int, help="second diff target got from `diffo list`.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0 1   # diff between 0 and 1".format(_cmdline_)

    _note_ = "You can check the available indexes with `diffo list`."

    def __init__(self):
        super().__init__(prefix=False)
        return

    def make_diff(self, path1, path2):
        cmd = "{:s} diff --color=always '{:s}' '{:s}'".format(self.git, path1, path2)
        result = subprocess.getoutput(cmd)
        return result

    @parse_args
    def do_invoke(self, args):
        try:
            self.git = GefUtil.which("git")
        except FileNotFoundError as e:
            err("{}".format(e))
            return

        saved_files = self.get_saved_files()
        try:
            f1 = saved_files[args.n1]
            f2 = saved_files[args.n2]
        except IndexError:
            err("Out of index error")
            return

        if not os.path.exists(f1):
            err("{:s} is not found".format(f1))
            return
        if not os.path.exists(f1):
            err("{:s} is not found".format(f2))
            return

        output = self.make_diff(f1, f2)

        if output:
            gef_print(output, less=not args.no_pager)
        else:
            gef_print("No difference")
        return


@register_command
class DiffOutputListCommand(DiffOutputCommand):
    """List up saved outputs."""
    _cmdline_ = "diffo list"
    _category_ = "09-g. Misc - Diff"
    _aliases_ = ["diffo ls"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=False)
        return

    @parse_args
    def do_invoke(self, args):
        fmt = "{:<3s}  {:26s}  {:39s}  {:<7s}  {:s}"
        legend = ["#", "mtime", "path", "size", "command"]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        import datetime
        for idx, path in enumerate(self.get_saved_files()):
            data = open(path, "rb").read()
            size = len(data)
            mtime = datetime.datetime.fromtimestamp(os.path.getmtime(path))
            cmd = open(path[:-4] + ".cmd", "rb").read()
            cmd = String.bytes2str(cmd)
            gef_print("{:<3d}  {}  {:s}  {:<7d}  {:s}".format(idx, mtime, path, size, cmd))
        return


@register_command
class DiffOutputClearCommand(DiffOutputCommand):
    """Clear all saved outputs."""
    _cmdline_ = "diffo clear"
    _category_ = "09-g. Misc - Diff"
    _aliases_ = ["diffo del", "diffo rm"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("n", metavar="N", type=int, nargs="*", help="index to be deleted.")
    parser.add_argument("--all", action="store_true", help="delete everything.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=False)
        return

    @parse_args
    def do_invoke(self, args):
        if args.all:
            for path in self.get_saved_files():
                os.unlink(path)
                os.unlink(path[:-4] + ".cmd")
        elif args.n:
            for i, path in enumerate(self.get_saved_files()):
                if i in args.n:
                    os.unlink(path)
                    os.unlink(path[:-4] + ".cmd")
        else:
            self.usage()
            return

        info("Removed")
        return


@register_command
class IiCommand(GenericCommand):
    """Shortcut `x/50i $pc` with opcode bytes."""
    _cmdline_ = "ii"
    _category_ = "01-e. Debugging Support - Assemble"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the dump start address.")
    parser.add_argument("-l", "--length", type=AddressUtil.parse_address, default=50,
                        help="the dump instruction length.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def ii(self, addr, N):
        try:
            res = read_memory(addr, N)
        except gdb.MemoryError:
            err("Memory read error")
            return

        if N >= 50 and res[0:1] * N == res:
            info("all targeted area is {:#04x}".format(res[0]))
            return

        # get instruction size
        try:
            res = gdb.execute("x/{:d}i {:#x}".format(N+1, addr), to_string=True)
        except gdb.MemoryError:
            err("Memory read error")
            return
        addrs = []
        for line in res.splitlines():
            # [x64]
            # "=> 0x55555555aac0:      endbr64"
            # "   0x55555555aac4:      xor    ebp,ebp"
            # [arm]
            # "=> 0x10340 <_start>:    mov.w   r11, #0"
            # "   0x10344 <_start+4>:  mov.w   lr, #0"
            r = re.search("^(?:=>|  ) (0x[0-9a-f]+)", line)
            if r:
                addrs.append(int(r.group(1), 16))
        insn_sizes = [(x, y - x) for x, y in zip(addrs[:-1], addrs[1:])]
        max_insn_width = max(x[1] for x in insn_sizes) * 2

        # print
        for i, line in enumerate(res.splitlines()[:-1]):
            addr, size = insn_sizes[i]
            bytecode = read_memory(addr, size)
            bytecode_hex = "{:{:d}s}".format(bytecode.hex(), max_insn_width)

            line = line.rstrip()
            line = line.expandtabs(8)

            # get position to split
            # [x64]
            # "0x55555555aac0:      endbr64"
            # "0x55555555aac4:      xor    ebp,ebp"
            #                ^
            # [arm]
            # "0x10340 <_start>:    mov.w   r11, #0"
            # "0x10344 <_start+4>:  mov.w   lr, #0"
            #         ^
            # Since it depends on the presence or absence of symbols, it must be calculated line by line each time.
            pos = None
            r = re.search("[: ]", line[3:])
            if r:
                pos = 3 + r.span()[0]

            if pos is None:
                # somethinig is wrong
                gef_print(line)
            else:
                gef_print(line[:pos] + ": " + bytecode_hex + " " + line[pos:])
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.location is None:
            location = current_arch.pc
        else:
            location = args.location

        self.ii(location, args.length)
        return


@register_command
class ConstGrepCommand(GenericCommand):
    """Grep for lines with #define in files under /usr/include."""
    _cmdline_ = "constgrep"
    _category_ = "09-b. Misc - Search"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("pattern", metavar="GREP_PATTERN", help="filter by regex.")
    _syntax_ = parser.format_help()

    _example_ = "constgrep '__NR_*'"

    def read_normalize(self, path):
        try:
            content = open(path, "rb").read()
        except (FileNotFoundError, IsADirectoryError):
            return None
        content = content.replace(b"\\\n", b"GEF_MARKER")
        content = content.replace(b"\t", b" ")
        for i in range(0x80, 0x100):
            content = content.replace(bytes([i]), b"")
        try:
            content = content.decode("UTF-8")
        except UnicodeDecodeError:
            err("decode error: " + path)
            return None
        return content

    @parse_args
    def do_invoke(self, args):
        srcdir = "/usr/include"
        pattern = re.compile(r"^#define\s+\S*" + args.pattern)
        for cur, _dirs, files in os.walk(srcdir):
            for f in files:
                path = os.path.join(cur, f)
                content = self.read_normalize(path)
                if content is None:
                    continue
                for line in content.splitlines():
                    if pattern.search(line):
                        line = line.replace("GEF_MARKER", "\\\n")
                        gef_print("{:s}: {:s}".format(Color.redify(path), line))
        return


@register_command
class SlubDumpCommand(GenericCommand):
    """Dump slub free-list."""
    _cmdline_ = "slub-dump"
    _category_ = "08-e. Qemu-system Cooperation - Linux Allocator"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("cache_name", metavar="SLUB_CACHE_NAME", nargs="*",
                        help="filter by specific slub cache name.")
    parser.add_argument("--cpu", type=int, help="filter by specific cpu.")
    parser.add_argument("--list", action="store_true", help="list up all slub cache names.")
    parser.add_argument("--meta", action="store_true", help="display offset information.")
    parser.add_argument("-s", "--simple", action="store_true", help="skip displaying layout and freelist.")
    parser.add_argument("--hexdump-used", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="hexdump `used chunks` if layout is resolved.")
    parser.add_argument("--hexdump-freed", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="hexdump `unused (freed) chunks` if layout is resolved.")
    parser.add_argument("--telescope-used", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="telescope `used chunks` if layout is resolved.")
    parser.add_argument("--telescope-freed", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="telescope `unused (freed) chunks` if layout is resolved.")
    parser.add_argument("--skip-page2virt", action="store_true",
                        help="used internally in gef, please don't use it.")
    parser.add_argument("--no-xor", action="store_true",
                        help="skip xor to chunk->next when `kmem_cache.random` is falsely detected.")
    parser.add_argument("--offset-random", type=lambda x: int(x, 16),
                        help="specified offsetof(kmem_cache, random) when `kmem_cache.random` is falsely detected.")
    parser.add_argument("--no-byte-swap", action="store_true", default=None,
                        help="skip byteswap to chunk->next. when `kmem_cache.random` is falsely detected.")
    parser.add_argument("--offset-node", type=lambda x: int(x, 16),
                        help="specified offsetof(kmem_cache, node) when `kmem_cache.node` is falsely detected.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", "--partial", action="store_true",
                        help="dump partial pages.")
    parser.add_argument("-vv", "--vverbose", "--node", action="store_true",
                        help="dump partial pages and node pages.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} kmalloc-256             # dump kmalloc-256 from all cpus\n".format(_cmdline_)
    _example_ += "{:s} kmalloc-256 --cpu 1     # dump kmalloc-256 from cpu 1\n".format(_cmdline_)
    _example_ += "{:s} kmalloc-256 --partial   # show partial pages\n".format(_cmdline_)
    _example_ += "{:s} kmalloc-256 --node      # show partial pages and node pages\n".format(_cmdline_)
    _example_ += "{:s} --list                  # list up slub cache names".format(_cmdline_)

    _note_ = "Simplified SLUB structure:\n"
    _note_ += "\n"
    _note_ += "                         +-kmem_cache--+          +-kmem_cache--+   +-kmem_cache--+\n"
    _note_ += "                         | cpu_slab    |---+      | cpu_slab    |   | cpu_slab    |\n"
    _note_ += "                         | flags       |   |      | flags       |   | flags       |\n"
    _note_ += "                         | size        |   |      | size        |   | size        |\n"
    _note_ += "                         | object_size |   |      | object_size |   | object_size |\n"
    _note_ += "                         | offset      |   |      | offset      |   | offset      |\n"
    _note_ += "       +-slab_caches-+   | name        |   |      | name        |   | name        |\n"
    _note_ += " ...<->| list_head   |<->| list_head   |<-------->| list_head   |<->| list_head   |<-> ...\n"
    _note_ += "       +-------------+   | random      |   |      | random      |   | random      |\n"
    _note_ += "                         | node[]      |-+ |      | node[]      |   | node[]      |\n"
    _note_ += "                         +-------------+ | |      +-------------+   +-------------+\n"
    _note_ += "                                         | |\n"
    _note_ += "    +------------------------------------+ |\n"
    _note_ += "    |   +----------------------------------+\n"
    _note_ += "    |   |\n"
    _note_ += "    |   |          +-__per_cpu_offset-+\n"
    _note_ += "    |   +----------| cpu0_offset      |\n"
    _note_ += "    |   |          | cpu1_offset      |\n"
    _note_ += "    |   |          | cpu2_offset      |\n"
    _note_ += "    |   |          | ...              |\n"
    _note_ += "    |   |          +------------------+\n"
    _note_ += "    |   v\n"
    _note_ += "    |  +-kmem_cache_cpu-+  +--------------------------------------------------------------+\n"
    _note_ += "    |  | freelist       |--+                           [active page freelist (slow path)] | [active page freelist (fast path)]\n"
    _note_ += "    |  | page           |---->+-page(active)---+         +-chunk---+  +-chunk---+         |   +-chunk---+  +-chunk---+\n"
    _note_ += "    |  | partial        |--+  | freelist       |----+    | ^       |  | ^       |         |   | ^       |  | ^       |\n"
    _note_ += "    |  +----------------+  |  |                |    |    | |offset |  | |offset |         |   | |offset |  | |offset |\n"
    _note_ += "    |                      |  +----------------+    |    | v       |  | v       |         |   | v       |  | v       |\n"
    _note_ += "    |                      |                        +--->| next    |->| next    |->NULL   +-->| next    |->| next    |->NULL\n"
    _note_ += "    |                      |                             +---------+  +---------+             +---------+  +---------+\n"
    _note_ += "    |                      |\n"
    _note_ += "    |                      |                           [partial page freelist]\n"
    _note_ += "    |                      +->+-page(partial)--+         +-chunk---+  +-chunk---+\n"
    _note_ += "    |                         | freelist       |----+    | ^       |  | ^       |\n"
    _note_ += "    |                         | next           |--+ |    | |offset |  | |offset |\n"
    _note_ += "    |                         +----------------+  | |    | v       |  | v       |\n"
    _note_ += "    |                                             | +--->| next    |->| next    |->NULL\n"
    _note_ += "    |                           +-----------------+      +---------+  +---------+\n"
    _note_ += "    |                           |\n"
    _note_ += "    |                           v                      [partial page freelist]\n"
    _note_ += "    |                         +-page(partial)--+         +-chunk---+  +-chunk---+\n"
    _note_ += "    |                         | freelist       |----+    | ^       |  | ^       |\n"
    _note_ += "    |                         | next           |--+ |    | |offset |  | |offset |\n"
    _note_ += "    |                         +----------------+  | |    | v       |  | v       |\n"
    _note_ += "    |                                             | +--->| next    |->| next    |->NULL\n"
    _note_ += "    |                           +-----------------+      +---------+  +---------+\n"
    _note_ += "    |                           |\n"
    _note_ += "    |                           v\n"
    _note_ += "    |                          ...\n"
    _note_ += "    +->+-kmem_cache_node-+                             [numa node partial page freelist]\n"
    _note_ += "       | partial         |--->+-page(numa-node)+         +-chunk---+  +-chunk---+\n"
    _note_ += "       |                 |    | freelist       |----+    | ^       |  | ^       |\n"
    _note_ += "       +-----------------+    | next           |--+ |    | |offset |  | |offset |\n"
    _note_ += "       | ...             |    +----------------+  | |    | v       |  | v       |\n"
    _note_ += "       |                 |                        | +--->| next    |->| next    |->NULL\n"
    _note_ += "       +-----------------+      +-----------------+      +---------+  +---------+\n"
    _note_ += "                                |\n"
    _note_ += "                                v                      [numa node partial page freelist]\n"
    _note_ += "                              +-page(numa-node)+         +-chunk---+  +-chunk---+\n"
    _note_ += "                              | freelist       |----+    | ^       |  | ^       |\n"
    _note_ += "                              | next           |--+ |    | |offset |  | |offset |\n"
    _note_ += "                              +----------------+  | |    | v       |  | v       |\n"
    _note_ += "                                                  | +--->| next    |->| next    |->NULL\n"
    _note_ += "                                +-----------------+      +---------+  +---------+\n"
    _note_ += "                                |\n"
    _note_ += "                                v\n"
    _note_ += "                               ...\n"
    _note_ += "* If all chunks in certain page are in use, they will not be displayed this command.\n"
    _note_ += "  This because they cannot be reached by parsing from slab_caches.\n"
    _note_ += "  So use `slab-contains` (if you know the address) or `pagewalk-with-hints` (if you'd to know the whole even if it takes time)."

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        return

    def quiet_err(self, msg):
        if not self.args.quiet:
            err(msg)
        return

    def quiet_info(self, msg):
        if not self.args.quiet:
            info(msg)
        return

    """
    struct kmem_cache {
        struct kmem_cache_cpu *cpu_slab;         // In fact, the offset value, not the pointer
        slab_flags_t flags;                      // unsigned int (+ padding 4 byte)
        unsigned long min_partial;
        unsigned int size;
        unsigned int object_size;
        struct reciprocal_value {                //
            u32 m;                               //
            u8 sh1, sh2;                         // (+ padding 2 byte)
        } reciprocal_size;                       // if kernel >= 5.9-rc1
        unsigned int offset;
        unsigned int cpu_partial;                // if CONFIG_SLUB_CPU_PARTIAL=y
        unsigned int cpu_partial_slabs;          // if CONFIG_SLUB_CPU_PARTIAL=y && kernel >= 5.16-rc1
        struct kmem_cache_order_objects oo;
        struct kmem_cache_order_objects max;     // if kernel < 5.19-rc1
        struct kmem_cache_order_objects min;
        gfp_t allocflags;                        // unsigned int
        int refcount;
        void (*ctor)(void *);
        unsigned int inuse;
        unsigned int align;
        unsigned int red_left_pad;
        const char *name;
        struct list_head list; <-----> struct list_head <-----> struct list_head <-----> ...
        struct kobject kobj;                     // if CONFIG_SYSFS=y
        struct work_struct kobj_remove_work;     // if CONFIG_SYSFS=y && kernel < 5.9-rc1
        struct memcg_cache_params memcg_params;  // if CONFIG_MEMCG=y && kernel < 5.9-rc1
        unsigned int max_attr_size;              // if CONFIG_MEMCG=y && kernel < 5.9-rc1
        struct kset *memcg_kset;                 // if CONFIG_MEMCG=y && CONFIG_SYSFS=y && kernel < 5.9-rc1
        unsigned long random;                    // if CONFIG_SLAB_FREELIST_HARDENED=y
        unsigned int remote_node_defrag_ratio;   // if CONFIG_NUMA=y
        unsigned int *random_seq;                // if CONFIG_SLAB_FREELIST_RANDOM=y
        struct kasan_cache {
            int alloc_meta_offset;
            int free_meta_offset;
            bool is_kmalloc;
        } kasan_info;                            // if CONFIG_KASAN=y
        unsigned int useroffset;
        unsigned int usersize;
        struct kmem_cache_node *node[MAX_NUMNODES];
    };

    struct kmem_cache_cpu {
        void **freelist;
        unsigned long tid;
        struct slab *slab;                       // if kernel >= 5.17-rc1
        struct page *page;                       // if kernel < 5.17-rc1
        struct slab *partial;                    // if kernel >= 5.17-rc1 && CONFIG_SLUB_CPU_PARTIAL=y
        struct page *partial;                    // if kernel < 5.17-rc1 && CONFIG_SLUB_CPU_PARTIAL=y
        local_lock_t lock;                       // if kernel >= 5.15-rc1
        unsigned stat[NR_SLUB_STAT_ITEMS];       // if CONFIG_SLUB_STATS=y
    };

    struct page {                                // if kernel < 4.18-rc1
        unsigned long flags;
        union { };                               // long
        void *freelist;
        unsigned inuse:16, objects:15, frozen:1;
        atomic_t refcount;                       // if kernel < 4.16-rc1
        struct page *next;
        int pages;                               // if 64bit else `short pages`
        int pobjects;                            // if 64bit else `short pobjects`
        struct kmem_cache *slab_cache;
        ...
    };

    struct page {                                // if 4.18-rc1 <= kernel < 5.17-rc1
        unsigned long flags;
        struct page *next;
        int pages;                               // if 64bit else `short pages`
        int pobjects;                            // if 64bit else `short pobjects`
        struct kmem_cache *slab_cache;
        void *freelist;
        unsigned inuse:16, objects:15, frozen:1;
        ...
    };

    struct slab {                                // if kernel >= 5.17-rc1
        unsigned long __page_flags;
        struct kmem_cache *slab_cache;           // if kernel >= 6.2-rc1
        struct slab *next;
        int slabs;
        struct kmem_cache *slab_cache;           // if kernel < 6.2-rc1
        void *freelist;
        unsigned inuse:16, objects:15, frozen:1;
        ...
    };

    struct kmem_cache_node {
        spinlock_t list_lock;
        unsigned long nr_partial;
        struct list_head partial;
        atomic_long_t nr_slabs;                  // CONFIG_SLUB_DEBUG=y
        atomic_long_t total_objects;             // CONFIG_SLUB_DEBUG=y
        struct list_head full;                   // CONFIG_SLUB_DEBUG=y
    };
    """

    def initialize(self):
        if not self.args.meta and self.initialized:
            return True

        # resolve slab_caches
        self.slab_caches = KernelAddressHeuristicFinder.get_slab_caches()
        if self.slab_caches is None:
            self.quiet_err("Failed to resolve `slab_caches`")
            return False
        else:
            self.quiet_info("slab_caches: {:#x}".format(self.slab_caches))

        seen = [self.slab_caches]
        current = self.slab_caches
        while True:
            current = read_int_from_memory(current)
            if current in seen:
                break
            seen.append(current)
        kmem_caches = seen[1:]

        # resolve __per_cpu_offset
        __per_cpu_offset = KernelAddressHeuristicFinder.get_per_cpu_offset()
        if __per_cpu_offset is None:
            self.quiet_info("__per_cpu_offset: Not found")
            self.cpu_offset = []
            self.ncpus = 1
        else:
            self.quiet_info("__per_cpu_offset: {:#x}".format(__per_cpu_offset))
            self.cpu_offset = KernelCurrentCommand.get_each_cpu_offset(__per_cpu_offset)
            self.ncpus = len(self.cpu_offset)

        # offsetof(kmem_cache, list)
        for candidate_offset in range(current_arch.ptrsize * 2, 0x70, current_arch.ptrsize):
            # backward search for the start of `struct kmem_cache`
            found = True
            seen = []
            for kmem_cache in kmem_caches:
                val = read_int_from_memory(kmem_cache - candidate_offset)
                if val in [0, 0xffffffff, 0xffffffffffffffff]:
                    found = False
                    break
                if val in seen:
                    found = False
                    break
                else:
                    seen.append(val)

                for cpuoff in self.cpu_offset:
                    if not is_valid_addr(AddressUtil.align_address(val + cpuoff)):
                        found = False
                        break

            if found:
                self.kmem_cache_offset_list = candidate_offset
                self.quiet_info("offsetof(kmem_cache, list): {:#x}".format(self.kmem_cache_offset_list))
                break
        else:
            self.quiet_info("offsetof(kmem_cache, list): Not found")
            return False

        # offsetof(kmem_cache, name)
        self.kmem_cache_offset_name = self.kmem_cache_offset_list - current_arch.ptrsize
        self.quiet_info("offsetof(kmem_cache, name): {:#x}".format(self.kmem_cache_offset_name))

        # offsetof(kmem_cache, offset)
        top = read_int_from_memory(self.slab_caches) - self.kmem_cache_offset_list
        object_size = u32(read_memory(top + current_arch.ptrsize * 3 + 4, 4))
        maybe_recip = u32(read_memory(top + current_arch.ptrsize * 3 + 4 + 4, 4))
        if object_size < maybe_recip or (maybe_recip % 8) != 0:
            self.kmem_cache_offset_offset = current_arch.ptrsize * 3 + 4 + 4 + 8
        else:
            self.kmem_cache_offset_offset = current_arch.ptrsize * 3 + 4 + 4
        self.quiet_info("offsetof(kmem_cache, offset): {:#x}".format(self.kmem_cache_offset_offset))

        # offsetof(kmem_cache, cpu_slab)
        self.kmem_cache_offset_cpu_slab = 0
        self.quiet_info("offsetof(kmem_cache, cpu_slab): {:#x}".format(self.kmem_cache_offset_cpu_slab))

        # offsetof(kmem_cache, flags)
        self.kmem_cache_offset_flags = current_arch.ptrsize
        self.quiet_info("offsetof(kmem_cache, flags): {:#x}".format(self.kmem_cache_offset_flags))

        # offsetof(kmem_cache, size)
        self.kmem_cache_offset_size = current_arch.ptrsize * 3
        self.quiet_info("offsetof(kmem_cache, size): {:#x}".format(self.kmem_cache_offset_size))

        # offsetof(kmem_cache, object_size)
        self.kmem_cache_offset_object_size = current_arch.ptrsize * 3 + 4
        self.quiet_info("offsetof(kmem_cache, object_size): {:#x}".format(self.kmem_cache_offset_object_size))

        # offsetof(kmem_cache, red_left_pad)
        self.kmem_cache_offset_red_left_pad = self.kmem_cache_offset_name - current_arch.ptrsize
        self.quiet_info("offsetof(kmem_cache, red_left_pad): {:#x}".format(self.kmem_cache_offset_red_left_pad))

        # offsetof(kmem_cache, random)
        if self.args.no_xor:
            self.kmem_cache_offset_random = None
            self.quiet_info("offsetof(kmem_cache, random): None")
        elif self.args.offset_random is not None:
            self.kmem_cache_offset_random = self.args.offset_random
            self.quiet_info("offsetof(kmem_cache, random): {:#x}".format(self.kmem_cache_offset_random))
        else:
            for i in range(2, 0x40): # walk from list for heuristic search
                candidate_offset = current_arch.ptrsize * i
                found = True
                count = 0
                seen = []
                for kmem_cache in kmem_caches:
                    if not is_valid_addr(kmem_cache + candidate_offset):
                        found = False
                        break

                    val = read_int_from_memory(kmem_cache + candidate_offset)
                    if is_valid_addr(val):
                        count += 1
                        if count >= 3:
                            found = False
                            break
                    else:
                        if val > 0xffffff:
                            count -= 1

                    if val != 0:
                        if val in seen:
                            found = False
                            break
                        seen.append(val)

                if found:
                    # Too few random numbers.
                    if len(seen) < 10:
                        found = False

                    # Occurrences of non-negative small integers are stochastically rare.
                    elif sum([0 < x < 0x100000 for x in seen]) >= 3:
                        found = False

                    # Occurrences of big integers are stochastically rare.
                    elif sum([0xffff000000000000 < x <= 0xffffffffffffffff for x in seen]) >= 3:
                        found = False

                    # Occurrences of 0xXXXX000 are stochastically rare.
                    elif sum([x and (x & 0xfff) == 0 for x in seen]) >= 3:
                        found = False

                if found:
                    # search `struct kmem_cache_node *node` or `unsigned int *random_seq`
                    for i in range(1, 9):
                        maybe_ptrs = []
                        for kmem_cache in kmem_caches:
                            v = read_int_from_memory(kmem_cache + candidate_offset + current_arch.ptrsize * i)
                            maybe_ptrs.append(v)
                        # they should be at the same offset
                        if all(is_valid_addr(p) for p in maybe_ptrs):
                            break
                    else:
                        found = False

                if found:
                    self.kmem_cache_offset_random = self.kmem_cache_offset_list + candidate_offset
                    self.quiet_info("offsetof(kmem_cache, random): {:#x}".format(self.kmem_cache_offset_random))
                    break
            else:
                self.quiet_info("offsetof(kmem_cache, random): Not found")
                self.kmem_cache_offset_random = None # maybe CONFIG_SLAB_FREELIST_HARDENED=n

        # offsetof(kmem_cache, node)
        if self.args.offset_node is not None:
            self.kmem_cache_offset_node = self.args.offset_node
            self.quiet_info("offsetof(kmem_cache, node): {:#x}".format(self.kmem_cache_offset_node))
        else:
            start_offset = self.kmem_cache_offset_list + current_arch.ptrsize * 2 # sizeof(kmem_cache.list)
            for candidate_offset in range(start_offset, start_offset + 0x100, current_arch.ptrsize): # walk from list for heuristic search
                found = True
                for kmem_cache in kmem_caches:
                    # fast path
                    if is_64bit():
                        x = read_int_from_memory(kmem_cache - self.kmem_cache_offset_list + candidate_offset + 4 * 2)
                        if is_valid_addr(x):
                            y = read_int_from_memory(x)
                            if y == 0xdead4ead00000000: # SPINLOCK_MAGIC
                                break

                    # slow path
                    user_offset = u32(read_memory(kmem_cache - self.kmem_cache_offset_list + candidate_offset, 4))
                    user_size = u32(read_memory(kmem_cache - self.kmem_cache_offset_list + candidate_offset + 4, 4))
                    object_size = u32(read_memory(kmem_cache - self.kmem_cache_offset_list + self.kmem_cache_offset_object_size, 4))
                    if user_offset == user_size == 0:
                        continue
                    if user_offset != 0 and user_size == 0:
                        found = False
                        break
                    if object_size < user_size:
                        found = False
                        break
                    node_offset = kmem_cache - self.kmem_cache_offset_list + candidate_offset + 4 + 4
                    node_addr = read_int_from_memory(node_offset)
                    if not is_valid_addr(node_addr):
                        found = False
                        break

                if found:
                    self.kmem_cache_offset_node = candidate_offset + 4 * 2
                    self.quiet_info("offsetof(kmem_cache, node): {:#x}".format(self.kmem_cache_offset_node))
                    break
            else:
                self.quiet_info("offsetof(kmem_cache, node): Not found")
                self.kmem_cache_offset_node = None

        # offsetof(kmem_cache_cpu, freelist)
        self.kmem_cache_cpu_offset_freelist = 0
        self.quiet_info("offsetof(kmem_cache_cpu, freelist): {:#x}".format(self.kmem_cache_cpu_offset_freelist))

        # offsetof(kmem_cache_cpu, page or slab)
        self.kmem_cache_cpu_offset_page = current_arch.ptrsize * 2
        self.quiet_info("offsetof(kmem_cache_cpu, page): {:#x}".format(self.kmem_cache_cpu_offset_page))

        # offsetof(kmem_cache_cpu, partial)
        self.kmem_cache_cpu_offset_partial = current_arch.ptrsize * 3
        self.quiet_info("offsetof(kmem_cache_cpu, partial): {:#x}".format(self.kmem_cache_cpu_offset_partial))

        # offsetof(page, next)
        kversion = Kernel.kernel_version()
        if kversion < "4.16" and is_32bit():
            self.page_offset_next = current_arch.ptrsize * 5
        elif kversion < "4.18":
            self.page_offset_next = current_arch.ptrsize * 4
        elif kversion < "5.17":
            self.page_offset_next = current_arch.ptrsize
        elif kversion < "6.2":
            self.page_offset_next = current_arch.ptrsize
        else:
            self.page_offset_next = current_arch.ptrsize * 2
        self.quiet_info("offsetof(page, next): {:#x}".format(self.page_offset_next))

        # offsetof(page, freelist)
        if kversion < "4.18":
            self.page_offset_freelist = current_arch.ptrsize * 2
        elif kversion < "5.17":
            self.page_offset_freelist = current_arch.ptrsize * 4
        elif kversion < "6.2":
            self.page_offset_freelist = current_arch.ptrsize * 4
        else:
            self.page_offset_freelist = current_arch.ptrsize * 4
        self.quiet_info("offsetof(page, freelist): {:#x}".format(self.page_offset_freelist))

        # offsetof(page, slab_cache)
        if kversion < "4.16" and is_32bit():
            self.page_offset_slab_cache = current_arch.ptrsize * 7
        elif kversion < "4.18":
            self.page_offset_slab_cache = current_arch.ptrsize * 6
        elif kversion <= "5.17":
            self.page_offset_slab_cache = current_arch.ptrsize * 3
        elif kversion < "6.2":
            self.page_offset_slab_cache = current_arch.ptrsize * 3
        else:
            self.page_offset_slab_cache = current_arch.ptrsize
        self.quiet_info("offsetof(page, slab_cache): {:#x}".format(self.page_offset_slab_cache))

        # offsetof(page, inuse_objects_frozen)
        self.page_offset_inuse_objects_frozen = self.page_offset_freelist + current_arch.ptrsize
        self.quiet_info("offsetof(page, inuse_objects_frozen): {:#x}".format(self.page_offset_inuse_objects_frozen))

        if self.kmem_cache_offset_node is None:
            self.quiet_info("offsetof(kmem_cache_node, partial): Not found")
            self.kmem_cache_node_offset_partial = None
        else:
            # offsetof(kmem_cache_node, partial)
            node = read_int_from_memory(kmem_caches[0] - self.kmem_cache_offset_list + self.kmem_cache_offset_node)
            for i in range(2, 16):
                offset_partial = current_arch.ptrsize * i
                if is_double_link_list(node + offset_partial):
                    self.kmem_cache_node_offset_partial = offset_partial
                    self.quiet_info("offsetof(kmem_cache_node, partial): {:#x}".format(self.kmem_cache_node_offset_partial))
                    break
            else:
                self.quiet_info("offsetof(kmem_cache_node, partial): Not found")
                self.kmem_cache_node_offset_partial = None

        self.initialized = True
        return True

    def get_flags_str(self, flags_value):
        _flags = {
            "__OBJECT_POISON":         0x80000000,
            "__CMPXCHG_DOUBLE":        0x40000000,
            "SLAB_SKIP_KFENCE":        0x20000000,
            "SLAB_NO_USER_FLAGS":      0x10000000,
            "SLAB_KASAN":              0x08000000,
            "SLAB_ACCOUNT":            0x04000000,
            "SLAB_FAILSLAB":           0x02000000,
            "SLAB_NOTRACK":            0x01000000,
            "SLAB_NOLEAKTRACE":        0x00800000,
            "SLAB_DEBUG_OBJECTS":      0x00400000,
            "SLAB_TRACE":              0x00200000,
            "SLAB_MEM_SPREAD":         0x00100000,
            "SLAB_TYPESAFE_BY_RCU":    0x00080000,
            "SLAB_PANIC":              0x00040000,
            "SLAB_RECLAIM_ACCOUNT":    0x00020000,
            "SLAB_STORE_USER":         0x00010000,
            "SLAB_CACHE_DMA32":        0x00008000,
            "SLAB_CACHE_DMA":          0x00004000,
            "SLAB_HWCACHE_ALIGN":      0x00002000,
            "SLAB_KMALLOC":            0x00001000,
            "SLAB_POISON":             0x00000800,
            "SLAB_RED_ZONE":           0x00000400,
            "SLAB_DEBUG_INITIAL":      0x00000200, # kernel < v2.6.22
            "SLAB_CONSISTENCY_CHECKS": 0x00000100,
        }
        flags = []
        for k, v in _flags.items():
            if flags_value & v:
                flags.append(k)

        flags_str = " | ".join(flags)
        if flags_str == "":
            flags_str = "none"
        return flags_str

    def get_next_kmem_cache(self, addr, point_to_base=True):
        if point_to_base:
            addr += self.kmem_cache_offset_list
        return read_int_from_memory(addr) - self.kmem_cache_offset_list

    def get_name(self, addr):
        name_addr = read_int_from_memory(addr + self.kmem_cache_offset_name)
        return read_cstring_from_memory(name_addr)

    def get_random(self, addr):
        if self.kmem_cache_offset_random is None:
            return 0
        else:
            return read_int_from_memory(addr + self.kmem_cache_offset_random)

    def get_kmem_cache_cpu(self, addr, cpu):
        cpu_slab = read_int_from_memory(addr + self.kmem_cache_offset_cpu_slab)
        if len(self.cpu_offset) > 0:
            kmem_cache_cpu = cpu_slab + self.cpu_offset[cpu]
        else:
            kmem_cache_cpu = cpu_slab
        return AddressUtil.align_address(kmem_cache_cpu)

    def page2virt(self, page, kmem_cache, freelist_fastpath=()):
        if not self.args.skip_page2virt:
            ret = gdb.execute("page2virt {:#x}".format(page["address"]), to_string=True)
            r = re.search(r"Virt: (\S+)", ret)
            if r:
                return int(r.group(1), 16)

        # setup for heuristic search from freelist
        freelist = list(freelist_fastpath) + page["freelist"]
        freelist = [x for x in freelist if isinstance(x, int) and x != 0] # ignore str and last 0
        if not freelist:
            return None

        # heuristic detection pattern 1
        # freed chunks are scattered and can be confirmed on each of the pages
        page_heads = [x & gef_getpagesize_mask_high() for x in freelist]
        uniq_page_heads = list(set(page_heads))
        if page["num_pages"] == len(uniq_page_heads):
            return min(uniq_page_heads)

        # heuristic detection pattern 2
        # if there is only one pattern with good alignment, use it
        # e.g.: num_pages = 5
        # 0xXXXX0000
        # 0xXXXX1000   <----------------------------------- most_top_page   ^
        # 0xXXXX2000                                                       ^|
        # 0xXXXX3000   <-- chunk in freelist (min_page) ^                 ^||
        # 0xXXXX4000                                    | known_num_pages |||
        # 0xXXXX5000   <-- chunk in freelist (max_page) v                 ||v pattern 3
        # 0xXXXX6000                                                      |v pattern 2
        # 0xXXXX7000                                                      v pattern 1
        chunk_size = kmem_cache["size"]
        min_page = min(freelist) & gef_getpagesize_mask_high()
        max_page = max(freelist) & gef_getpagesize_mask_high()
        known_num_pages = ((max_page - min_page) // gef_getpagesize()) + 1
        unknown_num_pages = page["num_pages"] - known_num_pages
        most_top_page = min_page - (unknown_num_pages * gef_getpagesize())
        candidate_top_pages = range(most_top_page, min_page + gef_getpagesize(), gef_getpagesize())
        # alignment check for each candidate_top_pages
        valid_top_pages = []
        for cand_top in candidate_top_pages:
            for chunk in freelist:
                # divisible?
                if (chunk - cand_top) % chunk_size != 0:
                    break
            else:
                valid_top_pages.append(cand_top)
            # fast break if invalid
            if len(valid_top_pages) >= 2:
                break
        # confirm if there is only one valid pattern
        if len(valid_top_pages) == 1:
            return valid_top_pages[0]

        # not found
        return None

    def pointer_xor(self, addr, chunk, cache):
        def pattern1(addr, chunk, cache):
            return chunk ^ addr ^ cache["random"]

        def pattern2(addr, chunk, cache):
            return chunk ^ byteswap(addr) ^ cache["random"]

        if is_64bit():
            shift_bits = 48
        else:
            shift_bits = 24

        if self.swap is False:
            chunk = pattern1(addr, chunk, cache)
        elif self.swap is True:
            chunk = pattern2(addr, chunk, cache)

        elif self.swap is None: # swap type is unknown, try heuristic check
            if pattern1(addr, chunk, cache) == 0:
                chunk = pattern1(addr, chunk, cache)
                self.swap = False
            elif (chunk >> shift_bits) == (cache["random"] >> shift_bits):
                chunk = pattern1(addr, chunk, cache)
                self.swap = False
            else:
                chunk = pattern2(addr, chunk, cache)
                self.swap = True
        return chunk

    def walk_freelist(self, chunk, kmem_cache):
        if self.args.simple:
            return [chunk]

        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")

        freelist = [chunk]
        while chunk:
            try:
                addr = chunk + kmem_cache["offset"]
                chunk = read_int_from_memory(addr) # get next chunk
            except gdb.MemoryError:
                freelist.append("{:s}".format(Color.colorify("Corrupted (Memory access denied)", corrupted_msg_color)))
                break
            if self.kmem_cache_offset_random is not None: # fix if randomized
                chunk = self.pointer_xor(addr, chunk, kmem_cache)
            if chunk % 8:
                freelist.append("{:#x}: {:s}".format(chunk, Color.colorify("Corrupted (Not aligned)", corrupted_msg_color)))
                break
            if chunk in freelist:
                freelist.append("{:#x}: {:s}".format(chunk, Color.colorify("Corrupted (Loop detected)", corrupted_msg_color)))
                break
            freelist.append(chunk)
        return freelist

    def walk_caches(self, target_names, cpus):
        current_kmem_cache = self.get_next_kmem_cache(self.slab_caches, point_to_base=False)
        parsed_caches = [{"name": "slab_caches", "next": current_kmem_cache}]

        # first, parse kmem_cache
        while current_kmem_cache + self.kmem_cache_offset_list != self.slab_caches:
            kmem_cache = {}
            # parse member
            kmem_cache["name"] = self.get_name(current_kmem_cache)
            if target_names != [] and kmem_cache["name"] not in target_names:
                current_kmem_cache = self.get_next_kmem_cache(current_kmem_cache)
                continue
            kmem_cache["address"] = current_kmem_cache
            kmem_cache["flags"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_flags, 4))
            kmem_cache["flags_str"] = self.get_flags_str(kmem_cache["flags"])
            kmem_cache["size"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_size, 4))
            kmem_cache["object_size"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_object_size, 4))
            kmem_cache["offset"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_offset, 4))
            kmem_cache["red_left_pad"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_red_left_pad, 4))
            kmem_cache["random"] = self.get_random(current_kmem_cache)
            kmem_cache["next"] = self.get_next_kmem_cache(current_kmem_cache)
            parsed_caches.append(kmem_cache)
            # goto next
            current_kmem_cache = kmem_cache["next"]

        if self.args.list:
            return parsed_caches

        # second, parse kmem_cache_cpu
        tqdm = GefUtil.get_tqdm(not self.args.quiet)
        for kmem_cache in tqdm(parsed_caches[1:], leave=False): # parsed_caches[0] is slab_caches, so skip
            # parse kmem_cache_cpu
            kmem_cache["kmem_cache_cpu"] = {}
            for cpu in cpus:
                kmem_cache["kmem_cache_cpu"][cpu] = {}
                kmem_cache["kmem_cache_cpu"][cpu]["address"] = self.get_kmem_cache_cpu(kmem_cache["address"], cpu)
                active_chunk_fast = read_int_from_memory(kmem_cache["kmem_cache_cpu"][cpu]["address"] + self.kmem_cache_cpu_offset_freelist)
                kmem_cache["kmem_cache_cpu"][cpu]["freelist"] = self.walk_freelist(active_chunk_fast, kmem_cache)

                # parse active
                active_page = {}
                active_page["address"] = page = read_int_from_memory(kmem_cache["kmem_cache_cpu"][cpu]["address"] + self.kmem_cache_cpu_offset_page)
                if is_valid_addr(page):
                    x = read_int_from_memory(page + self.page_offset_inuse_objects_frozen)
                    active_page["inuse"] = x & 0xffff
                    active_page["objects"] = (x >> 16) & 0x7fff
                    active_page["frozen"] = (x >> 31) & 1
                    active_chunk = read_int_from_memory(page + self.page_offset_freelist)
                    active_page["freelist"] = self.walk_freelist(active_chunk, kmem_cache)
                    active_page["num_pages"] = (kmem_cache["size"] * active_page["objects"] + gef_getpagesize_mask_low()) // gef_getpagesize()
                    active_page["virt_addr"] = self.page2virt(active_page, kmem_cache, kmem_cache["kmem_cache_cpu"][cpu]["freelist"])
                kmem_cache["kmem_cache_cpu"][cpu]["active_page"] = active_page

                # parse partial
                if self.args.verbose or self.args.vverbose:
                    kmem_cache["kmem_cache_cpu"][cpu]["partial_pages"] = []
                    current_partial_page = read_int_from_memory(kmem_cache["kmem_cache_cpu"][cpu]["address"] + self.kmem_cache_cpu_offset_partial)
                    while True:
                        partial_page = {}
                        partial_page["address"] = current_partial_page
                        if not is_valid_addr(current_partial_page):
                            kmem_cache["kmem_cache_cpu"][cpu]["partial_pages"].append(partial_page)
                            break
                        x = read_int_from_memory(current_partial_page + self.page_offset_inuse_objects_frozen)
                        partial_page["inuse"] = x & 0xffff
                        partial_page["objects"] = (x >> 16) & 0x7fff
                        if partial_page["objects"] == 0 or partial_page["inuse"] > partial_page["objects"]: # something is wrong
                            break
                        partial_page["frozen"] = (x >> 31) & 1
                        partial_chunk = read_int_from_memory(current_partial_page + self.page_offset_freelist)
                        partial_page["freelist"] = self.walk_freelist(partial_chunk, kmem_cache)
                        partial_page["num_pages"] = (kmem_cache["size"] * partial_page["objects"] + gef_getpagesize_mask_low()) // gef_getpagesize()
                        partial_page["virt_addr"] = self.page2virt(partial_page, kmem_cache)
                        kmem_cache["kmem_cache_cpu"][cpu]["partial_pages"].append(partial_page)
                        next_partial_page = read_int_from_memory(current_partial_page + self.page_offset_next)
                        if next_partial_page in [x["address"] for x in kmem_cache["kmem_cache_cpu"][cpu]["partial_pages"]]:
                            break
                        current_partial_page = next_partial_page

            # parse node
            if self.args.vverbose and self.kmem_cache_offset_node and self.kmem_cache_node_offset_partial:
                kmem_cache["nodes"] = []
                kmem_cache_node_array = kmem_cache["address"] + self.kmem_cache_offset_node
                current_kmem_cache_node_ptr = kmem_cache_node_array
                while True:
                    current_kmem_cache_node = read_int_from_memory(current_kmem_cache_node_ptr)
                    if current_kmem_cache_node == 0:
                        break
                    if current_kmem_cache_node == current_kmem_cache_node_ptr:
                        break
                    if current_kmem_cache_node & 0b111:
                        break
                    node_page_list = []
                    node_page_head = current_kmem_cache_node + self.kmem_cache_node_offset_partial
                    if not is_valid_addr(node_page_head):
                        break
                    current_node_page = read_int_from_memory(node_page_head)
                    while current_node_page != node_page_head:
                        node_page = {}
                        node_page["address"] = current_node_page - self.page_offset_next
                        if not is_valid_addr(node_page["address"]):
                            node_page_list.append(node_page)
                            break
                        x = read_int_from_memory(node_page["address"] + self.page_offset_inuse_objects_frozen)
                        node_page["inuse"] = x & 0xffff
                        node_page["objects"] = (x >> 16) & 0x7fff
                        if node_page["objects"] == 0 or node_page["inuse"] > node_page["objects"]: # something is wrong
                            break
                        node_page["frozen"] = (x >> 31) & 1
                        node_chunk = read_int_from_memory(node_page["address"] + self.page_offset_freelist)
                        node_page["freelist"] = self.walk_freelist(node_chunk, kmem_cache)
                        node_page["num_pages"] = (kmem_cache["size"] * node_page["objects"] + gef_getpagesize_mask_low()) // gef_getpagesize()
                        node_page["virt_addr"] = self.page2virt(node_page, kmem_cache)
                        node_page_list.append(node_page)
                        current_node_page = read_int_from_memory(node_page["address"] + self.page_offset_next)
                    kmem_cache["nodes"].append(node_page_list)
                    current_kmem_cache_node_ptr += current_arch.ptrsize
        return parsed_caches

    def dump_page(self, page, kmem_cache, tag, freelist_fastpath=()):
        label_active_color = Config.get_gef_setting("theme.heap_label_active")
        label_inactive_color = Config.get_gef_setting("theme.heap_label_inactive")
        heap_page_color = Config.get_gef_setting("theme.heap_page_address")
        used_address_color = Config.get_gef_setting("theme.heap_chunk_address_used")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        freelist_fastpath = list(freelist_fastpath)

        # page address
        if tag == "active":
            tag_s = Color.colorify("{:s} page".format(tag), label_active_color)
        else:
            tag_s = Color.colorify("{:s} page".format(tag), label_inactive_color)
        self.out.append("      {:s}: {:#x}".format(tag_s, page["address"]))

        # fast return if invalid
        if not is_valid_addr(page["address"]):
            return

        # print virtual address
        if page["virt_addr"] is None:
            self.out.append("        virtual address: ???")
        else:
            colored_virt_addr = Color.colorify_hex(page["virt_addr"], heap_page_color)
            self.out.append("        virtual address: {:s}".format(colored_virt_addr))

        # print info
        self.out.append("        num pages: {:d}".format(page["num_pages"]))

        if self.args.simple:
            return

        freelist = page["freelist"]
        if tag == "active":
            freelist_len = len(set(freelist + freelist_fastpath)) - 1 # ignore last 0
            inuse = page["objects"] - freelist_len
        else:
            inuse = page["inuse"]
        self.out.append("        in-use: {:d}/{:d}".format(inuse, page["objects"]))
        self.out.append("        frozen: {:d}".format(page["frozen"]))

        # print layout
        if page["virt_addr"] is not None:
            end_virt = page["virt_addr"] + page["num_pages"] * gef_getpagesize()
            start_addr = page["virt_addr"] + kmem_cache["red_left_pad"]

            if kmem_cache["red_left_pad"]:
                chunk_s = Color.colorify_hex(page["virt_addr"], used_address_color)
                self.out.append("        {:7s}   {:#05x} {:s} ({:s})".format("layout:", 0, chunk_s, "never-used"))
                start_idx = 1
            else:
                start_idx = 0

            for idx, chunk in enumerate(range(start_addr, end_virt, kmem_cache["size"]), start=start_idx):
                if chunk in freelist_fastpath[:-1]:
                    next_chunk = freelist_fastpath[freelist_fastpath.index(chunk) + 1]
                    if isinstance(next_chunk, str):
                        next_msg = "next: {:s}".format(next_chunk)
                    else:
                        next_msg = "next: {:#x}".format(next_chunk)
                    chunk_s = Color.colorify_hex(chunk, freed_address_color)
                elif chunk in freelist[:-1]:
                    next_chunk = freelist[freelist.index(chunk) + 1]
                    if isinstance(next_chunk, str):
                        next_msg = "next: {:s}".format(next_chunk)
                    else:
                        next_msg = "next: {:#x}".format(next_chunk)
                    if tag == "active":
                        next_msg += " (slow path)"
                    chunk_s = Color.colorify_hex(chunk, freed_address_color)
                else:
                    if page["objects"] <= idx:
                        next_msg = "never-used"
                    else:
                        next_msg = "in-use"
                    chunk_s = Color.colorify_hex(chunk, used_address_color)
                layout_msg = "layout:" if idx == 0 else ""
                self.out.append("        {:7s}   {:#05x} {:s} ({:s})".format(layout_msg, idx, chunk_s, next_msg))

                # dump chunks
                if self.args.hexdump_used and next_msg == "in-use":
                    peeked_data = read_memory(chunk, self.args.hexdump_used)
                    h = hexdump(peeked_data, 0x10, base=chunk, unit=current_arch.ptrsize)
                    self.out.append(h)

                if self.args.hexdump_freed and next_msg.startswith("next: "):
                    peeked_data = read_memory(chunk, self.args.hexdump_freed)
                    h = hexdump(peeked_data, 0x10, base=chunk, unit=current_arch.ptrsize)
                    self.out.append(h)

                if self.args.telescope_used and next_msg == "in-use":
                    n = self.args.telescope_used // current_arch.ptrsize
                    for i in range(n):
                        line = DereferenceCommand.pprint_dereferenced(chunk, i)
                        self.out.append(line)

                if self.args.telescope_freed and next_msg.startswith("next: "):
                    n = self.args.telescope_freed // current_arch.ptrsize
                    for i in range(n):
                        line = DereferenceCommand.pprint_dereferenced(chunk, i)
                        self.out.append(line)
        else:
            self.out.append("        layout: Failed to the get first page")

        # print freelist
        def print_freelist(freelist):
            for chunk_addr in freelist:
                if page["virt_addr"] is not None:
                    if chunk_addr == 0:
                        continue
                    if isinstance(chunk_addr, str):
                        chunk_idx = ""
                        msg = chunk_addr
                    else:
                        chunk_idx = (chunk_addr - page["virt_addr"]) // kmem_cache["size"]
                        if chunk_idx < 0 or page["objects"] <= chunk_idx:
                            chunk_idx = ""
                        else:
                            chunk_idx = "{:#05x}".format(chunk_idx)
                        msg = Color.colorify_hex(chunk_addr, freed_address_color)
                    self.out.append("                  {:5s} {:s}".format(chunk_idx, msg))
                else:
                    if isinstance(chunk_addr, str):
                        msg = chunk_addr
                    else:
                        msg = Color.colorify_hex(chunk_addr, freed_address_color)
                    self.out.append("                        {:s}".format(msg))
            return

        if tag == "active":
            if freelist_fastpath == [] or freelist_fastpath == [0]:
                self.out.append("        freelist (fast path): (none)")
            else:
                self.out.append("        freelist (fast path):")
                print_freelist(freelist_fastpath)
            if freelist == [] or freelist == [0]:
                self.out.append("        freelist (slow path): (none)")
            else:
                self.out.append("        freelist (slow path):")
                print_freelist(freelist)
        else:
            if freelist == [] or freelist == [0]:
                self.out.append("        freelist: (none)")
            else:
                self.out.append("        freelist:")
                print_freelist(freelist)
        return

    def dump_caches(self, target_names, cpus, parsed_caches):
        chunk_label_color = Config.get_gef_setting("theme.heap_chunk_label")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")
        label_inactive_color = Config.get_gef_setting("theme.heap_label_inactive")

        self.out.append("slab_caches @ {:#x}".format(self.slab_caches))
        for kmem_cache in parsed_caches[1:]:
            if target_names != [] and kmem_cache["name"] not in target_names:
                continue

            # dump meta
            self.out.append("")
            self.out.append("  kmem_cache: {:#x}".format(kmem_cache["address"]))
            self.out.append("    name: {:s}".format(Color.colorify(kmem_cache["name"], chunk_label_color)))
            self.out.append("    flags: {:#x} ({:s})".format(kmem_cache["flags"], kmem_cache["flags_str"]))
            object_size_s = Color.colorify_hex(kmem_cache["object_size"], chunk_size_color)
            self.out.append("    object size: {:s} (chunk size: {:#x})".format(object_size_s, kmem_cache["size"]))
            self.out.append("    offset (next pointer in chunk): {:#x}".format(kmem_cache["offset"]))
            if self.kmem_cache_offset_random is not None:
                if self.args.no_xor is False:
                    if self.swap is True:
                        fmt = "    random (xor key): {:#x} ^ byteswap(&chunk->next)"
                        self.out.append(fmt.format(kmem_cache["random"]))
                    else:
                        fmt = "    random (xor key): {:#x} ^ &chunk->next"
                        self.out.append(fmt.format(kmem_cache["random"]))
            self.out.append("    red_left_pad: {:#x}".format(kmem_cache["red_left_pad"]))

            for cpu in cpus:
                self.out.append("    kmem_cache_cpu (cpu{:d}): {:#x}".format(cpu, kmem_cache["kmem_cache_cpu"][cpu]["address"]))

                # dump active
                active_page = kmem_cache["kmem_cache_cpu"][cpu]["active_page"]
                freelist_fastpath = kmem_cache["kmem_cache_cpu"][cpu]["freelist"]
                self.dump_page(active_page, kmem_cache, "active", freelist_fastpath)

                # dump partial
                if self.args.verbose or self.args.vverbose:
                    printed_count = 0
                    for partial_page in kmem_cache["kmem_cache_cpu"][cpu]["partial_pages"]:
                        self.dump_page(partial_page, kmem_cache, "partial")
                        printed_count += 1
                    if printed_count > 1 : # included address == 0
                        self.out.append("        (end of the list)")

            # dump nodes
            if self.args.vverbose and "nodes" in kmem_cache:
                for node_index, node_page_list in enumerate(kmem_cache["nodes"]):
                    node_addr = read_int_from_memory(kmem_cache["address"] + self.kmem_cache_offset_node + current_arch.ptrsize * node_index)
                    self.out.append("    kmem_cache_node[{:d}]: {:#x}".format(node_index, node_addr))
                    printed_count = 0
                    for node_page in node_page_list:
                        self.dump_page(node_page, kmem_cache, "node")
                        printed_count += 1
                    if printed_count == 0:
                        tag = Color.colorify("node pages", label_inactive_color)
                        self.out.append("      {:s}: (none)".format(tag))

            self.out.append("    next: {:#x}".format(kmem_cache["next"]))
        return

    def dump_names(self, parsed_caches):
        if not self.args.quiet:
            fmt = "{:<16s} {:<16s} {:30s} {:20s}"
            legend = ["Object Size", "Chunk Size", "Name", "kmem_cache"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
        for kmem_cache in sorted(parsed_caches[1:], key=lambda x: x["object_size"]):
            objsz = "{0:d} ({0:#x})".format(kmem_cache["object_size"])
            chunksz = "{0:d} ({0:#x})".format(kmem_cache["size"])
            chunk_name = kmem_cache["name"]
            address = kmem_cache["address"]
            self.out.append("{:16s} {:16s} {:30s} {:#x}".format(objsz, chunksz, chunk_name, address))
        return

    def slubwalk(self, target_names, cpu):
        if self.initialize() is False:
            self.quiet_err("Initialize failed")
            return

        if self.args.meta:
            return

        if self.args.list:
            parsed_caches = self.walk_caches(target_names, cpus=None)
            self.dump_names(parsed_caches)
            return

        if cpu is None:
            target_cpus = list(range(self.ncpus))
        else:
            if self.ncpus <= cpu:
                self.quiet_err("CPU number is invalid (valid range: {:d}-{:d})".format(0, self.ncpus - 1))
                return
            target_cpus = [cpu]

        parsed_caches = self.walk_caches(target_names, target_cpus)
        self.dump_caches(target_names, target_cpus, parsed_caches)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if not args.quiet:
            info("Wait for memory scan")

        if (is_x86() or is_arm32()) and not self.initialized and not args.skip_page2virt:
            # The slub-dump command is also called by page2virt and kmagic to determine vmemmap and sizeof(struct page).
            # Therefore, slub-dump itself may be called recursively (up to once) from slub-dump.
            # If a recursive call is made, various parameters held by self will be destroyed.
            # It's very tricky, but if we make sure to call page2virt first, no further calls will be made and
            # it will work without any problems.
            gdb.execute("page2virt 0", to_string=True)

        allocator = KernelChecksecCommand.get_slab_type()
        if allocator != "SLUB":
            if not args.quiet:
                err("Unsupported SLAB, SLOB, SLUB_TINY")
            return

        if args.no_byte_swap is None:
            self.swap = None
        else:
            self.swap = not args.no_byte_swap

        self.args = args
        self.maps = None
        self.out = []
        self.slubwalk(args.cache_name, args.cpu)
        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class SlubTinyDumpCommand(GenericCommand):
    """Dump slub-tiny free-list."""
    _cmdline_ = "slub-tiny-dump"
    _category_ = "08-e. Qemu-system Cooperation - Linux Allocator"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("cache_name", metavar="SLUB_CACHE_NAME", nargs="*", help="filter by specific slub cache name.")
    parser.add_argument("--list", action="store_true", help="list up all slub cache names.")
    parser.add_argument("--meta", action="store_true", help="display offset information.")
    parser.add_argument("-s", "--simple", action="store_true", help="skip displaying layout and freelist.")
    parser.add_argument("--hexdump-used", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="hexdump `used chunks` if layout is resolved.")
    parser.add_argument("--hexdump-freed", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="hexdump `unused (freed) chunks` if layout is resolved.")
    parser.add_argument("--telescope-used", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="telescope `used chunks` if layout is resolved.")
    parser.add_argument("--telescope-freed", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="telescope `unused (freed) chunks` if layout is resolved.")
    parser.add_argument("--skip-page2virt", action="store_true", help="used internally in gef, please don't use it.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} kmalloc-256 # dump kmalloc-256 from all cpus\n".format(_cmdline_)
    _example_ += "{:s} --list      # list up slub cache names".format(_cmdline_)

    _note_ = "Simplified SLUB-TINY structure:\n"
    _note_ += "\n"
    _note_ += "                         +-kmem_cache--+     +-kmem_cache--+   +-kmem_cache--+\n"
    _note_ += "                         | flags       |     | flags       |   | flags       |\n"
    _note_ += "                         | size        |     | size        |   | size        |\n"
    _note_ += "                         | object_size |     | object_size |   | object_size |\n"
    _note_ += "                         | offset      |     | offset      |   | offset      |\n"
    _note_ += "       +-slab_caches-+   | name        |     | name        |   | name        |\n"
    _note_ += " ...<->| list_head   |<->| list_head   |<--->| list_head   |<->| list_head   |<-> ...\n"
    _note_ += "       +-------------+   | node[]      |--+  | node[]      |   | node[]      |\n"
    _note_ += "                         +-------------+  |  +-------------+   +-------------+\n"
    _note_ += "                                          |\n"
    _note_ += "    +-------------------------------------+\n"
    _note_ += "    |\n"
    _note_ += "    v\n"
    _note_ += "  +-kmem_cache_node-+\n"
    _note_ += "  | partial         |--+\n"
    _note_ += "  +-----------------+  |\n"
    _note_ += "  | ...             |  |\n"
    _note_ += "  +-----------------+  |\n"
    _note_ += "                       |\n"
    _note_ += "    +------------------+\n"
    _note_ += "    |\n"
    _note_ += "    v                       [numa node partial page freelist]\n"
    _note_ += "  +-slub-----------+          +-chunk---+  +-chunk---+\n"
    _note_ += "  | freelist       |----+     | ^       |  | ^       |\n"
    _note_ += "  | next           |--+ |     | |offset |  | |offset |\n"
    _note_ += "  +----------------+  | |     | v       |  | v       |\n"
    _note_ += "                      | +---->| next    |->| next    |->NULL\n"
    _note_ += "    +-----------------+       +---------+  +---------+\n"
    _note_ += "    |\n"
    _note_ += "    v                       [numa node partial page freelist]\n"
    _note_ += "  +-slub-----------+          +-chunk---+  +-chunk---+\n"
    _note_ += "  | freelist       |----+     | ^       |  | ^       |\n"
    _note_ += "  | next           |--+ |     | |offset |  | |offset |\n"
    _note_ += "  +----------------+  | |     | v       |  | v       |\n"
    _note_ += "                      | +---->| next    |->| next    |->NULL\n"
    _note_ += "    +-----------------+       +---------+  +---------+\n"
    _note_ += "    |\n"
    _note_ += "    v\n"
    _note_ += "   ...\n"

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        return

    def quiet_err(self, msg):
        if not self.args.quiet:
            err(msg)
        return

    def quiet_info(self, msg):
        if not self.args.quiet:
            info(msg)
        return

    """
    struct kmem_cache {
        slab_flags_t flags;                      // unsigned int (+ padding 4 byte)
        unsigned long min_partial;
        unsigned int size;
        unsigned int object_size;
        struct reciprocal_value {                //
            u32 m;                               //
            u8 sh1, sh2;                         // (+ padding 2 byte)
        } reciprocal_size;                       //
        unsigned int offset;
        unsigned int cpu_partial;                // if CONFIG_SLUB_CPU_PARTIAL=y
        unsigned int cpu_partial_slabs;          // if CONFIG_SLUB_CPU_PARTIAL=y
        struct kmem_cache_order_objects oo;
        struct kmem_cache_order_objects min;
        gfp_t allocflags;                        // unsigned int
        int refcount;
        void (*ctor)(void *);
        unsigned int inuse;
        unsigned int align;
        unsigned int red_left_pad;
        const char *name;
        struct list_head list; <-----> struct list_head <-----> struct list_head <-----> ...
        struct kobject {
            const char *name;
            struct list_head entry;
            struct kobject *parent;
            struct kset *kset;
            const struct kobj_type *ktype;
            struct kernfs_node *sd;
            struct kref kref;
            struct delayed_work release;         // if CONFIG_DEBUG_KOBJECT_RELEASE=y
            unsigned int state_initialized:1;
            unsigned int state_in_sysfs:1;
            unsigned int state_add_uevent_sent:1;
            unsigned int state_remove_uevent_sent:1;
            unsigned int uevent_suppress:1;
        } kobj;                                  // if CONFIG_SYSFS=y
        unsigned int remote_node_defrag_ratio;   // if CONFIG_NUMA=y
        struct kasan_cache {
            int alloc_meta_offset;
            int free_meta_offset;
            bool is_kmalloc;
        } kasan_info;                            // if CONFIG_KASAN=y
        unsigned int useroffset;
        unsigned int usersize;
        struct kmem_cache_node *node[MAX_NUMNODES];
    };

    struct slab {
        unsigned long __page_flags;
        struct kmem_cache *slab_cache;
        struct slab *next;
        int slabs;
        void *freelist;
        unsigned inuse:16, objects:15, frozen:1;
        ...
    };

    struct kmem_cache_node {
        spinlock_t list_lock;
        unsigned long nr_partial;
        struct list_head partial;
        atomic_long_t nr_slabs;                  // CONFIG_SLUB_DEBUG=y
        atomic_long_t total_objects;             // CONFIG_SLUB_DEBUG=y
        struct list_head full;                   // CONFIG_SLUB_DEBUG=y
    };
    """

    def initialize(self):
        if not self.args.meta and self.initialized:
            return True

        # resolve slab_caches
        self.slab_caches = KernelAddressHeuristicFinder.get_slab_caches()
        if self.slab_caches is None:
            self.quiet_err("Failed to resolve `slab_caches`")
            return False
        else:
            self.quiet_info("slab_caches: {:#x}".format(self.slab_caches))

        seen = [self.slab_caches]
        current = self.slab_caches
        while True:
            current = read_int_from_memory(current)
            if current in seen:
                break
            seen.append(current)
        kmem_caches = seen[1:]

        # offsetof(kmem_cache, list)
        candidate = (0, -1) # (count, candidate_offset)
        for candidate_offset in range(current_arch.ptrsize * 2, 0x70, current_arch.ptrsize):
            # backward search for the start of `struct kmem_cache`
            found = True
            count = 0
            for kmem_cache in kmem_caches:
                val = read_int_from_memory(kmem_cache - candidate_offset)
                if val & 0x40000000: # __CMPXCHG_DOUBLE
                    count += 1
            if candidate[0] < count:
                candidate = (count, candidate_offset)

        self.kmem_cache_offset_list = candidate[1]
        self.quiet_info("offsetof(kmem_cache, list): {:#x}".format(self.kmem_cache_offset_list))

        # offsetof(kmem_cache, name)
        self.kmem_cache_offset_name = self.kmem_cache_offset_list - current_arch.ptrsize
        self.quiet_info("offsetof(kmem_cache, name): {:#x}".format(self.kmem_cache_offset_name))

        # offsetof(kmem_cache, offset)
        self.kmem_cache_offset_offset = current_arch.ptrsize * 2 + 4 + 4 + 8
        self.quiet_info("offsetof(kmem_cache, offset): {:#x}".format(self.kmem_cache_offset_offset))

        # offsetof(kmem_cache, flags)
        self.kmem_cache_offset_flags = 0
        self.quiet_info("offsetof(kmem_cache, flags): {:#x}".format(self.kmem_cache_offset_flags))

        # offsetof(kmem_cache, size)
        self.kmem_cache_offset_size = current_arch.ptrsize * 2
        self.quiet_info("offsetof(kmem_cache, size): {:#x}".format(self.kmem_cache_offset_size))

        # offsetof(kmem_cache, object_size)
        self.kmem_cache_offset_object_size = current_arch.ptrsize * 2 + 4
        self.quiet_info("offsetof(kmem_cache, object_size): {:#x}".format(self.kmem_cache_offset_object_size))

        # offsetof(kmem_cache, red_left_pad)
        self.kmem_cache_offset_red_left_pad = self.kmem_cache_offset_name - current_arch.ptrsize
        self.quiet_info("offsetof(kmem_cache, red_left_pad): {:#x}".format(self.kmem_cache_offset_red_left_pad))

        # offsetof(kmem_cache, node)
        start_offset = self.kmem_cache_offset_list + current_arch.ptrsize * 2 # sizeof(kmem_cache.list)
        for candidate_offset in range(start_offset, start_offset + 0x100, current_arch.ptrsize): # walk from list for heuristic search
            found = True
            for kmem_cache in kmem_caches:
                top = kmem_cache - self.kmem_cache_offset_list
                maybe_node = read_int_from_memory(top + candidate_offset)
                if not is_valid_addr(maybe_node):
                    found = False
                    break
                if not is_valid_addr(maybe_node + current_arch.ptrsize * 2):
                    found = False
                    break
                maybe_slub = read_int_from_memory(maybe_node + current_arch.ptrsize * 2)
                if not is_valid_addr(maybe_slub):
                    found = False
                    break
                a = read_int_from_memory(maybe_slub)
                if not is_valid_addr(a):
                    found = False
                    break
                b = read_int_from_memory(maybe_slub + current_arch.ptrsize)
                if not is_valid_addr(b):
                    found = False
                    break
                if a != maybe_node + current_arch.ptrsize * 2: # something is in linklist
                    c = read_int_from_memory(maybe_slub - current_arch.ptrsize)
                    if c != top:
                        found = False
                        break

            if found:
                self.kmem_cache_offset_node = candidate_offset
                self.quiet_info("offsetof(kmem_cache, node): {:#x}".format(self.kmem_cache_offset_node))
                break
        else:
            self.quiet_info("offsetof(kmem_cache, node): Not found")
            self.kmem_cache_offset_node = None

        # offsetof(page, next)
        self.page_offset_next = current_arch.ptrsize * 2
        self.quiet_info("offsetof(page, next): {:#x}".format(self.page_offset_next))

        # offsetof(page, freelist)
        self.page_offset_freelist = current_arch.ptrsize * 4
        self.quiet_info("offsetof(page, freelist): {:#x}".format(self.page_offset_freelist))

        # offsetof(page, slab_cache)
        self.page_offset_slab_cache = current_arch.ptrsize
        self.quiet_info("offsetof(page, slab_cache): {:#x}".format(self.page_offset_slab_cache))

        # offsetof(page, inuse_objects_frozen)
        self.page_offset_inuse_objects_frozen = self.page_offset_freelist + current_arch.ptrsize
        self.quiet_info("offsetof(page, inuse_objects_frozen): {:#x}".format(self.page_offset_inuse_objects_frozen))

        # offsetof(kmem_cache_node, partial)
        node = read_int_from_memory(kmem_caches[0] - self.kmem_cache_offset_list + self.kmem_cache_offset_node)
        for i in range(2, 16):
            offset_partial = current_arch.ptrsize * i
            if is_double_link_list(node + offset_partial):
                self.kmem_cache_node_offset_partial = offset_partial
                self.quiet_info("offsetof(kmem_cache_node, partial): {:#x}".format(self.kmem_cache_node_offset_partial))
                break
        else:
            self.quiet_info("offsetof(kmem_cache_node, partial): Not found")
            return False

        self.initialized = True
        return True

    def get_flags_str(self, flags_value):
        _flags = {
            "__OBJECT_POISON":         0x80000000,
            "__CMPXCHG_DOUBLE":        0x40000000,
            "SLAB_SKIP_KFENCE":        0x20000000,
            "SLAB_NO_USER_FLAGS":      0x10000000,
            "SLAB_KASAN":              0x08000000,
            "SLAB_ACCOUNT":            0x04000000,
            "SLAB_FAILSLAB":           0x02000000,
            "SLAB_NOTRACK":            0x01000000,
            "SLAB_NOLEAKTRACE":        0x00800000,
            "SLAB_DEBUG_OBJECTS":      0x00400000,
            "SLAB_TRACE":              0x00200000,
            "SLAB_MEM_SPREAD":         0x00100000,
            "SLAB_TYPESAFE_BY_RCU":    0x00080000,
            "SLAB_PANIC":              0x00040000,
            "SLAB_RECLAIM_ACCOUNT":    0x00020000,
            "SLAB_STORE_USER":         0x00010000,
            "SLAB_CACHE_DMA32":        0x00008000,
            "SLAB_CACHE_DMA":          0x00004000,
            "SLAB_HWCACHE_ALIGN":      0x00002000,
            "SLAB_KMALLOC":            0x00001000,
            "SLAB_POISON":             0x00000800,
            "SLAB_RED_ZONE":           0x00000400,
            "SLAB_DEBUG_INITIAL":      0x00000200, # kernel < v2.6.22
            "SLAB_CONSISTENCY_CHECKS": 0x00000100,
        }
        flags = []
        for k, v in _flags.items():
            if flags_value & v:
                flags.append(k)

        flags_str = " | ".join(flags)
        if flags_str == "":
            flags_str = "none"
        return flags_str

    def get_next_kmem_cache(self, addr, point_to_base=True):
        if point_to_base:
            addr += self.kmem_cache_offset_list
        return read_int_from_memory(addr) - self.kmem_cache_offset_list

    def get_name(self, addr):
        name_addr = read_int_from_memory(addr + self.kmem_cache_offset_name)
        return read_cstring_from_memory(name_addr)

    def page2virt(self, page, kmem_cache):
        if not self.args.skip_page2virt:
            ret = gdb.execute("page2virt {:#x}".format(page["address"]), to_string=True)
            r = re.search(r"Virt: (\S+)", ret)
            if r:
                return int(r.group(1), 16)

        # setup for heuristic search from freelist
        freelist = page["freelist"]
        freelist = [x for x in freelist if isinstance(x, int) and x != 0] # ignore str and last 0
        if not freelist:
            return None

        # heuristic detection pattern 1
        # freed chunks are scattered and can be confirmed on each of the pages
        page_heads = [x & gef_getpagesize_mask_high() for x in freelist]
        uniq_page_heads = list(set(page_heads))
        if page["num_pages"] == len(uniq_page_heads):
            return min(uniq_page_heads)

        # heuristic detection pattern 2
        # if there is only one pattern with good alignment, use it
        # e.g.: num_pages = 5
        # 0xXXXX0000
        # 0xXXXX1000   <----------------------------------- most_top_page   ^
        # 0xXXXX2000                                                       ^|
        # 0xXXXX3000   <-- chunk in freelist (min_page) ^                 ^||
        # 0xXXXX4000                                    | known_num_pages |||
        # 0xXXXX5000   <-- chunk in freelist (max_page) v                 ||v pattern 3
        # 0xXXXX6000                                                      |v pattern 2
        # 0xXXXX7000                                                      v pattern 1
        chunk_size = kmem_cache["size"]
        min_page = min(freelist) & gef_getpagesize_mask_high()
        max_page = max(freelist) & gef_getpagesize_mask_high()
        known_num_pages = ((max_page - min_page) // gef_getpagesize()) + 1
        unknown_num_pages = page["num_pages"] - known_num_pages
        most_top_page = min_page - (unknown_num_pages * gef_getpagesize())
        candidate_top_pages = range(most_top_page, min_page + gef_getpagesize(), gef_getpagesize())
        # alignment check for each candidate_top_pages
        valid_top_pages = []
        for cand_top in candidate_top_pages:
            for chunk in freelist:
                # divisible?
                if (chunk - cand_top) % chunk_size != 0:
                    break
            else:
                valid_top_pages.append(cand_top)
            # fast break if invalid
            if len(valid_top_pages) >= 2:
                break
        # confirm if there is only one valid pattern
        if len(valid_top_pages) == 1:
            return valid_top_pages[0]

        # not found
        return None

    def walk_freelist(self, chunk, kmem_cache):
        if self.args.simple:
            return [chunk]

        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")

        freelist = [chunk]
        while chunk:
            try:
                addr = chunk + kmem_cache["offset"]
                chunk = read_int_from_memory(addr) # get next chunk
            except gdb.MemoryError:
                freelist.append("{:s}".format(Color.colorify("Corrupted (Memory access denied)", corrupted_msg_color)))
                break
            if chunk % 8:
                freelist.append("{:#x}: {:s}".format(chunk, Color.colorify("Corrupted (Not aligned)", corrupted_msg_color)))
                break
            if chunk in freelist:
                freelist.append("{:#x}: {:s}".format(chunk, Color.colorify("Corrupted (Loop detected)", corrupted_msg_color)))
                break
            freelist.append(chunk)
        return freelist

    def walk_caches(self, target_names):
        current_kmem_cache = self.get_next_kmem_cache(self.slab_caches, point_to_base=False)
        parsed_caches = [{"name": "slab_caches", "next": current_kmem_cache}]

        # first, parse kmem_cache
        while current_kmem_cache + self.kmem_cache_offset_list != self.slab_caches:
            kmem_cache = {}
            # parse member
            kmem_cache["name"] = self.get_name(current_kmem_cache)
            if target_names != [] and kmem_cache["name"] not in target_names:
                current_kmem_cache = self.get_next_kmem_cache(current_kmem_cache)
                continue
            kmem_cache["address"] = current_kmem_cache
            kmem_cache["flags"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_flags, 4))
            kmem_cache["flags_str"] = self.get_flags_str(kmem_cache["flags"])
            kmem_cache["size"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_size, 4))
            kmem_cache["object_size"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_object_size, 4))
            kmem_cache["offset"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_offset, 4))
            kmem_cache["red_left_pad"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_red_left_pad, 4))
            kmem_cache["next"] = self.get_next_kmem_cache(current_kmem_cache)
            parsed_caches.append(kmem_cache)
            # goto next
            current_kmem_cache = kmem_cache["next"]

        if self.args.list:
            return parsed_caches

        # second, parse node then update
        tqdm = GefUtil.get_tqdm(not self.args.quiet)
        for kmem_cache in tqdm(parsed_caches[1:], leave=False): # parsed_caches[0] is slab_caches, so skip
            # parse node
            kmem_cache["nodes"] = []
            kmem_cache_node_array = kmem_cache["address"] + self.kmem_cache_offset_node
            current_kmem_cache_node_ptr = kmem_cache_node_array
            while True:
                current_kmem_cache_node = read_int_from_memory(current_kmem_cache_node_ptr)
                if current_kmem_cache_node == 0:
                    break
                if current_kmem_cache_node == current_kmem_cache_node_ptr:
                    break
                if current_kmem_cache_node & 0b111:
                    break
                node_page_list = []
                node_page_head = current_kmem_cache_node + self.kmem_cache_node_offset_partial
                if not is_valid_addr(node_page_head):
                    break
                current_node_page = read_int_from_memory(node_page_head)
                while current_node_page != node_page_head:
                    node_page = {}
                    node_page["address"] = current_node_page - self.page_offset_next
                    if not is_valid_addr(node_page["address"]):
                        node_page_list.append(node_page)
                        break
                    x = read_int_from_memory(node_page["address"] + self.page_offset_inuse_objects_frozen)
                    node_page["inuse"] = x & 0xffff
                    node_page["objects"] = (x >> 16) & 0x7fff
                    if node_page["objects"] == 0 or node_page["inuse"] > node_page["objects"]: # something is wrong
                        break
                    node_page["frozen"] = (x >> 31) & 1
                    node_chunk = read_int_from_memory(node_page["address"] + self.page_offset_freelist)
                    node_page["freelist"] = self.walk_freelist(node_chunk, kmem_cache)
                    node_page["num_pages"] = (kmem_cache["size"] * node_page["objects"] + gef_getpagesize_mask_low()) // gef_getpagesize()
                    node_page["virt_addr"] = self.page2virt(node_page, kmem_cache)
                    node_page_list.append(node_page)
                    current_node_page = read_int_from_memory(node_page["address"] + self.page_offset_next)
                kmem_cache["nodes"].append(node_page_list)
                current_kmem_cache_node_ptr += current_arch.ptrsize
        return parsed_caches

    def dump_page(self, page, kmem_cache, tag, freelist=None):
        label_active_color = Config.get_gef_setting("theme.heap_label_active")
        heap_page_color = Config.get_gef_setting("theme.heap_page_address")
        used_address_color = Config.get_gef_setting("theme.heap_chunk_address_used")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")

        # page address
        tag_s = Color.colorify("{:s} page".format(tag), label_active_color)
        self.out.append("      {:s}: {:#x}".format(tag_s, page["address"]))

        # fast return if invalid
        if not is_valid_addr(page["address"]):
            return

        # for partial or node page
        if freelist is None:
            freelist = page["freelist"]

        # print virtual address
        if page["virt_addr"] is None:
            self.out.append("        virtual address: ???")
        else:
            colored_virt_addr = Color.colorify_hex(page["virt_addr"], heap_page_color)
            self.out.append("        virtual address: {:s}".format(colored_virt_addr))

        # print info
        self.out.append("        num pages: {:d}".format(page["num_pages"]))

        if self.args.simple:
            return

        if tag == "active":
            freelist_len = len(freelist) - 1 # ignore last 0
            inuse = page["objects"] - freelist_len
        else:
            inuse = page["inuse"]
        self.out.append("        in-use: {:d}/{:d}".format(inuse, page["objects"]))
        self.out.append("        frozen: {:d}".format(page["frozen"]))

        # print layout
        if page["virt_addr"] is not None:
            end_virt = page["virt_addr"] + page["num_pages"] * gef_getpagesize()
            start_addr = page["virt_addr"] + kmem_cache["red_left_pad"]

            if kmem_cache["red_left_pad"]:
                chunk_s = Color.colorify_hex(page["virt_addr"], used_address_color)
                self.out.append("        {:7s}   {:#05x} {:s} ({:s})".format("layout:", 0, chunk_s, "never-used"))
                start_idx = 1
            else:
                start_idx = 0

            for idx, chunk in enumerate(range(start_addr, end_virt, kmem_cache["size"]), start=start_idx):
                if chunk in freelist[:-1]:
                    next_chunk = freelist[freelist.index(chunk) + 1]
                    if isinstance(next_chunk, str):
                        next_msg = "next: {:s}".format(next_chunk)
                    else:
                        next_msg = "next: {:#x}".format(next_chunk)
                    chunk_s = Color.colorify_hex(chunk, freed_address_color)
                else:
                    if page["objects"] <= idx:
                        next_msg = "never-used"
                    else:
                        next_msg = "in-use"
                    chunk_s = Color.colorify_hex(chunk, used_address_color)
                layout_msg = "layout:" if idx == 0 else ""
                self.out.append("        {:7s}   {:#05x} {:s} ({:s})".format(layout_msg, idx, chunk_s, next_msg))

                # dump chunks
                if self.args.hexdump_used and next_msg == "in-use":
                    peeked_data = read_memory(chunk, self.args.hexdump_used)
                    h = hexdump(peeked_data, 0x10, base=chunk, unit=current_arch.ptrsize)
                    self.out.append(h)

                if self.args.hexdump_freed and next_msg.startswith("next: "):
                    peeked_data = read_memory(chunk, self.args.hexdump_freed)
                    h = hexdump(peeked_data, 0x10, base=chunk, unit=current_arch.ptrsize)
                    self.out.append(h)

                if self.args.telescope_used and next_msg == "in-use":
                    n = self.args.telescope_used // current_arch.ptrsize
                    for i in range(n):
                        line = DereferenceCommand.pprint_dereferenced(chunk, i)
                        self.out.append(line)

                if self.args.telescope_freed and next_msg.startswith("next: "):
                    n = self.args.telescope_freed // current_arch.ptrsize
                    for i in range(n):
                        line = DereferenceCommand.pprint_dereferenced(chunk, i)
                        self.out.append(line)
        else:
            self.out.append("        layout: Failed to the get first page")

        # print freelist
        if freelist == [] or freelist == [0]:
            self.out.append("        freelist: (none)")
        else:
            for idx, chunk_addr in enumerate(freelist):
                if page["virt_addr"] is not None:
                    if chunk_addr == 0:
                        continue
                    if isinstance(chunk_addr, str):
                        chunk_idx = ""
                        msg = chunk_addr
                    else:
                        chunk_idx = (chunk_addr - page["virt_addr"]) // kmem_cache["size"]
                        if chunk_idx < 0 or page["objects"] <= chunk_idx:
                            chunk_idx = ""
                        else:
                            chunk_idx = "{:#05x}".format(chunk_idx)
                        msg = Color.colorify_hex(chunk_addr, freed_address_color)
                    freelist_msg = "freelist:" if idx == 0 else ""
                    self.out.append("        {:9s} {:5s} {:s}".format(freelist_msg, chunk_idx, msg))
                else:
                    if isinstance(chunk_addr, str):
                        msg = chunk_addr
                    else:
                        msg = Color.colorify_hex(chunk_addr, freed_address_color)
                    freelist_msg = "freelist:" if idx == 0 else ""
                    self.out.append("        {:9s}       {:s}".format(freelist_msg, msg))
        return

    def dump_caches(self, target_names, parsed_caches):
        chunk_label_color = Config.get_gef_setting("theme.heap_chunk_label")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")
        label_inactive_color = Config.get_gef_setting("theme.heap_label_inactive")

        self.out.append("slab_caches @ {:#x}".format(self.slab_caches))
        for kmem_cache in parsed_caches[1:]:
            if target_names != [] and kmem_cache["name"] not in target_names:
                continue

            # dump meta
            self.out.append("")
            self.out.append("  kmem_cache: {:#x}".format(kmem_cache["address"]))
            self.out.append("    name: {:s}".format(Color.colorify(kmem_cache["name"], chunk_label_color)))
            self.out.append("    flags: {:#x} ({:s})".format(kmem_cache["flags"], kmem_cache["flags_str"]))
            object_size_s = Color.colorify_hex(kmem_cache["object_size"], chunk_size_color)
            self.out.append("    object size: {:s} (chunk size: {:#x})".format(object_size_s, kmem_cache["size"]))
            self.out.append("    offset (next pointer in chunk): {:#x}".format(kmem_cache["offset"]))
            self.out.append("    red_left_pad: {:#x}".format(kmem_cache["red_left_pad"]))

            # dump nodes
            for node_index, node_page_list in enumerate(kmem_cache["nodes"]):
                node_addr = read_int_from_memory(kmem_cache["address"] + self.kmem_cache_offset_node + current_arch.ptrsize * node_index)
                self.out.append("    kmem_cache_node[{:d}]: {:#x}".format(node_index, node_addr))
                printed_count = 0
                for node_page in node_page_list:
                    self.dump_page(node_page, kmem_cache, "node")
                    printed_count += 1
                if printed_count == 0:
                    tag = Color.colorify("node pages", label_inactive_color)
                    self.out.append("      {:s}: (none)".format(tag))

            self.out.append("    next: {:#x}".format(kmem_cache["next"]))
        return

    def dump_names(self, parsed_caches):
        if not self.args.quiet:
            fmt = "{:<16s} {:<16s} {:30s} {:20s}"
            legend = ["Object Size", "Chunk Size", "Name", "kmem_cache"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
        for kmem_cache in sorted(parsed_caches[1:], key=lambda x: x["object_size"]):
            objsz = "{0:d} ({0:#x})".format(kmem_cache["object_size"])
            chunksz = "{0:d} ({0:#x})".format(kmem_cache["size"])
            chunk_name = kmem_cache["name"]
            address = kmem_cache["address"]
            self.out.append("{:16s} {:16s} {:30s} {:#x}".format(objsz, chunksz, chunk_name, address))
        return

    def slub_tiny_walk(self, target_names):
        if self.initialize() is False:
            self.quiet_err("Initialize failed")
            return

        if self.args.meta:
            return

        if self.args.list:
            parsed_caches = self.walk_caches(target_names)
            self.dump_names(parsed_caches)
            return

        parsed_caches = self.walk_caches(target_names)
        self.dump_caches(target_names, parsed_caches)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if not args.quiet:
            info("Wait for memory scan")

        if (is_x86() or is_arm32()) and not self.initialized and not args.skip_page2virt:
            # The slub-tiny-dump command is also called by page2virt and kmagic to determine vmemmap and sizeof(struct page).
            # Therefore, slub-tiny-dump itself may be called recursively (up to once) from slub-tiny-dump.
            # If a recursive call is made, various parameters held by self will be destroyed.
            # It's very tricky, but if we make sure to call page2virt first, no further calls will be made and
            # it will work without any problems.
            gdb.execute("page2virt 0", to_string=True)

        allocator = KernelChecksecCommand.get_slab_type()
        if allocator != "SLUB_TINY":
            if not args.quiet:
                err("Unsupported SLUB, SLAB, SLOB")
            return

        self.args = args
        self.maps = None
        self.out = []
        self.slub_tiny_walk(args.cache_name)
        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class SlabDumpCommand(GenericCommand):
    """Dump slab free-list."""
    _cmdline_ = "slab-dump"
    _category_ = "08-e. Qemu-system Cooperation - Linux Allocator"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("cache_name", metavar="SLAB_CACHE_NAME", nargs="*", help="filter by specific slab cache name.")
    parser.add_argument("--cpu", type=int, help="filter by specific cpu.")
    parser.add_argument("--list", action="store_true", help="list up all slab cache names.")
    parser.add_argument("--meta", action="store_true", help="display offset information.")
    parser.add_argument("-s", "--simple", action="store_true", help="skip displaying layout and freelist.")
    parser.add_argument("--skip-partial", action="store_true", help="skip displaying slabs_partial.")
    parser.add_argument("--skip-full", action="store_true", help="skip displaying slabs_full.")
    parser.add_argument("--skip-free", action="store_true", help="skip displaying slabs_free.")
    parser.add_argument("--hexdump-used", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="hexdump `used chunks` if layout is resolved.")
    parser.add_argument("--hexdump-freed", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="hexdump `unused (freed) chunks` if layout is resolved.")
    parser.add_argument("--telescope-used", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="telescope `used chunks` if layout is resolved.")
    parser.add_argument("--telescope-freed", metavar="SIZE", type=lambda x: int(x, 16), default=0,
                        help="telescope `unused (freed) chunks` if layout is resolved.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} kmalloc-256          # dump kmalloc-256 from all cpus\n".format(_cmdline_)
    _example_ += "{:s} kmalloc-256 --cpu 1  # dump kmalloc-256 from cpu 1\n".format(_cmdline_)
    _example_ += "{:s} --list               # list up slab cache names".format(_cmdline_)

    _note_ = "Simplified SLAB structure:\n"
    _note_ += "\n"
    _note_ += "                         +-kmem_cache--+         +-kmem_cache--+   +-kmem_cache--+\n"
    _note_ += "                         | cpu_cache   |---+     | cpu_cache   |   | cpu_cache   |\n"
    _note_ += "                         | limit       |   |     | limit       |   | limit       |\n"
    _note_ += "                         | size        |   |     | size        |   | size        |\n"
    _note_ += "                         | flags       |   |     | flags       |   | flags       |\n"
    _note_ += "                         | num         |   |     | num         |   | num         |\n"
    _note_ += "                         | gfporder    |   |     | gfporder    |   | gfporder    |\n"
    _note_ += "       +-slab_caches-+   | name        |   |     | name        |   | name        |\n"
    _note_ += " ...<->| list_head   |<->| list_head   |<------->| list_head   |<->| list_head   |<-> ...\n"
    _note_ += "       +-------------+   | object_size |   |     | object_size |   | object_size |\n"
    _note_ += "                         | node[]      |------+  | node[]      |   | node[]      |\n"
    _note_ += "                         +-------------+   |  |  +-------------+   +-------------+\n"
    _note_ += "    +-__per_cpu_offset-+                   |  |\n"
    _note_ += "    | cpu0_offset      |--+----------------+  |\n"
    _note_ += "    | cpu1_offset      |  |                   |\n"
    _note_ += "    | cpu2_offset      |  |                   v                  +-page------+    +-page------+\n"
    _note_ += "    | ...              |  |       +-kmem_cache_node-+      +---->| slab_list |--->| slab_list |-->...\n"
    _note_ += "    +------------------+  |       | slabs_partial   |------+     | freelist  |    | freelist  |\n"
    _note_ += "                          |       | slabs_full      |----->...   | s_mem     |-+  | s_mem     |-+\n"
    _note_ += "      +-------------------+       | slabs_free      |----->...   | active    | |  | active    | |\n"
    _note_ += "      |                           +-----------------+            +-----------+ |  +-----------+ |\n"
    _note_ += "      v                                                                        |                |\n"
    _note_ += "    +-array_cache--------+                                         +-----------+    +-----------+\n"
    _note_ += "    | avail              |                                         |                |\n"
    _note_ += "    | limit              |                                         v                v\n"
    _note_ += "    | entry[]            |                                       +-chunk--+       +-chunk--+\n"
    _note_ += "    |   freed_chunk_ptr  |-------------------------------------->|        |       |        |\n"
    _note_ += "    |   freed_chunk_ptr  |----------------------------+          +-chunk--+       +-chunk--+\n"
    _note_ += "    |   freed_chunk_ptr  |                            |          |        |       |        |\n"
    _note_ += "    |   freed_chunk_ptr  |                            |          +-chunk--+       +-chunk--+\n"
    _note_ += "    |   freed_chunk_ptr  |                            +--------->|        |       |        |\n"
    _note_ += "    |   ...              |                                       +-...----+       +-...----+\n"
    _note_ += "    +--------------------+\n"
    _note_ += "* Chunks in array_cache are marked as in-use, even though they are actually reusable."

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        return

    def quiet_err(self, msg):
        if not self.args.quiet:
            err(msg)
        return

    def quiet_info(self, msg):
        if not self.args.quiet:
            info(msg)
        return

    """
    struct kmem_cache {
        struct array_cache __percpu *cpu_cache;  // In fact, the offset value, not the pointer. if 3.18-rc1 <= kernel
        unsigned int batchcount;
        unsigned int limit;
        unsigned int shared;
        unsigned int size;
        struct reciprocal_value {
            u32 m;
            u8 sh1, sh2;
        } reciprocal_buffer_size;
        slab_flags_t flags;                      // unsigned int
        unsigned int num;
        unsigned int gfporder;
        gfp_t allocflags;                        // unsigned int
        size_t colour;
        unsigned int colour_off;
        struct kmem_cache *freelist_cache;       // if kernel < 6.1-rc1
        unsigned int freelist_size;
        void (*ctor)(void *obj);
        const char *name;
        struct list_head list;  <-----> struct list_head <-----> struct list_head <-----> ...
        int refcount;
        int object_size;
        int align;
        unsigned long num_active;                // if CONFIG_DEBUG_SLAB=y
        unsigned long num_allocations;           // if CONFIG_DEBUG_SLAB=y
        unsigned long high_mark;                 // if CONFIG_DEBUG_SLAB=y
        unsigned long grown;                     // if CONFIG_DEBUG_SLAB=y
        unsigned long reaped;                    // if CONFIG_DEBUG_SLAB=y
        unsigned long errors;                    // if CONFIG_DEBUG_SLAB=y
        unsigned long max_freeable;              // if CONFIG_DEBUG_SLAB=y
        unsigned long node_allocs;               // if CONFIG_DEBUG_SLAB=y
        unsigned long node_frees;                // if CONFIG_DEBUG_SLAB=y
        unsigned long node_overflow;             // if CONFIG_DEBUG_SLAB=y
        atomic_t allochit;                       // if CONFIG_DEBUG_SLAB=y
        atomic_t allocmiss;                      // if CONFIG_DEBUG_SLAB=y
        atomic_t freehit;                        // if CONFIG_DEBUG_SLAB=y
        atomic_t freemiss;                       // if CONFIG_DEBUG_SLAB=y
        atomic_t store_user_clean;               // if CONFIG_DEBUG_SLAB=y && CONFIG_DEBUG_SLAB_LEAK=y && 4.6-rc1 <= kernel < 5.2-rc1
        int obj_offset;                          // if CONFIG_DEBUG_SLAB=y
        struct memcg_cache_params memcg_params;  // if CONFIG_MEMCG=y && kernel < 5.9-rc1
        struct kasan_cache kasan_info;           // if CONFIG_KASAN=y && 4.6-rc1 <= kernel
        unsigned int *random_seq;                // if CONFIG_SLAB_FREELIST_RANDOM=y && 4.7-rc1 <= kernel
        unsigned int useroffset;                 // if 4.16-rc1 <= kernel
        unsigned int usersize;                   // if 4.16-rc1 <= kernel
        struct kmem_cache_node *node[MAX_NUMNODES]; // if 3.18-rc1 <= kernel
        struct kmem_cache_node **node;           // if kernel < 3.18-rc1
        struct array_cache *array[NR_CPUS + MAX_NUMNODES];  // if kernel < 3.18-rc1
    };

    struct array_cache {
        unsigned int avail;
        unsigned int limit;
        unsigned int batchcount;
        unsigned int touched;
        spinlock_t lock;                         // if kernel < 3.17-rc1
        void *entry[];
    };

    struct kmem_cache_node {
        raw_spinlock_t list_lock;
        struct list_head slabs_partial;
        struct list_head slabs_full;
        struct list_head slabs_free;
        unsigned long total_slabs;               // if 4.10-rc1 <= kernel
        unsigned long free_slabs;                // if 4.10-rc1 <= kernel
        unsigned long num_slabs;                 // if 4.9-rc1 <= kernel < 4.10-rc1
        unsigned long free_objects;
        unsigned int free_limit;
        unsigned int colour_next;
        struct array_cache *shared;
        struct alien_cache **alien;
        unsigned long next_reap;
        int free_touched;
    };

    struct page {                                // if kernel < 4.18-rc1
        unsigned long flags;
        void *s_mem;
        void *freelist;
        unsigned int active;
        atomic_t refcount;                       // if kernel < 4.16-rc1
        struct rcu_head rcu_head;
        struct kmem_cache *slab_cache;
        ...
    };

    struct page {                                // if 4.18-rc1 <= kernel < 5.17-rc1
        unsigned long flags;
        struct list_head slab_list;
        struct kmem_cache *slab_cache;
        void *freelist;
        void *s_mem;
        unsigned int active;
        ...
    };

    struct slab {                                // if kernel >= 5.17-rc1
        unsigned long __page_flags;
        struct kmem_cache *slab_cache;           // if kernel >= 6.2-rc1
        struct list_head slab_list;
        struct kmem_cache *slab_cache;           // if kernel < 6.2-rc1
        void *freelist;
        void *s_mem;
        unsigned int active;
        ...
    };
    """

    def initialize(self):
        if not self.args.meta and self.initialized:
            return True

        # resolve slab_caches
        self.slab_caches = KernelAddressHeuristicFinder.get_slab_caches()
        if self.slab_caches is None:
            self.quiet_err("Failed to resolve `slab_caches`")
            return False
        else:
            self.quiet_info("slab_caches: {:#x}".format(self.slab_caches))

        seen = [self.slab_caches]
        current = self.slab_caches
        while True:
            current = read_int_from_memory(current)
            if current in seen:
                break
            seen.append(current)
        kmem_caches = seen[1:]

        # resolve __per_cpu_offset
        __per_cpu_offset = KernelAddressHeuristicFinder.get_per_cpu_offset()
        if __per_cpu_offset is None:
            self.quiet_info("__per_cpu_offset: Not found")
            self.cpu_offset = []
            self.ncpus = 1
        else:
            self.quiet_info("__per_cpu_offset: {:#x}".format(__per_cpu_offset))
            self.cpu_offset = KernelCurrentCommand.get_each_cpu_offset(__per_cpu_offset)
            self.ncpus = len(self.cpu_offset)

        # offsetof(kmem_cache, list)
        kversion = Kernel.kernel_version()
        if kversion < "3.18":
            self.kmem_cache_offset_list = current_arch.ptrsize * 6 + 4 * 10
        elif kversion < "6.1":
            self.kmem_cache_offset_list = current_arch.ptrsize * 7 + 4 * 10
        else:
            self.kmem_cache_offset_list = current_arch.ptrsize * 4 + 4 * 12
        self.quiet_info("offsetof(kmem_cache, list): {:#x}".format(self.kmem_cache_offset_list))

        # offsetof(kmem_cache, name)
        self.kmem_cache_offset_name = self.kmem_cache_offset_list - current_arch.ptrsize
        self.quiet_info("offsetof(kmem_cache, name): {:#x}".format(self.kmem_cache_offset_name))

        # offsetof(kmem_cache, size)
        if kversion >= "3.18":
            self.kmem_cache_offset_size = current_arch.ptrsize + 4 * 3
        else:
            self.kmem_cache_offset_size = 4 * 3
        self.quiet_info("offsetof(kmem_cache, size): {:#x}".format(self.kmem_cache_offset_size))

        # offsetof(kmem_cache, flags)
        self.kmem_cache_offset_flags = self.kmem_cache_offset_size + 4 * 3
        self.quiet_info("offsetof(kmem_cache, flags): {:#x}".format(self.kmem_cache_offset_flags))

        # offsetof(kmem_cache, num)
        self.kmem_cache_offset_num = self.kmem_cache_offset_flags + 4
        self.quiet_info("offsetof(kmem_cache, num): {:#x}".format(self.kmem_cache_offset_num))

        # offsetof(kmem_cache, gfporder)
        self.kmem_cache_offset_gfporder = self.kmem_cache_offset_num + 4
        self.quiet_info("offsetof(kmem_cache, gfporder): {:#x}".format(self.kmem_cache_offset_gfporder))

        # offsetof(kmem_cache, object_size)
        self.kmem_cache_offset_object_size = self.kmem_cache_offset_list + current_arch.ptrsize * 2 + 4
        self.quiet_info("offsetof(kmem_cache, object_size): {:#x}".format(self.kmem_cache_offset_object_size))

        # offsetof(kmem_cache, node)
        if kversion < "4.16":
            self.kmem_cache_offset_node = self.kmem_cache_offset_object_size + 4 * 2 # heuristic could not use, so hard-coded
            self.quiet_info("offsetof(kmem_cache, node): {:#x}".format(self.kmem_cache_offset_node))
        else:
            # Search heuristically using useroffset and usersize as markers
            start_offset = self.kmem_cache_offset_list + current_arch.ptrsize * 2
            for candidate_offset in range(start_offset, start_offset + 0x100, 4):
                found = True
                for kmem_cache in kmem_caches:
                    user_offset = u32(read_memory(kmem_cache - self.kmem_cache_offset_list + candidate_offset, 4))
                    user_size = u32(read_memory(kmem_cache - self.kmem_cache_offset_list + candidate_offset + 4, 4))
                    object_size = u32(read_memory(kmem_cache - self.kmem_cache_offset_list + self.kmem_cache_offset_object_size, 4))
                    if user_offset == user_size == 0:
                        continue
                    if user_offset != 0 and user_size == 0:
                        found = False
                        break
                    if object_size < user_size:
                        found = False
                        break
                    node_addr_ptr = kmem_cache - self.kmem_cache_offset_list + candidate_offset + 4 + 4
                    node_addr_ptr = AddressUtil.align_address_to_size(node_addr_ptr, current_arch.ptrsize)
                    node_addr = read_int_from_memory(node_addr_ptr)
                    if not is_valid_addr(node_addr):
                        found = False
                        break

                if found:
                    self.kmem_cache_offset_node = AddressUtil.align_address_to_size(candidate_offset + 4 * 2, current_arch.ptrsize)
                    self.quiet_info("offsetof(kmem_cache, node): {:#x}".format(self.kmem_cache_offset_node))
                    break
            else:
                self.quiet_info("offsetof(kmem_cache, node): Not found")
                self.kmem_cache_offset_node = None

        if kversion >= "3.18":
            # offsetof(kmem_cache, cpu_cache)
            self.kmem_cache_offset_cpu_cache = 0
            self.quiet_info("offsetof(kmem_cache, cpu_cache): {:#x}".format(self.kmem_cache_offset_cpu_cache))
        else:
            self.kmem_cache_offset_array = self.kmem_cache_offset_node + current_arch.ptrsize
            self.quiet_info("offsetof(kmem_cache, array): {:#x}".format(self.kmem_cache_offset_array))

        # offsetof(page, next)
        kversion = Kernel.kernel_version()
        if kversion < "4.16":
            self.page_offset_next = current_arch.ptrsize * 3 + 4 * 2
        elif kversion < "4.18":
            self.page_offset_next = current_arch.ptrsize * 3 + 4
        elif kversion < "5.17":
            self.page_offset_next = current_arch.ptrsize
        elif kversion < "6.2":
            self.page_offset_next = current_arch.ptrsize
        else:
            self.page_offset_next = current_arch.ptrsize * 2
        self.quiet_info("offsetof(page, next): {:#x}".format(self.page_offset_next))

        # offsetof(page, freelist)
        if kversion < "4.18":
            self.page_offset_freelist = current_arch.ptrsize * 2
        elif kversion < "5.17":
            self.page_offset_freelist = current_arch.ptrsize * 4
        elif kversion < "6.2":
            self.page_offset_freelist = current_arch.ptrsize * 4
        else:
            self.page_offset_freelist = current_arch.ptrsize * 4
        self.quiet_info("offsetof(page, freelist): {:#x}".format(self.page_offset_freelist))

        # offsetof(page, slab_cache)
        if kversion < "4.16" and is_32bit():
            self.page_offset_slab_cache = current_arch.ptrsize * 7
        elif kversion < "4.18":
            self.page_offset_slab_cache = current_arch.ptrsize * 6
        elif kversion <= "5.17":
            self.page_offset_slab_cache = current_arch.ptrsize * 3
        elif kversion < "6.2":
            self.page_offset_slab_cache = current_arch.ptrsize * 3
        else:
            self.page_offset_slab_cache = current_arch.ptrsize
        self.quiet_info("offsetof(page, slab_cache): {:#x}".format(self.page_offset_slab_cache))

        # offsetof(page, s_mem)
        if kversion < "4.18":
            self.page_offset_s_mem = current_arch.ptrsize
        elif kversion < "5.17":
            self.page_offset_s_mem = current_arch.ptrsize * 5
        elif kversion < "6.2":
            self.page_offset_s_mem = 8 + current_arch.ptrsize * 5
        else:
            self.page_offset_s_mem = 8 + current_arch.ptrsize * 5
        self.quiet_info("offsetof(page, s_mem): {:#x}".format(self.page_offset_s_mem))

        # offsetof(page, active)
        if kversion < "4.18":
            self.page_offset_active = current_arch.ptrsize * 3
        elif kversion < "5.17":
            self.page_offset_active = current_arch.ptrsize * 6
        elif kversion < "6.2":
            self.page_offset_active = current_arch.ptrsize * 6
        else:
            self.page_offset_active = current_arch.ptrsize * 6
        self.quiet_info("offsetof(page, active): {:#x}".format(self.page_offset_active))

        # offsetof(kmem_cache_node, slabs_partial)
        # sizeof(raw_spinlock_t) can take many different values and must be determined heuristically.
        for candidate_offset in range(0, 0x80, current_arch.ptrsize):
            found = True
            for _kmem_cache in kmem_caches:
                kmem_cache = _kmem_cache - self.kmem_cache_offset_list
                if kversion >= "3.18":
                    kmem_cache_node_array = kmem_cache + self.kmem_cache_offset_node
                else:
                    kmem_cache_node_array = read_int_from_memory(kmem_cache + self.kmem_cache_offset_node)
                kmem_cache_node_0 = read_int_from_memory(kmem_cache_node_array)

                # slabs_partial
                if not is_double_link_list(kmem_cache_node_0 + candidate_offset + current_arch.ptrsize * 0):
                    found = False
                    break
                # slabs_full
                if not is_double_link_list(kmem_cache_node_0 + candidate_offset + current_arch.ptrsize * 2):
                    found = False
                    break
                # slabs_free
                if not is_double_link_list(kmem_cache_node_0 + candidate_offset + current_arch.ptrsize * 4):
                    found = False
                    break

            if found:
                self.kmem_cache_node_offset_slabs_partial = candidate_offset
                self.quiet_info("offsetof(kmem_cache_node, slabs_partial): {:#x}".format(self.kmem_cache_node_offset_slabs_partial))
                break
        else:
            self.quiet_info("offsetof(kmem_cache_node, slabs_partial): Not found")
            return False

        # offsetof(kmem_cache_node, slabs_full)
        self.kmem_cache_node_offset_slabs_full = self.kmem_cache_node_offset_slabs_partial + current_arch.ptrsize * 2
        self.quiet_info("offsetof(kmem_cache_node, slabs_full): {:#x}".format(self.kmem_cache_node_offset_slabs_full))

        # offsetof(kmem_cache_node, slabs_free)
        self.kmem_cache_node_offset_slabs_free = self.kmem_cache_node_offset_slabs_full + current_arch.ptrsize * 2
        self.quiet_info("offsetof(kmem_cache_node, slabs_free): {:#x}".format(self.kmem_cache_node_offset_slabs_free))

        # offsetof(array_cache, avail)
        self.array_cache_offset_avail = 0
        self.quiet_info("offsetof(array_cache, avail): {:#x}".format(self.array_cache_offset_avail))

        # offsetof(array_cache, limit)
        self.array_cache_offset_limit = 4
        self.quiet_info("offsetof(array_cache, limit): {:#x}".format(self.array_cache_offset_limit))

        # offsetof(array_cache, entry)
        if kversion >= "3.17":
            self.array_cache_offset_entry = 4 * 4
        else:
            sizeof_raw_spinlock_t = self.kmem_cache_node_offset_slabs_partial
            self.array_cache_offset_entry = 4 * 4 + sizeof_raw_spinlock_t
        self.quiet_info("offsetof(array_cache, entry): {:#x}".format(self.array_cache_offset_entry))

        self.initialized = True
        return True

    def get_flags_str(self, flags_value):
        _flags = {
            "__OBJECT_POISON":         0x80000000,
            "__CMPXCHG_DOUBLE":        0x40000000,
            "SLAB_SKIP_KFENCE":        0x20000000,
            "SLAB_NO_USER_FLAGS":      0x10000000,
            "SLAB_KASAN":              0x08000000,
            "SLAB_ACCOUNT":            0x04000000,
            "SLAB_FAILSLAB":           0x02000000,
            "SLAB_NOTRACK":            0x01000000,
            "SLAB_NOLEAKTRACE":        0x00800000,
            "SLAB_DEBUG_OBJECTS":      0x00400000,
            "SLAB_TRACE":              0x00200000,
            "SLAB_MEM_SPREAD":         0x00100000,
            "SLAB_TYPESAFE_BY_RCU":    0x00080000,
            "SLAB_PANIC":              0x00040000,
            "SLAB_RECLAIM_ACCOUNT":    0x00020000,
            "SLAB_STORE_USER":         0x00010000,
            "SLAB_CACHE_DMA32":        0x00008000,
            "SLAB_CACHE_DMA":          0x00004000,
            "SLAB_HWCACHE_ALIGN":      0x00002000,
            "SLAB_KMALLOC":            0x00001000,
            "SLAB_POISON":             0x00000800,
            "SLAB_RED_ZONE":           0x00000400,
            "SLAB_DEBUG_INITIAL":      0x00000200, # kernel < v2.6.22
            "SLAB_CONSISTENCY_CHECKS": 0x00000100,
        }
        flags = []
        for k, v in _flags.items():
            if flags_value & v:
                flags.append(k)

        flags_str = " | ".join(flags)
        if flags_str == "":
            flags_str = "none"
        return flags_str

    def get_next_kmem_cache(self, addr, point_to_base=True):
        if point_to_base:
            addr += self.kmem_cache_offset_list
        return read_int_from_memory(addr) - self.kmem_cache_offset_list

    def get_name(self, addr):
        name_addr = read_int_from_memory(addr + self.kmem_cache_offset_name)
        return read_cstring_from_memory(name_addr)

    def get_array_cache_cpu(self, addr, cpu):
        kversion = Kernel.kernel_version()
        if kversion >= "3.18":
            cpu_cache = read_int_from_memory(addr + self.kmem_cache_offset_cpu_cache)
            if len(self.cpu_offset) > 0:
                # __percpu
                return AddressUtil.align_address(cpu_cache + self.cpu_offset[cpu])
            else:
                # not __percpu
                return cpu_cache
        else:
            return read_int_from_memory(addr + self.kmem_cache_offset_array + current_arch.ptrsize * cpu)

    def walk_array_cache(self, array_cache, cpu, kmem_cache):
        if self.args.simple:
            return []

        freelist = []
        entry = array_cache + self.array_cache_offset_entry
        end = entry + kmem_cache["array_cache"][cpu]["avail"] * current_arch.ptrsize
        for current in range(entry, end, current_arch.ptrsize):
            chunk = read_int_from_memory(current)
            freelist.append(chunk)
        return freelist

    def walk_node_list(self, node_page_head, current_node_page, kmem_cache):
        kversion = Kernel.kernel_version()
        node_page_list = []
        seen = [] # avoid infinity loop
        while current_node_page != node_page_head:
            if current_node_page in seen:
                break
            seen.append(current_node_page)
            node_page = {}
            node_page["address"] = current_node_page - self.page_offset_next
            if not is_valid_addr(node_page["address"]):
                node_page_list.append(node_page)
                break
            node_page["s_mem"] = read_int_from_memory(node_page["address"] + self.page_offset_s_mem)
            node_page["s_mem_base"] = node_page["s_mem"] & gef_getpagesize_mask_high()

            if not self.args.simple:
                freelist_addr = read_int_from_memory(node_page["address"] + self.page_offset_freelist)
                if is_valid_addr(freelist_addr):
                    active = u32(read_memory(node_page["address"] + self.page_offset_active, 4))
                    if kversion >= "3.15":
                        freelist_byteseq = read_memory(freelist_addr, kmem_cache["objperslab"])
                        node_page["freelist"] = list(freelist_byteseq[active:])
                    else:
                        freelist_intseq = read_memory(freelist_addr, kmem_cache["objperslab"] * 4)
                        node_page["freelist"] = slice_unpack(freelist_intseq, current_arch.ptrsize)[active:]
                else:
                    node_page["freelist"] = []

            node_page_list.append(node_page)
            current_node_page = read_int_from_memory(node_page["address"] + self.page_offset_next)
        return node_page_list

    def walk_caches(self, target_names, cpus):
        kversion = Kernel.kernel_version()
        current_kmem_cache = self.get_next_kmem_cache(self.slab_caches, point_to_base=False)
        parsed_caches = [{"name": "slab_caches", "next": current_kmem_cache}]

        # first, parse kmem_cache
        while current_kmem_cache + self.kmem_cache_offset_list != self.slab_caches:
            kmem_cache = {}
            # parse member
            kmem_cache["name"] = self.get_name(current_kmem_cache)
            if target_names != [] and kmem_cache["name"] not in target_names:
                current_kmem_cache = self.get_next_kmem_cache(current_kmem_cache)
                continue
            kmem_cache["address"] = current_kmem_cache
            kmem_cache["flags"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_flags, 4))
            kmem_cache["flags_str"] = self.get_flags_str(kmem_cache["flags"])
            kmem_cache["size"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_size, 4))
            kmem_cache["object_size"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_object_size, 4))
            kmem_cache["objperslab"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_num, 4))
            gfporder = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_gfporder, 4))
            kmem_cache["pagesperslab"] = 1 << gfporder
            kmem_cache["next"] = self.get_next_kmem_cache(current_kmem_cache)
            parsed_caches.append(kmem_cache)
            # goto next
            current_kmem_cache = kmem_cache["next"]

        if self.args.list:
            return parsed_caches

        # second, parse array_cache and node
        tqdm = GefUtil.get_tqdm(not self.args.quiet)
        for kmem_cache in tqdm(parsed_caches[1:], leave=False): # parsed_caches[0] is slab_caches, so skip
            # parse array_cache
            kmem_cache["array_cache"] = {}
            kmem_cache["array_cache"]["freelist_all"] = []
            for cpu in cpus:
                kmem_cache["array_cache"][cpu] = {}
                if is_valid_addr(self.get_array_cache_cpu(kmem_cache["address"], cpu)):
                    kmem_cache["array_cache"][cpu]["address"] = array_cache = self.get_array_cache_cpu(kmem_cache["address"], cpu)
                    kmem_cache["array_cache"][cpu]["avail"] = u32(read_memory(array_cache + self.array_cache_offset_avail, 4))
                    kmem_cache["array_cache"][cpu]["limit"] = u32(read_memory(array_cache + self.array_cache_offset_limit, 4))
                    kmem_cache["array_cache"][cpu]["freelist"] = self.walk_array_cache(array_cache, cpu, kmem_cache)
                    kmem_cache["array_cache"]["freelist_all"].extend(kmem_cache["array_cache"][cpu]["freelist"])

            # parse node
            kmem_cache["nodes"] = []
            if kversion >= "3.18":
                kmem_cache_node_array = kmem_cache["address"] + self.kmem_cache_offset_node
            else:
                kmem_cache_node_array = read_int_from_memory(kmem_cache["address"] + self.kmem_cache_offset_node)
            current_kmem_cache_node_ptr = kmem_cache_node_array
            while True:
                # 3.18 or after: node is array (node[MAX_NUMNODES]), so need loop until invalid address
                current_kmem_cache_node = read_int_from_memory(current_kmem_cache_node_ptr)
                if not is_valid_addr(current_kmem_cache_node):
                    break
                slabs_list = {}

                node_page_head = current_kmem_cache_node + self.kmem_cache_node_offset_slabs_partial
                if is_valid_addr(node_page_head):
                    current_node_page = read_int_from_memory(node_page_head)
                    slabs_list["slabs_partial"] = self.walk_node_list(node_page_head, current_node_page, kmem_cache)

                node_page_head = current_kmem_cache_node + self.kmem_cache_node_offset_slabs_full
                if is_valid_addr(node_page_head):
                    current_node_page = read_int_from_memory(node_page_head)
                    slabs_list["slabs_full"] = self.walk_node_list(node_page_head, current_node_page, kmem_cache)

                node_page_head = current_kmem_cache_node + self.kmem_cache_node_offset_slabs_free
                if is_valid_addr(node_page_head):
                    current_node_page = read_int_from_memory(node_page_head)
                    slabs_list["slabs_free"] = self.walk_node_list(node_page_head, current_node_page, kmem_cache)

                kmem_cache["nodes"].append(slabs_list)

                if kversion < "3.18":
                    # 3.17 or before: node is single element (**node), so skip loop
                    break
                current_kmem_cache_node_ptr += current_arch.ptrsize
        return parsed_caches

    def dump_page(self, page, kmem_cache, tag):
        heap_page_color = Config.get_gef_setting("theme.heap_page_address")
        label_inactive_color = Config.get_gef_setting("theme.heap_label_inactive")
        used_address_color = Config.get_gef_setting("theme.heap_chunk_address_used")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")

        # page address
        tag_s = Color.colorify(tag, label_inactive_color)
        self.out.append("      {:s}: {:#x}".format(tag_s, page["address"]))

        # fast return if invalid
        if not is_valid_addr(page["address"]):
            return

        # print virtual address
        colored_s_mem_base = Color.colorify_hex(page["s_mem_base"], heap_page_color)
        self.out.append("        virtual address (s_mem & ~0xfff): {:s}".format(colored_s_mem_base))

        # print info
        self.out.append("        num pages: {:d}".format(kmem_cache["pagesperslab"]))

        colour_off = page["s_mem"] - page["s_mem_base"]
        self.out.append("        colour offset: {:#x}".format(colour_off))

        if self.args.simple:
            return

        # print layout
        freelist = page["freelist"]
        end_virt = page["s_mem_base"] + kmem_cache["pagesperslab"] * gef_getpagesize()

        if colour_off:
            chunk_s = Color.colorify_hex(page["s_mem_base"], used_address_color)
            self.out.append("        {:7s}   {:#04x} {:s} ({:s})".format("layout:", 0, chunk_s, "never-used"))
            start_idx = 1
        else:
            start_idx = 0

        for idx, chunk in enumerate(range(page["s_mem"], end_virt, kmem_cache["size"]), start=start_idx):
            if idx in freelist:
                idxidx = freelist.index(idx)
                if idxidx == len(freelist) - 1:
                    next_msg = "next: None"
                else:
                    next_idx = freelist[idxidx + 1]
                    next_msg = "next: {:#x}".format(next_idx)
                chunk_s = Color.colorify_hex(chunk, freed_address_color)
            elif "array_cache" in kmem_cache and chunk in kmem_cache["array_cache"]["freelist_all"]:
                next_msg = "in-use (array_cache)"
                chunk_s = Color.colorify_hex(chunk, freed_address_color)
            else:
                if kmem_cache["objperslab"] <= idx:
                    next_msg = "never-used"
                else:
                    next_msg = "in-use"
                chunk_s = Color.colorify_hex(chunk, used_address_color)
            self.out.append("        {:7s}   {:#04x} {:s} ({:s})".format("layout:" if idx == 0 else "", idx, chunk_s, next_msg))

            # dump chunks
            if self.args.hexdump_used and next_msg == "in-use":
                peeked_data = read_memory(chunk, self.args.hexdump_used)
                h = hexdump(peeked_data, 0x10, base=chunk, unit=current_arch.ptrsize)
                self.out.append(h)

            if self.args.hexdump_freed and next_msg.startswith(("next: ", "in-use (array_cache)")):
                peeked_data = read_memory(chunk, self.args.hexdump_freed)
                h = hexdump(peeked_data, 0x10, base=chunk, unit=current_arch.ptrsize)
                self.out.append(h)

            if self.args.telescope_used and next_msg == "in-use":
                n = self.args.telescope_used // current_arch.ptrsize
                for i in range(n):
                    line = DereferenceCommand.pprint_dereferenced(chunk, i)
                    self.out.append(line)

            if self.args.telescope_freed and next_msg.startswith(("next: ", "in-use (array_cache)")):
                n = self.args.telescope_freed // current_arch.ptrsize
                for i in range(n):
                    line = DereferenceCommand.pprint_dereferenced(chunk, i)
                    self.out.append(line)

        # print freelist
        if freelist == []:
            self.out.append("        freelist: (none)")
        else:
            for i, idx in enumerate(freelist):
                chunk = page["s_mem"] + kmem_cache["size"] * idx
                msg = Color.colorify_hex(chunk, freed_address_color)
                self.out.append("        {:9s} {:#04x} {:s}".format("freelist:" if i == 0 else "", idx, msg))
        return

    def dump_array_cache(self, cpu, kmem_cache):
        label_active_color = Config.get_gef_setting("theme.heap_label_active")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")

        tag_s = Color.colorify("array_cache (cpu{:d})".format(cpu), label_active_color)
        if "array_cache" not in kmem_cache:
            self.out.append("      {:s}: (none)".format(tag_s))
            return
        self.out.append("      {:s}: {:#x}".format(tag_s, kmem_cache["array_cache"][cpu]["address"]))

        self.out.append("        avail: {:d}".format(kmem_cache["array_cache"][cpu]["avail"]))
        self.out.append("        limit: {:d}".format(kmem_cache["array_cache"][cpu]["limit"]))

        if self.args.simple:
            return

        freelist = kmem_cache["array_cache"][cpu]["freelist"]
        if freelist == []:
            self.out.append("        entry: (none)")
        else:
            for idx, f in enumerate(freelist):
                if not is_valid_addr(f):
                    break
                msg = Color.colorify_hex(f, freed_address_color)
                self.out.append("        {:6s} {:s}".format("entry:" if idx == 0 else "", msg))
        return

    def dump_caches(self, target_names, cpus, parsed_caches):
        chunk_label_color = Config.get_gef_setting("theme.heap_chunk_label")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")
        label_inactive_color = Config.get_gef_setting("theme.heap_label_inactive")

        self.out.append("slab_caches @ {:#x}".format(self.slab_caches))
        for kmem_cache in parsed_caches[1:]:
            if target_names != [] and kmem_cache["name"] not in target_names:
                continue

            # dump meta
            self.out.append("")
            self.out.append("  kmem_cache: {:#x}".format(kmem_cache["address"]))
            self.out.append("    name: {:s}".format(Color.colorify(kmem_cache["name"], chunk_label_color)))
            self.out.append("    flags: {:#x} ({:s})".format(kmem_cache["flags"], kmem_cache["flags_str"]))
            object_size_s = Color.colorify_hex(kmem_cache["object_size"], chunk_size_color)
            self.out.append("    object size: {:s} (chunk size: {:#x})".format(object_size_s, kmem_cache["size"]))
            self.out.append("    object per slab: {:#x}".format(kmem_cache["objperslab"]))
            self.out.append("    pages per slab: {:#x}".format(kmem_cache["pagesperslab"]))

            # dump array_cache
            for cpu in cpus:
                self.dump_array_cache(cpu, kmem_cache)

            # dump nodes
            if len(kmem_cache["nodes"]) == 0:
                self.out.append("      {:s}: (none)".format(Color.colorify("node pages", label_inactive_color)))
            else:
                for node_index, slabs_list in enumerate(kmem_cache["nodes"]):
                    node_addr = read_int_from_memory(kmem_cache["address"] + self.kmem_cache_offset_node + current_arch.ptrsize * node_index)
                    self.out.append("    kmem_cache_node[{:d}]: {:#x}".format(node_index, node_addr))

                    if not self.args.skip_partial and "slabs_partial" in slabs_list:
                        if len(slabs_list["slabs_partial"]) == 0:
                            tag = Color.colorify("node[{:d}].slabs_partial".format(node_index), label_inactive_color)
                            self.out.append("      {:s}: (none)".format(tag))
                        else:
                            for node_page in slabs_list["slabs_partial"]:
                                self.dump_page(node_page, kmem_cache, tag="node[{:d}].slabs_partial".format(node_index))

                    if not self.args.skip_full and "slabs_full" in slabs_list:
                        if len(slabs_list["slabs_full"]) == 0:
                            tag = Color.colorify("node[{:d}].slabs_full".format(node_index), label_inactive_color)
                            self.out.append("      {:s}: (none)".format(tag))
                        else:
                            for node_page in slabs_list["slabs_full"]:
                                self.dump_page(node_page, kmem_cache, tag="node[{:d}].slabs_full".format(node_index))

                    if not self.args.skip_free and "slabs_free" in slabs_list:
                        if len(slabs_list["slabs_free"]) == 0:
                            tag = Color.colorify("node[{:d}].slabs_free".format(node_index), label_inactive_color)
                            self.out.append("      {:s}: (none)".format(tag))
                        else:
                            for node_page in slabs_list["slabs_free"]:
                                self.dump_page(node_page, kmem_cache, tag="node[{:d}].slabs_free".format(node_index))

            self.out.append("    next: {:#x}".format(kmem_cache["next"]))
        return

    def dump_names(self, parsed_caches):
        if not self.quiet:
            fmt = "{:<16s} {:<16s} {:30s} {:20s}"
            legend = ["Object Size", "Chunk Size", "Name", "kmem_cache"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
        for kmem_cache in sorted(parsed_caches[1:], key=lambda x: x["object_size"]):
            objsz = "{0:d} ({0:#x})".format(kmem_cache["object_size"])
            chunksz = "{0:d} ({0:#x})".format(kmem_cache["size"])
            chunk_name = kmem_cache["name"]
            address = kmem_cache["address"]
            self.out.append("{:16s} {:16s} {:30s} {:#x}".format(objsz, chunksz, chunk_name, address))
        return

    def slabwalk(self, target_names, cpu):
        if self.initialize() is False:
            self.quiet_err("Initialize failed")
            return

        if self.args.meta:
            return

        if self.args.list:
            parsed_caches = self.walk_caches(target_names, cpus=None)
            self.dump_names(parsed_caches)
            return

        if cpu is None:
            target_cpus = list(range(self.ncpus))
        else:
            if self.ncpus <= cpu:
                self.quiet_err("CPU number is invalid (valid range: {:d}-{:d})".format(0, self.ncpus - 1))
                return
            target_cpus = [cpu]

        parsed_caches = self.walk_caches(target_names, target_cpus)
        self.dump_caches(target_names, target_cpus, parsed_caches)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if not args.quiet:
            info("Wait for memory scan")

        allocator = KernelChecksecCommand.get_slab_type()
        if allocator != "SLAB":
            if not args.quiet:
                err("Unsupported SLUB, SLOB, SLUB_TINY")
            return

        self.args = args
        self.maps = None
        self.out = []
        self.slabwalk(args.cache_name, args.cpu)
        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class SlobDumpCommand(GenericCommand):
    """Dump slob free-list."""
    _cmdline_ = "slob-dump"
    _category_ = "08-e. Qemu-system Cooperation - Linux Allocator"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("cache_name", metavar="SLOB_CACHE_NAME", nargs="*",
                        help="filter by specific slob cache name (need -v option).")
    parser.add_argument("--list", action="store_true", help="list up all slob cache names.")
    parser.add_argument("--meta", action="store_true", help="display offset information.")
    parser.add_argument("-s", "--simple", action="store_true", help="skip showing freelist.")
    parser.add_argument("--large", action="store_true", help="display only free_slob_large.")
    parser.add_argument("--medium", action="store_true", help="display only free_slob_medium.")
    parser.add_argument("--small", action="store_true", help="display only free_slob_small.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="enable verbose mode (print kmem_cache).")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} kmalloc-256  # dump kmalloc-256 kmem_cache and all freelists\n".format(_cmdline_)
    _example_ += "{:s} --list       # list up slob cache names".format(_cmdline_)

    _note_ = "Simplified SLOB structure:\n"
    _note_ += "\n"
    _note_ += "                         +-kmem_cache--+   +-kmem_cache--+   +-kmem_cache--+\n"
    _note_ += "                         | object_size |   | object_size |   | object_size |\n"
    _note_ += "                         | size        |   | size        |   | size        |\n"
    _note_ += "                         | flags       |   | flags       |   | flags       |\n"
    _note_ += "       +-slab_caches-+   | name        |   | name        |   | name        |\n"
    _note_ += " ...<->| list_head   |<->| list_head   |<->| list_head   |<->| list_head   |<-> ...\n"
    _note_ += "       +-------------+   +-------------+   +-------------+   +-------------+\n"
    _note_ += "* slab_caches is not used when traversing the freelist\n"
    _note_ += "\n"
    _note_ += "   +-free_slob_large--+              +-page----------+           +-page----------+\n"
    _note_ += "   | list_head        |<---------+   | freelist      |-----+     | freelist      |\n"
    _note_ += "   +-free_slob_medium-+          |   | units (total) |     |     | units (total) |\n"
    _note_ += "   | list_head        |-->...    +-->| list_head     |<----|---->| list_head     |<->...\n"
    _note_ += "   +-free_slob_small--+              +---------------+     |     +---------------+\n"
    _note_ += "   | list_head        |-->...                              |\n"
    _note_ += "   +------------------+                      +-------------+\n"
    _note_ += "   small : size < 0x100                      |\n"
    _note_ += "   medium: 0x100 <= size < 0x400             |   +-chunk-----+   +-chunk-----+\n"
    _note_ += "   large : 0x400 <= size < 0x1000            +-->| units     |-->| -offset   |-->...\n"
    _note_ += "* size is only judged when first inserted,       | offset    |   +-----------+\n"
    _note_ += "  so divided remainder is stay on                +-----------+   (when units=1, stored negative offset)"

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        return

    def quiet_err(self, msg):
        if not self.args.quiet:
            err(msg)
        return

    def quiet_info(self, msg):
        if not self.args.quiet:
            info(msg)
        return

    """
    struct kmem_cache {
        unsigned int object_size;
        unsigned int size;
        unsigned int align;
        slab_flags_t flags;                      // unsigned int
        unsigned int useroffset;                 // if 4.16-rc1 <= kernel
        unsigned int usersize;                   // if 4.16-rc1 <= kernel
        const char *name;
        int refcount;
        void (*ctor)(void *);
        struct list_head list;
    };

    struct page {                                // if kernel < 4.18-rc1
        unsigned long flags;
        void *__unused_1;
        void *freelist;
        int units;
        atomic_t refcount;                       // if kernel < 4.16-rc1
        struct list_head lru;
        ...
    };

    struct page {                                // if 4.18-rc1 <= kernel < 5.17-rc1
        unsigned long flags;
        struct list_head lru;
        struct kmem_cache *__unused_1;
        void *freelist;
        void *__unused_2;
        int units;
        ...
    };

    struct slab {                                // if kernel >= 5.17-rc1
        unsigned long __page_flags;
        struct list_head slab_list;
        void *__unused_1;
        void *freelist
        long units;
        unsigned int __unused_2;
    };
    """

    def initialize(self):
        if not self.args.meta and self.initialized:
            return True

        # resolve slab_caches
        self.slab_caches = KernelAddressHeuristicFinder.get_slab_caches()
        if self.slab_caches is None:
            self.quiet_err("Failed to resolve `slab_caches`")
            return False
        else:
            self.quiet_info("slab_caches: {:#x}".format(self.slab_caches))

        # resolve global freelists
        self.free_slob_large = Symbol.get_ksymaddr("free_slob_large")
        if self.free_slob_large is None:
            self.quiet_err("Failed to resolve `free_slob_large`")
            return False
        else:
            self.quiet_info("free_slob_large: {:#x}".format(self.free_slob_large))

        self.free_slob_medium = Symbol.get_ksymaddr("free_slob_medium")
        if self.free_slob_medium is None:
            self.quiet_err("Failed to resolve `free_slob_medium`")
            return False
        else:
            self.quiet_info("free_slob_medium: {:#x}".format(self.free_slob_medium))

        self.free_slob_small = Symbol.get_ksymaddr("free_slob_small")
        if self.free_slob_small is None:
            self.quiet_err("Failed to resolve `free_slob_small`")
            return False
        else:
            self.quiet_info("free_slob_small: {:#x}".format(self.free_slob_small))

        # offsetof(kmem_cache, list)
        kversion = Kernel.kernel_version()
        if kversion < "4.16":
            self.kmem_cache_offset_list = current_arch.ptrsize * 3 + 4 * 4
        else:
            self.kmem_cache_offset_list = current_arch.ptrsize * 3 + 4 * 6
        self.quiet_info("offsetof(kmem_cache, list): {:#x}".format(self.kmem_cache_offset_list))

        # offsetof(kmem_cache, name)
        self.kmem_cache_offset_name = self.kmem_cache_offset_list - current_arch.ptrsize * 3
        self.quiet_info("offsetof(kmem_cache, name): {:#x}".format(self.kmem_cache_offset_name))

        # offsetof(kmem_cache, object_size)
        self.kmem_cache_offset_object_size = 0
        self.quiet_info("offsetof(kmem_cache, object_size): {:#x}".format(self.kmem_cache_offset_object_size))

        # offsetof(kmem_cache, size)
        self.kmem_cache_offset_size = 4
        self.quiet_info("offsetof(kmem_cache, size): {:#x}".format(self.kmem_cache_offset_size))

        # offsetof(kmem_cache, flags)
        self.kmem_cache_offset_flags = 4 * 3
        self.quiet_info("offsetof(kmem_cache, flags): {:#x}".format(self.kmem_cache_offset_flags))

        # offsetof(page, next)
        kversion = Kernel.kernel_version()
        if kversion < "4.16":
            self.page_offset_next = current_arch.ptrsize * 3 + 4 * 2
        elif kversion < "4.18":
            self.page_offset_next = current_arch.ptrsize * 4
        elif kversion < "5.17":
            self.page_offset_next = current_arch.ptrsize
        else:
            self.page_offset_next = current_arch.ptrsize
        self.quiet_info("offsetof(page, next): {:#x}".format(self.page_offset_next))

        # offsetof(page, freelist)
        if kversion < "4.18":
            self.page_offset_freelist = current_arch.ptrsize * 2
        elif kversion < "5.17":
            self.page_offset_freelist = current_arch.ptrsize * 4
        else:
            self.page_offset_freelist = current_arch.ptrsize * 4
        self.quiet_info("offsetof(page, freelist): {:#x}".format(self.page_offset_freelist))

        # offsetof(page, units)
        if kversion < "4.18":
            self.page_offset_units = current_arch.ptrsize * 3
        elif kversion < "5.17":
            self.page_offset_freelist = current_arch.ptrsize * 6
        else:
            self.page_offset_freelist = current_arch.ptrsize * 5
        self.quiet_info("offsetof(page, units): {:#x}".format(self.page_offset_units))

        self.initialized = True
        return True

    def get_flags_str(self, flags_value):
        _flags = {
            "__OBJECT_POISON":         0x80000000,
            "__CMPXCHG_DOUBLE":        0x40000000,
            "SLAB_SKIP_KFENCE":        0x20000000,
            "SLAB_NO_USER_FLAGS":      0x10000000,
            "SLAB_KASAN":              0x08000000,
            "SLAB_ACCOUNT":            0x04000000,
            "SLAB_FAILSLAB":           0x02000000,
            "SLAB_NOTRACK":            0x01000000,
            "SLAB_NOLEAKTRACE":        0x00800000,
            "SLAB_DEBUG_OBJECTS":      0x00400000,
            "SLAB_TRACE":              0x00200000,
            "SLAB_MEM_SPREAD":         0x00100000,
            "SLAB_TYPESAFE_BY_RCU":    0x00080000,
            "SLAB_PANIC":              0x00040000,
            "SLAB_RECLAIM_ACCOUNT":    0x00020000,
            "SLAB_STORE_USER":         0x00010000,
            "SLAB_CACHE_DMA32":        0x00008000,
            "SLAB_CACHE_DMA":          0x00004000,
            "SLAB_HWCACHE_ALIGN":      0x00002000,
            "SLAB_KMALLOC":            0x00001000,
            "SLAB_POISON":             0x00000800,
            "SLAB_RED_ZONE":           0x00000400,
            "SLAB_DEBUG_INITIAL":      0x00000200, # kernel < v2.6.22
            "SLAB_CONSISTENCY_CHECKS": 0x00000100,
        }
        flags = []
        for k, v in _flags.items():
            if flags_value & v:
                flags.append(k)

        flags_str = " | ".join(flags)
        if flags_str == "":
            flags_str = "none"
        return flags_str

    def get_next_kmem_cache(self, addr, point_to_base=True):
        if point_to_base:
            addr += self.kmem_cache_offset_list
        return read_int_from_memory(addr) - self.kmem_cache_offset_list

    def get_name(self, addr):
        name_addr = read_int_from_memory(addr + self.kmem_cache_offset_name)
        return read_cstring_from_memory(name_addr)

    def walk_freelist(self, head, page):
        if self.args.simple:
            return []

        freelist = []
        current = head
        while True:
            base = current & gef_getpagesize_mask_high()
            units = struct.unpack("<h", read_memory(current, 2))[0]
            if units < 0:
                next = -units
                units = 1
            else:
                next = struct.unpack("<h", read_memory(current + 2, 2))[0]
            freelist.append([current, units])
            current = base + next * 2
            if (current & 0xfff) == 0:
                break
        return freelist

    def walk_page_freelist(self, head):
        seen = [head]
        page_freelist = []
        current = read_int_from_memory(head)
        while True:
            seen.append(current)
            page = {}
            page["address"] = current - self.page_offset_next
            page["units"] = u32(read_memory(page["address"] + self.page_offset_units, 4))
            freelist_head = read_int_from_memory(page["address"] + self.page_offset_freelist)
            page["virt_addr"] = freelist_head & gef_getpagesize_mask_high()
            page["num_pages"] = 1
            page["freelist"] = self.walk_freelist(freelist_head, page)
            page["next"] = next = read_int_from_memory(current)
            page_freelist.append(page)
            if next in seen:
                break
            current = next
        return page_freelist

    def walk_caches(self, target_names):
        current_kmem_cache = self.get_next_kmem_cache(self.slab_caches, point_to_base=False)
        parsed_caches = [{"name": "slab_caches", "next": current_kmem_cache}]

        while current_kmem_cache + self.kmem_cache_offset_list != self.slab_caches:
            kmem_cache = {}
            # parse member
            kmem_cache["name"] = self.get_name(current_kmem_cache)
            if target_names != [] and kmem_cache["name"] not in target_names:
                current_kmem_cache = self.get_next_kmem_cache(current_kmem_cache)
                continue
            kmem_cache["address"] = current_kmem_cache
            kmem_cache["flags"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_flags, 4))
            kmem_cache["flags_str"] = self.get_flags_str(kmem_cache["flags"])
            kmem_cache["size"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_size, 4))
            kmem_cache["object_size"] = u32(read_memory(current_kmem_cache + self.kmem_cache_offset_object_size, 4))
            kmem_cache["next"] = self.get_next_kmem_cache(current_kmem_cache)
            parsed_caches.append(kmem_cache)
            # goto next
            current_kmem_cache = kmem_cache["next"]

        if self.args.list:
            return parsed_caches, None

        parsed_freelist = {}
        if self.large:
            parsed_freelist["large"] = self.walk_page_freelist(self.free_slob_large)
        if self.medium:
            parsed_freelist["medium"] = self.walk_page_freelist(self.free_slob_medium)
        if self.small:
            parsed_freelist["small"] = self.walk_page_freelist(self.free_slob_small)

        return parsed_caches, parsed_freelist

    def dump_freelist(self, tag, page_freelist):
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")
        label_active_color = Config.get_gef_setting("theme.heap_label_active")
        heap_page_color = Config.get_gef_setting("theme.heap_page_address")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")

        self.out.append(titlify("{:s} @ {:#x}".format(tag, getattr(self, tag))))

        for page in page_freelist:
            self.out.append("  {:s}: {:#x}".format(Color.colorify("page", label_active_color), page["address"]))
            colored_virt_addr = Color.colorify_hex(page["virt_addr"], heap_page_color)
            self.out.append("    virtual address: {:s}".format(colored_virt_addr))
            self.out.append("    num pages: {:d}".format(page["num_pages"]))
            self.out.append("    total units: {:#x}".format(page["units"]))
            for i, (chunk, units) in enumerate(page["freelist"]):
                msg = Color.colorify_hex(chunk, freed_address_color)
                msg_sz = Color.colorify_hex(units * 2, chunk_size_color)
                self.out.append("    {:9s} {:s} (units: {:#x}, size: {:s})".format("freelist:" if i == 0 else "", msg, units, msg_sz))
            self.out.append("    next: {:#x}".format(page["next"]))
            self.out.append("")
        return

    def dump_caches(self, target_names, parsed_caches, parsed_freelist):
        chunk_label_color = Config.get_gef_setting("theme.heap_chunk_label")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")

        if self.args.verbose:
            self.out.append(titlify("{:s} @ {:#x}".format("slab_caches", self.slab_caches)))
            for kmem_cache in parsed_caches[1:]:
                if target_names != [] and kmem_cache["name"] not in target_names:
                    continue
                self.out.append("  kmem_cache: {:#x}".format(kmem_cache["address"]))
                colored_name = Color.colorify(kmem_cache["name"], chunk_label_color)
                self.out.append("    name: {:s}".format(colored_name))
                self.out.append("    flags: {:#x} ({:s})".format(kmem_cache["flags"], kmem_cache["flags_str"]))
                object_size_s = Color.colorify_hex(kmem_cache["object_size"], chunk_size_color)
                self.out.append("    object size: {:s} (chunk size: {:#x})".format(object_size_s, kmem_cache["size"]))
                self.out.append("    next: {:#x}".format(kmem_cache["next"]))
                self.out.append("")

        if self.large:
            self.dump_freelist("free_slob_large", parsed_freelist["large"])
        if self.medium:
            self.dump_freelist("free_slob_medium", parsed_freelist["medium"])
        if self.small:
            self.dump_freelist("free_slob_small", parsed_freelist["small"])
        return

    def dump_names(self, parsed_caches):
        if not self.args.quiet:
            fmt = "{:<16s} {:<16s} {:30s} {:20s}"
            legend = ["Object Size", "Chunk Size", "Name", "kmem_cache"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
        for kmem_cache in sorted(parsed_caches[1:], key=lambda x: x["object_size"]):
            objsz = "{0:d} ({0:#x})".format(kmem_cache["object_size"])
            chunksz = "{0:d} ({0:#x})".format(kmem_cache["size"])
            chunk_name = kmem_cache["name"]
            address = kmem_cache["address"]
            self.out.append("{:16s} {:16s} {:30s} {:#x}".format(objsz, chunksz, chunk_name, address))
        return

    def slobwalk(self, target_names):
        if self.initialize() is False:
            self.quiet_err("Initialize failed")
            return

        if self.args.meta:
            return

        if self.args.list:
            parsed_caches, _ = self.walk_caches(target_names)
            self.dump_names(parsed_caches)
            return

        parsed_caches, parsed_freelist = self.walk_caches(target_names)
        self.dump_caches(target_names, parsed_caches, parsed_freelist)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        if not args.quiet:
            info("Wait for memory scan")

        allocator = KernelChecksecCommand.get_slab_type()
        if allocator != "SLOB":
            if not args.quiet:
                err("Unsupported SLUB, SLAB, SLUB_TINY")
            return

        if (args.large, args.medium, args.small) == (False, False, False):
            self.large = True
            self.medium = True
            self.small = True
        else:
            self.large = args.large
            self.medium = args.medium
            self.small = args.small

        self.args = args
        self.maps = None
        self.out = []
        self.slobwalk(args.cache_name)
        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class SlabContainsCommand(GenericCommand):
    """Resolve the slab cache (kmem_cache) an object belongs to."""
    _cmdline_ = "slab-contains"
    _category_ = "08-e. Qemu-system Cooperation - Linux Allocator"
    _aliases_ = ["slub-contains", "slub-tiny-contains", "xslub", "xslab"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address, help="target address.")
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    parser.add_argument("-v", "--verbose", action="store_true", help="enable verbose mode.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        self.allocator = None
        return

    def initialize(self):
        if self.initialized:
            return True

        cmd = {"SLUB": "slub-dump", "SLAB": "slab-dump", "SLUB_TINY": "slub-tiny-dump"}[self.allocator]
        res = gdb.execute("{:s} --meta".format(cmd), to_string=True)

        r = re.search(r"offsetof\(page, slab_cache\): (0x\S+)", res)
        if not r:
            return False
        self.page_offset_slab_cache = int(r.group(1), 16)
        if self.verbose:
            info("offsetof(page, slab_cache): {:#x}".format(self.page_offset_slab_cache))

        r = re.search(r"offsetof\(page, next\): (0x\S+)", res)
        if not r:
            return False
        self.page_offset_next = int(r.group(1), 16)
        if self.verbose:
            info("offsetof(page, next): {:#x}".format(self.page_offset_next))

        r = re.search(r"offsetof\(kmem_cache, name\): (0x\S+)", res)
        if not r:
            return False
        self.kmem_cache_offset_name = int(r.group(1), 16)
        if self.verbose:
            info("offsetof(kmem_cache, name): {:#x}".format(self.kmem_cache_offset_name))

        r = re.search(r"offsetof\(kmem_cache, size\): (0x\S+)", res)
        if not r:
            return False
        self.kmem_cache_offset_size = int(r.group(1), 16)
        if self.verbose:
            info("offsetof(kmem_cache, size): {:#x}".format(self.kmem_cache_offset_size))

        # for num of pages
        if self.allocator in ["SLUB", "SLUB_TINY"]:
            r = re.search(r"offsetof\(page, inuse_objects_frozen\): (0x\S+)", res)
            if not r:
                return False
            self.page_offset_inuse_objects_frozen = int(r.group(1), 16)
            if self.verbose:
                info("offsetof(page, inuse_objects_frozen): {:#x}".format(self.page_offset_inuse_objects_frozen))

        elif self.allocator == "SLAB":
            r = re.search(r"offsetof\(kmem_cache, gfporder\): (0x\S+)", res)
            if not r:
                return False
            self.kmem_cache_offset_gfporder = int(r.group(1), 16)
            if self.verbose:
                info("offsetof(kmem_cache, gfporder): {:#x}".format(self.kmem_cache_offset_gfporder))

        self.initialized = True
        return True

    def virt2page_wrapper(self, vaddr):
        ret = gdb.execute("virt2page {:#x}".format(vaddr), to_string=True)
        r = re.search(r"Page: (\S+)", ret)
        if r:
            return int(r.group(1), 16)
        return None

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.verbose = args.verbose
        if args.reparse:
            self.initialized = False

        if self.allocator is None:
            if not args.quiet:
                info("Wait for memory scan")
            self.allocator = KernelChecksecCommand.get_slab_type()
        if self.allocator not in ["SLUB", "SLUB_TINY", "SLAB"]:
            if not args.quiet:
                err("Unsupported SLOB")
            return

        ret = self.initialize()
        if not ret:
            if not args.quiet:
                err("Failed to initialize")
            return

        current = args.address & gef_getpagesize_mask_high()
        chunk_label_color = Config.get_gef_setting("theme.heap_chunk_label")

        kversion = Kernel.kernel_version()
        try:
            while True:
                page = self.virt2page_wrapper(current)
                if page is None:
                    if not args.quiet:
                        err("Invalid address")
                    return

                if not args.quiet:
                    if kversion >= "5.17":
                        gef_print("slab: {:#x}".format(page))
                    else:
                        gef_print("page: {:#x}".format(page))

                page_next = read_int_from_memory(page + self.page_offset_next)
                if page_next & 1:
                    current -= gef_getpagesize()
                    if not args.quiet:
                        warn("Detected invalid value, continue exploring...")
                    continue

                kmem_cache = read_int_from_memory(page + self.page_offset_slab_cache)
                if kmem_cache == 0:
                    if not args.quiet:
                        err("This address is not managed by slab")
                    return

                if not args.quiet:
                    gef_print("kmem_cache: {:#x}".format(kmem_cache))

                if (kmem_cache & gef_getpagesize_mask_high()) == 0xdead000000000000:
                    current -= gef_getpagesize()
                    if not args.quiet:
                        warn("Detected invalid value, continue exploring...")
                    continue

                if kmem_cache & 1:
                    current -= gef_getpagesize()
                    if not args.quiet:
                        warn("Detected invalid value, continue exploring...")
                    continue

                if not args.quiet:
                    gef_print("base: {:#x}".format(current))
                break

            slab_cache_name_ptr = read_int_from_memory(kmem_cache + self.kmem_cache_offset_name)
            slab_cache_name = read_cstring_from_memory(slab_cache_name_ptr)
            if slab_cache_name is None:
                if not args.quiet:
                    err("This address is not managed by slab")
                return
            slab_cache_name_c = Color.colorify(slab_cache_name, chunk_label_color)
            slab_cache_size = u32(read_memory(kmem_cache + self.kmem_cache_offset_size, 4))

            if self.allocator in ["SLUB", "SLUB_TINY"]:
                x = read_int_from_memory(page + self.page_offset_inuse_objects_frozen)
                objects = (x >> 16) & 0x7fff
                num_pages = (slab_cache_size * objects + gef_getpagesize_mask_low()) // gef_getpagesize()
            else:
                gfporder = u32(read_memory(kmem_cache + self.kmem_cache_offset_gfporder, 4))
                num_pages = 1 << gfporder

            msg = ("name: {:s}  size: {:#x}  num_pages: {:#x}".format(slab_cache_name_c, slab_cache_size, num_pages))
            if (args.address - current) % slab_cache_size != 0:
                msg += " " + Color.redify("(unaligned?)")
            gef_print(msg)

        except (gdb.MemoryError, ZeroDivisionError):
            if not args.quiet:
                err("Memory error")
        return


@register_command
class BuddyDumpCommand(GenericCommand):
    """Dump zone of page allocator (buddy allocator) free-list."""
    _cmdline_ = "buddy-dump"
    _category_ = "08-e. Qemu-system Cooperation - Linux Allocator"
    _aliases_ = ["zone-dump"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-z", "--zone", action="append", choices=["DMA", "DMA32", "Normal", "HighMem", "Movable", "Device"],
                        help="filter by specified zone name.")
    parser.add_argument("-o", "--order", action="append", type=int, help="filter by specified order.")
    parser.add_argument("-m", "--mtype", action="append", type=int, help="filter by specified mtype.")
    parser.add_argument("--sort", action="store_true",
                        help="sort by page address instead of link list order of each size. filter options are ignored.")
    parser.add_argument("--sort-verbose", action="store_true", help="enable --sort and add information of used area.")
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -z DMA32\n".format(_cmdline_)
    _example_ += "{:s} -o 1 -o 2 -n".format(_cmdline_)

    _note_ = "Simplified buddy allocator structure:\n"
    _note_ += "\n"
    _note_ += "  +-node_data[MAX_NUMNODES]-+\n"
    _note_ += "  | *pglist_data (node 0)   |--+\n"
    _note_ += "  | *pglist_data (node 1)   |  |\n"
    _note_ += "  | *pglist_data (node 2)   |  |\n"
    _note_ += "  | ...                     |  |\n"
    _note_ += "  +-------------------------+  |\n"
    _note_ += "                               |\n"
    _note_ += "    +--------------------------+\n"
    _note_ += "    |\n"
    _note_ += "    v\n"
    _note_ += "  +-pglist_data------------------------------+\n"
    _note_ += "  | node_zones[MAX_NR_ZONES]                 |\n"
    _note_ += "  |   +-node_zones[0]----------------------+ |   +--->+-per_cpu_pages--------+\n"
    _note_ += "  |   |  ...                               | |   |    | ...                  |\n"
    _note_ += "  |   |  per_cpu_pageset                   |-----+    | lists[NR_PCP_LISTS]  |    +-page-----+\n"
    _note_ += "  |   |  ...                               | |        |   +-lists[0]-------+ |    | flags    |\n"
    _note_ += "  |   |  name                              | |        |   | next           |----->| lru.next |->...\n"
    _note_ += "  |   |  ...                               | |        |   | prev           | |    | lru.prev |\n"
    _note_ += "  |   |  free_area[MAX_ORDER]              | |        |   +-lists[1]-------+ |    | ...      |\n"
    _note_ += "  |   |    +-free_area[0]----------------+ | |        |   | ...            | |    +----------+\n"
    _note_ += "  |   |    | free_list[MIGRATE_TYPES]    | | |        |   +----------------+ |\n"
    _note_ += "  |   |    |   +-free_list[0]----------+ | | |        +----------------------+\n"
    _note_ += "  |   |    |   | next                  |---------+\n"
    _note_ += "  |   |    |   | prev                  | | | |   |\n"
    _note_ += "  |   |    |   +-free_list[1]----------+ | | |   |    +-page-----+    +-page-----+    +-page-----+\n"
    _note_ += "  |   |    |   | ...                   | | | |   |    | flags    |    | flags    |    | flags    |\n"
    _note_ += "  |   |    |   +-----------------------+ | | |   +--->| lru.next |--->| lru.next |--->| lru.next |->...\n"
    _note_ += "  |   |    | nr_free                     | | |        | lru.prev |    | lru.prev |    | lru.prev |\n"
    _note_ += "  |   |    +-free_area[1]----------------+ | |        | ...      |    | ...      |    | ...      |\n"
    _note_ += "  |   |    | ...                         | | |        +----------+    +----------+    +----------+\n"
    _note_ += "  |   |    +-----------------------------+ | |\n"
    _note_ += "  |   +-node_zones[1]----------------------+ |\n"
    _note_ += "  |   |  ...                               | |\n"
    _note_ += "  |   +------------------------------------+ |\n"
    _note_ += "  | ...                                      |\n"
    _note_ += "  +------------------------------------------+\n"
    _note_ += "\n"
    _note_ += "You can combine this result with information of in-use space. Try using `pagewalk-with-hints` command."

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        return

    def quiet_info(self, msg):
        if not self.quiet:
            msg = "{} {}".format(Color.colorify("[+]", "bold blue"), msg)
            gef_print(msg)
        return

    def quiet_err(self, msg):
        if not self.quiet:
            msg = "{} {}".format(Color.colorify("[+]", "bold red"), msg)
            gef_print(msg)
        return

    def add_msg(self, msg):
        if not self.sort:
            self.out.append(msg)
        return

    def initialize(self):
        if self.initialized:
            return True

        # search node_data
        node_data = KernelAddressHeuristicFinder.get_node_data()
        if node_data:
            self.quiet_info("node_data: {:#x}".format(node_data))
            # parse each node (*pglist_data)
            self.nodes = []
            current = node_data
            while True:
                node = read_int_from_memory(current)
                if not is_valid_addr(node):
                    break
                self.nodes.append(node)
                current += current_arch.ptrsize

        else:
            first_node = KernelAddressHeuristicFinder.get_node_data0()
            if first_node:
                self.quiet_info("first_node: {:#x}".format(first_node))
                self.nodes = [first_node]
            else:
                self.quiet_err("Failed to resolve node_data or first_node")
                return False

        self.quiet_info("num of nodes: {:d}".format(len(self.nodes)))
        assert len(self.nodes) > 0

        """
        typedef struct pglist_data {
            struct zone node_zones[MAX_NR_ZONES];
            ...
        };

        struct zone {
            ...
            struct pglist_data *zone_pgdat;
            struct per_cpu_pageset __percpu *pageset; // ~v5.14
            struct per_cpu_pages __percpu *per_cpu_pageset; // v5.14~
            ...
            const char *name;
        #ifdef CONFIG_MEMORY_ISOLATION
            unsigned long nr_isolate_pageblock;
        #endif
        #ifdef CONFIG_MEMORY_HOTPLUG
            seqlock_t span_seqlock;
        #endif
            int initialized;
            ZONE_PADDING(_pad1_)
            struct free_area free_area[MAX_ORDER];
            ...
        };

        static char * const zone_names[MAX_NR_ZONES] = {
        #ifdef CONFIG_ZONE_DMA
             "DMA",
        #endif
        #ifdef CONFIG_ZONE_DMA32
             "DMA32",
        #endif
             "Normal",
        #ifdef CONFIG_HIGHMEM
             "HighMem",
        #endif
             "Movable",
        #ifdef CONFIG_ZONE_DEVICE
             "Device",
        #endif
        };
        """

        # zone->name
        current = self.nodes[0]
        name_offsets = []
        while len(name_offsets) < 2:
            val = read_int_from_memory(current)
            name = read_cstring_from_memory(val)
            if name in ["DMA", "DMA32", "Normal", "HighMem", "Movable", "Device"]:
                offset = current - self.nodes[0]
                name_offsets.append(offset)
            current += current_arch.ptrsize
        self.offset_name = name_offsets[0]
        self.quiet_info("offsetof(zone, name): {:#x}".format(self.offset_name))

        # zone->per_cpu_pageset
        current = self.nodes[0]
        while current < self.nodes[0] + self.offset_name:
            val = read_int_from_memory(current)
            if is_valid_addr(val):
                offset_zone_pgdat = current - self.nodes[0]
                self.offset_per_cpu_pageset = offset_zone_pgdat + current_arch.ptrsize
                break
            current += current_arch.ptrsize
        if current == self.offset_name:
            self.quiet_err("Failed to resolve per_cpu_pageset")
            return False
        self.quiet_info("offsetof(zone, per_cpu_pageset): {:#x}".format(self.offset_per_cpu_pageset))

        # per_cpu_offset
        __per_cpu_offset = KernelAddressHeuristicFinder.get_per_cpu_offset()
        if __per_cpu_offset is None:
            self.cpu_offset = None
        else:
            self.cpu_offset = KernelCurrentCommand.get_each_cpu_offset(__per_cpu_offset)

        """
        struct per_cpu_pageset { // ~5.14
            struct per_cpu_pages pcp;
            ...
        }

        struct per_cpu_pages {
            spinlock_t lock; // 5.14~
            int count;
            int high;
            int batch;
            short free_factor; // 5.14~
        #ifdef CONFIG_NUMA
            short expire; // 5.14~
        #endif
            struct list_head lists[NR_PCP_LISTS]; // 5.14~
            struct list_head lists[MIGRATE_PCPTYPES]; // ~5.14
        } ____cacheline_aligned_in_smp;
        """
        # per_cpu_pageset->lists
        if __per_cpu_offset is None:
            per_cpu_pageset = read_int_from_memory(self.nodes[0] + self.offset_per_cpu_pageset)
        else:
            per_cpu_pageset = read_int_from_memory(self.nodes[0] + self.offset_per_cpu_pageset) + self.cpu_offset[0]
            per_cpu_pageset = AddressUtil.align_address(per_cpu_pageset)

        current = AddressUtil.align_address_to_size(per_cpu_pageset + 4 * 3, current_arch.ptrsize) # count, high, batch
        while True:
            # search list_head
            val1 = read_int_from_memory(current)
            val2 = read_int_from_memory(current + current_arch.ptrsize)
            if is_double_link_list(val1) and is_double_link_list(val2):
                break
            current += current_arch.ptrsize
        self.offset_lists = current - per_cpu_pageset
        self.quiet_info("offsetof(per_cpu_pageset, lists): {:#x}".format(self.offset_lists))

        # NR_PCP_LISTS
        current = per_cpu_pageset + self.offset_lists
        while True:
            val1 = read_int_from_memory(current)
            val2 = read_int_from_memory(current + current_arch.ptrsize)
            if not (is_double_link_list(val1) and is_double_link_list(val2)):
                break
            current += current_arch.ptrsize * 2
        self.NR_PCP_LISTS = ((current - per_cpu_pageset) - self.offset_lists) // (current_arch.ptrsize * 2)
        self.quiet_info("NR_PCP_LISTS: {:d}".format(self.NR_PCP_LISTS))

        # sizeof(zone)
        self.sizeof_zone = name_offsets[1] - name_offsets[0]
        self.quiet_info("sizeof(zone): {:#x}".format(self.sizeof_zone))

        # MAX_NR_ZONES
        self.MAX_NR_ZONES = 0
        for i in range(6):
            zone = self.nodes[0] + self.sizeof_zone * i
            name_ptr = read_int_from_memory(zone + self.offset_name)
            name = read_cstring_from_memory(name_ptr)
            if not name:
                break
            self.MAX_NR_ZONES += 1
        self.quiet_info("MAX_NR_ZONES: {:d}".format(self.MAX_NR_ZONES))

        # zone->free_area
        current = self.nodes[0] + self.offset_name + current_arch.ptrsize
        while True:
            # search list_head
            val1 = read_int_from_memory(current)
            val2 = read_int_from_memory(current + current_arch.ptrsize)
            if is_valid_addr(val1) and is_valid_addr(val2):
                break
            current += current_arch.ptrsize
        self.offset_free_area = current - self.nodes[0]
        self.quiet_info("offsetof(zone, free_area): {:#x}".format(self.offset_free_area))

        """
        const char * const migratetype_names[MIGRATE_TYPES] = {
            "Unmovable",
            "Movable",
            "Reclaimable",
            "HighAtomic",
        #ifdef CONFIG_CMA
            "CMA",
        #endif
        #ifdef CONFIG_MEMORY_ISOLATION
            "Isolate",
        #endif
        };
        """
        # MIGRATE_TYPES
        current = free_area = self.nodes[0] + self.offset_free_area
        while True:
            val = read_int_from_memory(current)
            if not is_valid_addr(val):
                break
            current += current_arch.ptrsize
        offset_nr_free = current - free_area
        sizeof_list_head = current_arch.ptrsize * 2
        self.MIGRATE_TYPES = offset_nr_free // sizeof_list_head
        self.quiet_info("MIGRATE_TYPES: {:d}".format(self.MIGRATE_TYPES))

        if self.MIGRATE_TYPES == 4:
            self.migrate_types = [
                "Unmovable",
                "Movable",
                "Reclaimable",
                "HighAtomic",
            ]
        elif self.MIGRATE_TYPES == 5:
            self.migrate_types = [
                "Unmovable",
                "Movable",
                "Reclaimable",
                "HighAtomic",
                "Isolate",
            ]
        elif self.MIGRATE_TYPES == 6:
            self.migrate_types = [
                "Unmovable",
                "Movable",
                "Reclaimable",
                "HighAtomic",
                "Contiguous", # CONFIG_CMA needs CONFIG_MEMORY_ISOLATION, so there is only this pattern
                "Isolate",
            ]
        else:
            err("MIGRATE_TYPES: {:#x}".format(self.MIGRATE_TYPES))
            raise

        """
        struct free_area {
            struct list_head free_list[MIGRATE_TYPES];
            unsigned long nr_free;
        };
        """
        # sizeof(free_area)
        self.sizeof_free_area = offset_nr_free + current_arch.ptrsize
        self.quiet_info("sizeof(free_area): {:#x}".format(self.sizeof_free_area))

        # MAX_ORDER
        current = free_area
        while True:
            val = read_int_from_memory(current)
            if not is_valid_addr(val):
                break
            current += self.sizeof_free_area
        self.MAX_ORDER = (current - free_area) // self.sizeof_free_area
        self.quiet_info("MAX_ORDER: {:d}".format(self.MAX_ORDER))

        """
        struct page {
            unsigned long flags;
            union {
                struct {
                    struct list_head lru;
                    ...
        """
        # page->lru
        self.offset_lru = current_arch.ptrsize

        self.initialized = True
        return True

    def page2virt_wrapper(self, page):
        ret = gdb.execute("page2virt {:#x}".format(page), to_string=True)
        r = re.search(r"Virt: (\S+)", ret)
        if r:
            return int(r.group(1), 16)
        return None

    # for per_cpu_pageset
    def dump_list(self, list_i, i, is_highmem):
        heap_page_color = Config.get_gef_setting("theme.heap_page_address")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        align = AddressUtil.get_format_address_width()

        MIGRATE_PCPTYPES = 3
        order = i // MIGRATE_PCPTYPES
        mtype = i % MIGRATE_PCPTYPES

        size = 0x1000 * (2 ** order)
        size_str = Color.colorify("{:#08x}".format(size), chunk_size_color)

        self.add_msg("  pcp_index: {:d}, order: {:d} ({:s} bytes), mtype: {:d} (={:s})".format(
            i, order, size_str, mtype, self.migrate_types[mtype],
        ))

        seen = [list_i]
        current = read_int_from_memory(list_i)
        if not is_valid_addr(current):
            return

        while current not in seen:
            # page info
            page = current - self.offset_lru
            page_str = Color.colorify("{:#0{:d}x}".format(page, align), freed_address_color)

            # filtering
            if self.mtype_filter and mtype not in self.mtype_filter:
                current = read_int_from_memory(current)
                continue
            if self.order_filter and order not in self.order_filter:
                current = read_int_from_memory(current)
                continue

            # address info
            virt_str = "???"
            phys_str = "???"

            if not is_highmem:
                virt = self.page2virt_wrapper(page)
                phys = None
                if virt:
                    phys = PageMap.v2p_from_map(virt, self.maps)
                if virt is not None:
                    virt_str = "{:#0{:d}x}-{:#0{:d}x}".format(virt, align, virt + size, align)
                    virt_str = Color.colorify(virt_str, heap_page_color)
                if phys is not None:
                    phys_str = "{:#0{:d}x}-{:#0{:d}x}".format(phys, align, phys + size, align)

            # create msg
            msg = "    page:{:s}  size:{:s}  virt:{:s}  phys:{:s} (pcp)".format(page_str, size_str, virt_str, phys_str)

            # add msg
            if self.sort:
                self.out.append([page, size, msg])
            else:
                self.out.append(msg)

            # get next
            current = read_int_from_memory(current)
        return

    def dump_pcp(self, zone, is_highmem):
        per_cpu_pageset = read_int_from_memory(zone + self.offset_per_cpu_pageset)
        if self.cpu_offset is None:
            per_cpu_pageset = [per_cpu_pageset]
        else:
            per_cpu_pageset = [AddressUtil.align_address(cpuoff + per_cpu_pageset) for cpuoff in self.cpu_offset]

        sizeof_list_head = current_arch.ptrsize * 2
        for cpu_num, pcp in enumerate(per_cpu_pageset):
            self.add_msg("cpu: {:d}".format(cpu_num))
            for i in range(self.NR_PCP_LISTS):
                lists_i = pcp + self.offset_lists + sizeof_list_head * i
                self.dump_list(lists_i, i, is_highmem)
        return

    def dump_free_list(self, free_list, mtype, size, is_highmem):
        heap_page_color = Config.get_gef_setting("theme.heap_page_address")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        align = AddressUtil.get_format_address_width()

        self.add_msg("  mtype: {:d} (={:s})".format(mtype, self.migrate_types[mtype]))
        seen = [free_list]
        current = read_int_from_memory(free_list)
        if not is_valid_addr(current):
            return

        # size info
        size_str = Color.colorify("{:#08x}".format(size), chunk_size_color)

        while current not in seen:
            # page info
            page = current - self.offset_lru
            page_str = Color.colorify("{:#0{:d}x}".format(page, align), freed_address_color)

            # address info
            virt_str = "???"
            phys_str = "???"

            if not is_highmem:
                virt = self.page2virt_wrapper(page)
                phys = None
                if virt:
                    phys = PageMap.v2p_from_map(virt, self.maps)
                if virt is not None:
                    virt_str = "{:#0{:d}x}-{:#0{:d}x}".format(virt, align, virt + size, align)
                    virt_str = Color.colorify(virt_str, heap_page_color)
                if phys is not None:
                    phys_str = "{:#0{:d}x}-{:#0{:d}x}".format(phys, align, phys + size, align)

            # create msg
            msg = "    page:{:s}  size:{:s}  virt:{:s}  phys:{:s}".format(page_str, size_str, virt_str, phys_str)

            # add msg
            if self.sort:
                self.out.append([page, size, msg])
            else:
                self.out.append(msg)

            # get next
            current = read_int_from_memory(current)
        return

    def dump_free_area(self, free_area, order, is_highmem):
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")

        size = 0x1000 * (2 ** order)
        size_str = Color.colorify_hex(size, chunk_size_color)
        self.add_msg("order: {:d} ({:s} bytes)".format(order, size_str))

        sizeof_list_head = current_arch.ptrsize * 2
        for mtype in range(self.MIGRATE_TYPES):
            if self.mtype_filter and mtype not in self.mtype_filter:
                continue
            free_list = free_area + sizeof_list_head * mtype
            self.dump_free_list(free_list, mtype, size, is_highmem)
        return

    def dump_zone(self, zone, is_highmem=False):
        self.add_msg(titlify("per_cpu_pageset"))
        self.dump_pcp(zone, is_highmem)

        tqdm = GefUtil.get_tqdm(not self.quiet)
        self.add_msg(titlify("free_area"))
        free_area_array = zone + self.offset_free_area
        for order in tqdm(range(self.MAX_ORDER), leave=False):
            if self.order_filter and order not in self.order_filter:
                continue
            free_area_i = free_area_array + self.sizeof_free_area * order
            self.dump_free_area(free_area_i, order, is_highmem)
        return

    def dump_node(self, node):
        for i in range(self.MAX_NR_ZONES):
            zone = node + self.sizeof_zone * i
            name_ptr = read_int_from_memory(zone + self.offset_name)
            name = read_cstring_from_memory(name_ptr)
            if self.zone_filter and name not in self.zone_filter:
                continue
            self.add_msg(titlify("zone[{:d}] @ {:#x} ({:s})".format(i, zone, name)))
            is_highmem = name == "HighMem"
            self.dump_zone(zone, is_highmem=is_highmem)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        # parse args
        if args.reparse:
            self.initialized = False

        self.quiet = args.quiet
        self.sort_verbose = args.sort_verbose
        self.sort = args.sort_verbose or args.sort

        if self.sort:
            self.zone_filter = False
            self.order_filter = False
            self.mtype_filter = False
        else:
            self.zone_filter = args.zone
            self.order_filter = args.order
            self.mtype_filter = args.mtype

        # initialize
        self.quiet_info("Wait for memory scan")
        if not self.initialize():
            return

        # do not use cache
        self.maps = PageMap.get_page_maps(None)
        if self.maps is None:
            self.quiet_err("Failed to resolve maps")
            return

        # dump
        self.out = []
        for i, node in enumerate(self.nodes):
            self.add_msg(titlify("node[{:d}] @ {:#x}".format(i, node)))
            self.dump_node(node)

        # sort
        if self.sort:
            prev_virt = None
            prev_size = None
            align = AddressUtil.get_format_address_width()

            out = []
            for page, size, msg in sorted(self.out, key=lambda x: x[0]):
                if not self.sort_verbose:
                    out.append(msg)
                    continue

                # sort_verbose
                if prev_virt is None:
                    # first entry
                    virt = self.page2virt_wrapper(page)
                    if virt is not None:
                        phys = PageMap.v2p_from_map(virt, self.maps)
                        if phys is not None:
                            out.append("    used:{:{:d}s}  size:{:#08x}".format("", align, phys))
                    out.append(msg)
                    prev_virt = virt
                    prev_size = size
                    continue
                # second or after entries
                virt = self.page2virt_wrapper(page)
                if prev_virt + prev_size != virt:
                    diff = virt - (prev_virt + prev_size)
                    out.append("    used:{:{:d}s}  size:{:#08x}".format("", align, diff))
                out.append(msg)
                prev_virt = virt
                prev_size = size
            self.out = out

        # print
        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class KernelPipeCommand(GenericCommand):
    """Dump pipe information."""
    _cmdline_ = "kpipe"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-i", "--inode-filter", type=AddressUtil.parse_address, default=[], action="append",
                        help="filter by specific struct inode.")
    parser.add_argument("-f", "--file-filter", type=AddressUtil.parse_address, default=[], action="append",
                        help="filter by specific struct file.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -q".format(_cmdline_)

    _note_ = "This command needs CONFIG_RANDSTRUCT=n.\n"
    _note_ += "\n"
    _note_ += "Simplified pipe structure:\n"
    _note_ += "\n"
    _note_ += "+-task_struct-+  +->+-files_struct-+  +->+-fdtable---+  +->+-files*[]----+  +->+-file------+\n"
    _note_ += "| ...         |  |  | ...          |  |  | max_fds   |  |  | [0]         |--+  | ...       |\n"
    _note_ += "| files       |--+  | fdt          |--+  | fd        |--+  | ...         |     | f_path    |\n"
    _note_ += "| ...         |     | ...          |     | ...       |     | [max_fds-1] |     |   dentry  |---+\n"
    _note_ += "+-------------+     +--------------+     +-----------+     +-------------+     | ...       |   |\n"
    _note_ += "                                                                               +-----------+   |\n"
    _note_ += "                                                                                               |\n"
    _note_ += "+----------------------------------------------------------------------------------------------+\n"
    _note_ += "|\n"
    _note_ += "|  +-dentry---+  +->+-inode-----+  +->+-pipe_inode_info--------+  +->+-pipe_buffer-+\n"
    _note_ += "|  | ...      |  |  | ...       |  |  | ...                    |  |  | page        |--->page\n"
    _note_ += "+->| d_inode  |--+  | i_pipe    |--+  | head, tail, (v5.5~)    |  |  | offset      |\n"
    _note_ += "   | ...      |     | ...       |     | max_usage, (v5.5~)     |  |  | len         |\n"
    _note_ += "   +----------+     +-----------+     | ring_size, (v5.5~)     |  |  | ...         |\n"
    _note_ += "                                      | nrbuf, curbuf, (~v5.5) |  |  +-------------+\n"
    _note_ += "                                      | buffers (~v5.5)        |  |  | page        |--->page\n"
    _note_ += "                                      | ...                    |  |  | offset      |\n"
    _note_ += "                                      | bufs                   |--+  | len         |\n"
    _note_ += "                                      | ...                    |     | ...         |\n"
    _note_ += "                                      +------------------------+     +-------------+\n"
    _note_ += "                                                                     | ...         |\n"
    _note_ += "                                                                     +-------------+\n"

    def initialize(self):
        # kbase
        self.kinfo = Kernel.get_kernel_base()
        if self.kinfo.has_none:
            if not self.quiet:
                err("The kernel .text area could not be determined correctly.")
            return False

        # struct file of pipe
        ret = gdb.execute("ktask --quiet --no-pager --user-process-only --print-fd", to_string=True)
        pipe_files = []
        for line in ret.splitlines():
            m = re.search(r"\d+\s+(0x\S+) 0x\S+ (0x\S+) pipe:\[\d+\]", line)
            if not m:
                continue
            file = int(m.group(1), 16)
            inode = int(m.group(2), 16)
            pipe_files.append((file, inode))
        if pipe_files == []:
            if not self.quiet:
                warn("Nothing to dump")
            return False
        else:
            if not self.quiet:
                info("Num of pipe: {:d}".format(len({x[1] for x in pipe_files})))

        # inode->i_pipe
        """
        struct inode {
            ...
        #if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING)
            atomic_t i_readcount;
        #endif
            union {
                const struct file_operations *i_fop;
                void (*free_inode)(struct inode *);
            };
            struct file_lock_context *i_flctx;
            struct address_space i_data;
        #ifdef CONFIG_QUOTA                   // ~3.18
            struct dquot *i_dquot[MAXQUOTAS]; // ~3.18 // MAXQUOTAS=2
        #endif                                // ~3.18
            struct list_head i_devices;
            union {
                struct pipe_inode_info *i_pipe;  <--- here
                struct block_device *i_bdev;
                struct cdev *i_cdev;
                char *i_link;
                unsigned i_dir_seq;
            };
            ...
        };
        """
        inode = pipe_files[0][1]
        for i in range(0x100):
            v = read_int_from_memory(inode + current_arch.ptrsize * i)
            # i_pipe is valid addr
            if v < 0x10000 or not is_valid_addr(v):
                continue
            # skip invalid chunk
            ret = Kernel.get_slab_contains(v)
            if ret is None:
                continue
            # pipe_inode_info is allocated from kmalloc-192 (x64) or kmalloc-256 (arm64).
            # sometimes it is allocated from kmalloc-512, kmalloc-128, kmalloc-96 and kmalloc-64.
            # Other candidates found are kmalloc-2k, kmalloc-1024 and inode_cache (these are false positives),
            # so these should be excluded.
            if re.search(r"kmalloc(-cg)?-(64|96|128|192|256|512)", ret):
                self.offset_i_pipe = current_arch.ptrsize * i
                if not self.quiet:
                    info("offsetof(inode, i_pipe): {:#x}".format(self.offset_i_pipe))
                break
        else:
            if not self.quiet:
                err("Not found inode->i_pipe")
            return False

        # pipe_inode_info->bufs
        """
        [v5.5~]
        struct pipe_inode_info {
            struct mutex mutex;
            wait_queue_head_t rd_wait, wr_wait; // v5.6~
            wait_queue_head_t wait; // ~v5.6
            unsigned int head;
            unsigned int tail;
            unsigned int max_usage;
            unsigned int ring_size;
        #ifdef CONFIG_WATCH_QUEUE // v5.8~
            bool note_loss;       // v5.8~
        #endif                    // v5.8~
            unsigned int nr_accounted; // v5.8~
            unsigned int readers;
            unsigned int writers;
            unsigned int files;
            unsigned int r_counter;
            unsigned int w_counter;
            bool poll_usage; // v5.10~
            struct page *tmp_page;
            struct fasync_struct *fasync_readers;
            struct fasync_struct *fasync_writers;
            struct pipe_buffer *bufs;  <--- here
            struct user_struct *user;
        #ifdef CONFIG_WATCH_QUEUE            // v5.8~
            struct watch_queue *watch_queue; // v5.8~
        #endif                               // v5.8~
        };

        [~v5.5]
        struct pipe_inode_info {
            struct mutex mutex;
            wait_queue_head_t wait;
            unsigned int nrbufs, curbuf, buffers;
            unsigned int readers;
            unsigned int writers;
            unsigned int files;
            unsigned int waiting_writers;
            unsigned int r_counter;
            unsigned int w_counter;
            struct page *tmp_page;
            struct fasync_struct *fasync_readers;
            struct fasync_struct *fasync_writers;
            struct pipe_buffer *bufs; <--- here
            struct user_struct *user;
        };
        """
        kversion = Kernel.kernel_version()
        pipe_inode_info = read_int_from_memory(inode + self.offset_i_pipe)
        for i in range(0x80):
            v = read_int_from_memory(pipe_inode_info + current_arch.ptrsize * i)
            # bufs is valid addr
            if v < 0x10000 or not is_valid_addr(v):
                continue
            # bufs is not self
            if v == pipe_inode_info:
                continue
            # skip invalid chunk
            ret = Kernel.get_slab_contains(v)
            if ret is None:
                continue
            # pipe_inode_info is allocated from kmalloc-1k (x64) or kmalloc-512 (x86)
            if re.search(r"kmalloc(-cg)?-(1k|1024|512)", ret):
                self.offset_bufs = current_arch.ptrsize * i
                if not self.quiet:
                    info("offsetof(pipe_inode_info, bufs): {:#x}".format(self.offset_bufs))
                break
            # before v5.5, pipe_buffer is allocated not from slub, but `user` is allocated from slub.
            if kversion < "5.5" and "uid_cache" in ret:
                self.offset_bufs = current_arch.ptrsize * (i - 1)
                if not self.quiet:
                    info("offsetof(pipe_inode_info, bufs): {:#x}".format(self.offset_bufs))
                break
        else:
            if not self.quiet:
                err("Not found pipe_inode_info->bufs")
            return False

        if kversion >= "5.5":
            # pipe_inode_info->{head,tail,max_usage,ring_size}
            for i in range(3, 0x40):
                # head is not address
                v1 = read_int_from_memory(pipe_inode_info + current_arch.ptrsize * i)
                if is_valid_addr(v1):
                    continue
                # head is too large
                v1_4 = u32(read_memory(pipe_inode_info + current_arch.ptrsize * i, 4))
                if v1_4 > 0x100:
                    continue
                # max_usage is not address
                v2 = read_int_from_memory(pipe_inode_info + current_arch.ptrsize * (i + 1))
                if is_valid_addr(v2):
                    continue
                # max_usage is too large or zero
                v2_4 = u32(read_memory(pipe_inode_info + current_arch.ptrsize * (i + 1), 4))
                if v2_4 > 0x100 or v2_4 == 0:
                    continue
                self.offset_head = current_arch.ptrsize * i
                if not self.quiet:
                    info("offsetof(pipe_inode_info, head): {:#x}".format(self.offset_head))
                self.offset_tail = self.offset_head + 4
                if not self.quiet:
                    info("offsetof(pipe_inode_info, tail): {:#x}".format(self.offset_tail))
                self.offset_max_usage = self.offset_tail + 4
                if not self.quiet:
                    info("offsetof(pipe_inode_info, max_usage): {:#x}".format(self.offset_max_usage))
                self.offset_ring_size = self.offset_max_usage + 4
                if not self.quiet:
                    info("offsetof(pipe_inode_info, ring_size): {:#x}".format(self.offset_ring_size))
                break
            else:
                if not self.quiet:
                    err("Not found pipe_inode_info->head")
                return False
        else:
            # pipe_inode_info->{nrbuf,curbuf,buffers}
            for i in range(3, 0x40):
                # nrbuf is not address
                v1 = read_int_from_memory(pipe_inode_info + current_arch.ptrsize * i)
                if is_valid_addr(v1):
                    continue
                # nrbuf is too large
                v1_4 = u32(read_memory(pipe_inode_info + current_arch.ptrsize * i, 4))
                if v1_4 > 0x100:
                    continue
                # buffers is not address
                v2 = read_int_from_memory(pipe_inode_info + current_arch.ptrsize * (i + 1))
                if is_valid_addr(v2):
                    continue
                # buffers is too large or zero
                v2_4 = u32(read_memory(pipe_inode_info + current_arch.ptrsize * (i + 1), 4))
                if v2_4 > 0x100 or v2_4 == 0:
                    continue
                self.offset_nrbuf = current_arch.ptrsize * i
                if not self.quiet:
                    info("offsetof(pipe_inode_info, nrbuf): {:#x}".format(self.offset_nrbuf))
                self.offset_curbuf = self.offset_nrbuf + 4
                if not self.quiet:
                    info("offsetof(pipe_inode_info, curbuf): {:#x}".format(self.offset_curbuf))
                self.offset_buffers = self.offset_curbuf + 4
                if not self.quiet:
                    info("offsetof(pipe_inode_info, buffers): {:#x}".format(self.offset_buffers))
                break
            else:
                if not self.quiet:
                    err("Not found pipe_inode_info->nrbuf")
                return False

        # pipe_buffer->{page, offset, len, flags}
        """
        struct pipe_buffer {
            struct page *page;
            unsigned int offset, len;
            const struct pipe_buf_operations *ops;
            unsigned int flags;
            unsigned long private;
        };
        """
        self.offset_page = 0
        if not self.quiet:
            info("offsetof(pipe_buffer, page): {:#x}".format(self.offset_page))
        self.offset_offset = current_arch.ptrsize
        if not self.quiet:
            info("offsetof(pipe_buffer, offset): {:#x}".format(self.offset_offset))
        self.offset_len = self.offset_offset + 4
        if not self.quiet:
            info("offsetof(pipe_buffer, len): {:#x}".format(self.offset_len))
        self.offset_flags = self.offset_len + 4 + current_arch.ptrsize
        if not self.quiet:
            info("offsetof(pipe_buffer, flags): {:#x}".format(self.offset_flags))
        self.sizeof_pipe_buffer = AddressUtil.align_address_to_size(self.offset_flags + 4, current_arch.ptrsize) + current_arch.ptrsize
        if not self.quiet:
            info("sizeof(pipe_buffer): {:#x}".format(self.sizeof_pipe_buffer))
        return pipe_files

    def page2virt_wrapper(self, page):
        ret = gdb.execute("page2virt {:#x}".format(page), to_string=True)
        r = re.search(r"Virt: (\S+)", ret)
        if r:
            return int(r.group(1), 16)
        return None

    def get_flags_str(self, flags_value):
        _flags = {
            "PIPE_BUF_FLAG_LRU":       0x01,
            "PIPE_BUF_FLAG_ATOMIC":    0x02,
            "PIPE_BUF_FLAG_GIFT":      0x04,
            "PIPE_BUF_FLAG_PACKET":    0x08,
            "PIPE_BUF_FLAG_CAN_MERGE": 0x10,
            "PIPE_BUF_FLAG_WHOLE":     0x20,
            "PIPE_BUF_FLAG_LOSS":      0x40,
        }
        flags = []
        for k, v in _flags.items():
            if flags_value & v:
                flags.append(k)

        flags_str = " | ".join(flags)
        if flags_str == "":
            flags_str = "none"
        return flags_str

    def dump_pipe(self, pipe_files):
        heap_page_color = Config.get_gef_setting("theme.heap_page_address")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        used_address_color = Config.get_gef_setting("theme.heap_chunk_address_used")
        kversion = Kernel.kernel_version()

        inodes = {}
        for file, inode in pipe_files:
            inodes[inode] = inodes.get(inode, []) + [file]

        for inode, files in inodes.items():
            if self.inode_filter and inode not in self.inode_filter:
                continue

            if self.file_filter and not (set(self.file_filter) & set(files)):
                continue

            related_files = ", ".join(["{:#x}".format(x) for x in files])
            self.out.append("inode: {:#x} (related struct file: {:s})".format(inode, related_files))

            pipe_inode_info = read_int_from_memory(inode + self.offset_i_pipe)
            self.out.append("  pipe_inode_info: {:#x}".format(pipe_inode_info))

            pipe_buffer = read_int_from_memory(pipe_inode_info + self.offset_bufs)
            self.out.append("    pipe_buffer: {:#x}".format(pipe_buffer))

            if kversion >= "5.5":
                head = u32(read_memory(pipe_inode_info + self.offset_head, 4))
                tail = u32(read_memory(pipe_inode_info + self.offset_tail, 4))
                max_usage = u32(read_memory(pipe_inode_info + self.offset_max_usage, 4))
                ring_size = u32(read_memory(pipe_inode_info + self.offset_ring_size, 4))
                self.out.append("    head: {:d}, tail: {:d}, max: {:d}, ring_size: {:d}".format(head, tail, max_usage, ring_size))
            else:
                nrbuf = u32(read_memory(pipe_inode_info + self.offset_nrbuf, 4))
                curbuf = u32(read_memory(pipe_inode_info + self.offset_curbuf, 4))
                buffers = u32(read_memory(pipe_inode_info + self.offset_buffers, 4))
                self.out.append("    nrbuf: {:d}, curbuf: {:d}, buffers: {:d}".format(nrbuf, curbuf, buffers))
                head = curbuf + nrbuf
                tail = curbuf
                max_usage = buffers

            used_range = [x % max_usage for x in range(tail, head)]
            for idx in range(max_usage):
                base = pipe_buffer + self.sizeof_pipe_buffer * idx
                page = read_int_from_memory(base + self.offset_page)
                offset = u32(read_memory(base + self.offset_offset, 4))
                len_ = u32(read_memory(base + self.offset_len, 4))
                flags = u32(read_memory(base + self.offset_flags, 4))
                virt = self.page2virt_wrapper(page)

                if idx in used_range:
                    status = Color.colorify("used", used_address_color)
                else:
                    status = Color.colorify("free", freed_address_color)

                if head % max_usage == idx:
                    head_marker = "head"
                else:
                    head_marker = "    "

                if tail % max_usage == idx:
                    tail_marker = "tail"
                else:
                    tail_marker = "    "

                out = "    {:s} {:s} {:s} [{:02d}] page: {:#x}, ".format(head_marker, tail_marker, status, idx, page)
                if virt:
                    colored_virt = Color.colorify_hex(virt, heap_page_color)
                    out += "(virt: {:s}), ".format(colored_virt)
                out += "offset: {:#x}, len: {:#x}, flags: {:#x} ({:s})".format(offset, len_, flags, self.get_flags_str(flags))
                self.out.append(out)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet
        if not args.quiet:
            info("Wait for memory scan")

        allocator = KernelChecksecCommand.get_slab_type()
        if allocator not in ["SLUB", "SLUB_TINY", "SLAB"]:
            err("Unsupported SLOB")
            return

        self.inode_filter = args.inode_filter
        self.file_filter = args.file_filter

        # init
        ret = self.initialize()
        if ret is False:
            return
        pipe_files = ret

        # dump
        self.out = []
        self.dump_pipe(pipe_files)

        # print
        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelBpfCommand(GenericCommand):
    """Dump bpf information."""
    _cmdline_ = "kbpf"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-p", "--only-progs", action="store_true", help="print progs only")
    parser.add_argument("-m", "--only-maps", action="store_true", help="print maps only")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="enable verbose mode.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -q".format(_cmdline_)

    _note_ = "This command needs CONFIG_RANDSTRUCT=n.\n"
    _note_ += "\n"
    _note_ += "Simplified bpf structure:\n"
    _note_ += "\n"
    _note_ += "+-prog_idr----+   +--->+-xa_node----------+   +--------->+-bpf_prog-------------+\n"
    _note_ += "| idr_rt      |   |    | shift            |   |          | ...                  |\n"
    _note_ += "|   xa_lock   |   |    | ...              |   |          | type                 |\n"
    _note_ += "|   xa_flags  |   |    | count            |   |          | expected_attach_type |\n"
    _note_ += "|   xa_head   |---+    | ...              |   |          | len                  |\n"
    _note_ += "| idr_base    |        | slots[0]         |---+          | jited_len            |\n"
    _note_ += "| idr_next    |        | slots[1]         |--->xa_node   | tag[8]               |\n"
    _note_ += "+-------------+        | ...              |    or        | ...                  |\n"
    _note_ += "                       | slots[15 or 63]  |    bpf_prog  | bpf_func             |---> BPF-code\n"
    _note_ += "                       | ...              |              | ...                  |\n"
    _note_ += "                       +------------------+              | aux                  |\n"
    _note_ += "                                                         | ...                  |\n"
    _note_ += "                                                         +----------------------+\n"
    _note_ += "\n"
    _note_ += "+-map_idr-----+   +--->+-xa_node----------+   +--------->+-bpf_array------------+\n"
    _note_ += "| idr_rt      |   |    | shift            |   |          | map                  |\n"
    _note_ += "|   xa_lock   |   |    | ...              |   |          |   ...                |\n"
    _note_ += "|   xa_flags  |   |    | count            |   |          |   map_type           |\n"
    _note_ += "|   xa_head   |---+    | ...              |   |          |   key_size           |\n"
    _note_ += "| idr_base    |        | slots[0]         |---+          |   value_size         |\n"
    _note_ += "| idr_next    |        | slots[1]         |--->xa_node   |   max_entries        |\n"
    _note_ += "+-------------+        | ...              |    or        |   ...                |\n"
    _note_ += "                       | slots[15 or 63]  |    bpf_array | elem_size            |\n"
    _note_ += "                       | ...              |              | index_mask           |\n"
    _note_ += "                       +------------------+              | ...                  |\n"
    _note_ += "                                                         +----------------------+\n"
    _note_ += "                                                         | value[0]             |\n"
    _note_ += "                                                         | value[1]             |\n"
    _note_ += "                                                         | ...                  |\n"
    _note_ += "                                                         | value[max_entries-1] |\n"
    _note_ += "                                                         +----------------------+\n"

    def parse_xarray(self, ptr, root=False):
        if ptr == 0:
            return []

        ptr &= ~3 # untagged

        if root:
            node = read_int_from_memory(ptr + self.offset_xa_head)
            return self.parse_xarray(node)

        shift = u8(read_memory(ptr + self.offset_shift, 1))
        count = u8(read_memory(ptr + self.offset_count, 1))
        slots = ptr + self.offset_slots
        elems = []
        for i in range(64): # 16 or 64
            x = read_int_from_memory(slots + current_arch.ptrsize * i)
            if x == 0:
                continue
            if shift:
                elems += self.parse_xarray(x)
            else:
                elems.append(x)
            count -= 1
            if count == 0:
                break
        return elems

    def initialize(self):
        # get global address
        prog_idr = KernelAddressHeuristicFinder.get_prog_idr()
        if not prog_idr:
            return False
        if not self.quiet:
            info("prog_idr: {:#x}".format(prog_idr))

        map_idr = KernelAddressHeuristicFinder.get_map_idr()
        if not map_idr:
            return False
        if not self.quiet:
            info("map_idr: {:#x}".format(map_idr))

        kversion = Kernel.kernel_version()

        """
        struct xarray {
            spinlock_t xa_lock;
            gfp_t xa_flags;
            void __rcu *xa_head;
        };
        """
        # idr->idr_rt->xa_head
        base = prog_idr + 4 * 2
        max_sizeof_idr = abs(prog_idr - map_idr)
        for i in range(20):
            pos = base + current_arch.ptrsize * i
            if (pos - prog_idr) >= max_sizeof_idr:
                continue
            x = read_int_from_memory(pos)
            if not is_valid_addr(x):
                continue
            if (x & 2) != 2: # tag
                continue
            y = read_cstring_from_memory(x)
            if y and len(y) > 8 or y == "bpf":
                continue
            z = read_int_from_memory(x)
            if is_valid_addr(z):
                continue
            self.offset_xa_head = pos - prog_idr
            if not self.quiet:
                info("offsetof(xarray, xa_head): {:#x}".format(self.offset_xa_head))
            break
        else:
            err("Not found xa_head. (maybe uninitialized?)")
            return False

        """
        struct xa_node {
            unsigned char shift;
            unsigned char offset;
            unsigned char count;
            unsigned char nr_values;
            struct xa_node __rcu *parent;
            struct xarray *array;
            union {
                struct list_head private_list;
                struct rcu_head rcu_head;
            };
            void __rcu *slots[XA_CHUNK_SIZE];
            union {
                unsigned long tags[XA_MAX_MARKS][XA_MARK_LONGS];
                unsigned long marks[XA_MAX_MARKS][XA_MARK_LONGS];
            };
        };
        """
        # xa_node->{shift,count,slots}
        self.offset_shift = 0
        self.offset_count = 2
        self.offset_slots = current_arch.ptrsize * 5
        if not self.quiet:
            info("offsetof(xa_node, shift): {:#x}".format(self.offset_shift))
            info("offsetof(xa_node, count): {:#x}".format(self.offset_count))
            info("offsetof(xa_node, slots): {:#x}".format(self.offset_slots))

        # parse progs, maps
        try:
            progs = self.parse_xarray(prog_idr, root=True)
            if not self.quiet:
                info("Num of progs: {:#x}".format(len(progs)))
            maps = self.parse_xarray(map_idr, root=True)
            if not self.quiet:
                info("Num of maps: {:#x}".format(len(maps)))
        except gdb.MemoryError:
            if not self.quiet:
                err("Not found")
            return False

        """
        struct bpf_prog {
            u16 pages;
            u16 jited:1,
                jit_requested:1,
                gpl_compatible:1,
                cb_access:1,
                dst_needed:1,
                blinded:1,
                is_func:1,
                kprobe_override:1,
                has_callchain_buf:1,
                enforce_expected_attach_type:1,
                call_get_stack:1;
            enum bpf_prog_type type;
            enum bpf_attach_type expected_attach_type;
            u32 len;
            u32 jited_len;
            u8 tag[BPF_TAG_SIZE]; // 8 byte
            struct bpf_prog_stats __percpu *stats; // 5.12~
            int __percpu *active;                  // 5.12~
            unsigned int (*bpf_func)(const void *ctx, const struct bpf_insn *insn); // 5.12~
            struct bpf_prog_aux *aux;
            struct sock_fprog_kern *orig_prog;
            unsigned int (*bpf_func)(const void *ctx, const struct bpf_insn *insn); // ~5.11
            const struct bpf_insn *insn);
            struct sock_filter insns[0];
            struct bpf_insn insnsi[];
        };
        """
        # bpf_prog->{type,expected_attach_type,len,jited_len,tag,aux}
        self.offset_prog_type = 4
        self.offset_expected_attach_type = self.offset_prog_type + 4
        self.offset_len = self.offset_expected_attach_type + 4
        self.offset_jited_len = self.offset_len + 4
        self.offset_tag = self.offset_jited_len + 4
        if kversion >= "5.12":
            self.offset_aux = AddressUtil.align_address_to_size(self.offset_tag + 8, current_arch.ptrsize) + current_arch.ptrsize * 3
            self.offset_bpf_func = self.offset_aux - current_arch.ptrsize
        else:
            self.offset_aux = AddressUtil.align_address_to_size(self.offset_tag + 8, current_arch.ptrsize)
            self.offset_bpf_func = self.offset_aux + current_arch.ptrsize * 2
        if not self.quiet:
            info("offsetof(bpf_prog, type): {:#x}".format(self.offset_prog_type))
            info("offsetof(bpf_prog, expected_attach_type): {:#x}".format(self.offset_expected_attach_type))
            info("offsetof(bpf_prog, len): {:#x}".format(self.offset_len))
            info("offsetof(bpf_prog, jited_len): {:#x}".format(self.offset_jited_len))
            info("offsetof(bpf_prog, tag): {:#x}".format(self.offset_tag))
            info("offsetof(bpf_prog, aux): {:#x}".format(self.offset_aux))
            info("offsetof(bpf_prog, bpf_func): {:#x}".format(self.offset_bpf_func))

        if maps:
            """
            struct bpf_map {
                const struct bpf_map_ops *ops ____cacheline_aligned;
                struct bpf_map *inner_map_meta;
            #ifdef CONFIG_SECURITY
                void *security;
            #endif
                enum bpf_map_type map_type;
                u32 key_size;
                u32 value_size;
                u32 max_entries;
                ...
            };
            """
            # bpf_map->{map_type,key_size,value_size,max_entries}
            cand = read_int_from_memory(maps[0] + current_arch.ptrsize * 2)
            if cand == 0 or is_valid_addr(cand):
                self.offset_map_type = current_arch.ptrsize * 3
            else:
                self.offset_map_type = current_arch.ptrsize * 2
            self.offset_key_size = self.offset_map_type + 4
            self.offset_value_size = self.offset_key_size + 4
            self.offset_max_entries = self.offset_value_size + 4
            if not self.quiet:
                info("offsetof(bpf_map, map_type): {:#x}".format(self.offset_map_type))
                info("offsetof(bpf_map, key_size): {:#x}".format(self.offset_key_size))
                info("offsetof(bpf_map, value_size): {:#x}".format(self.offset_value_size))
                info("offsetof(bpf_map, max_entries): {:#x}".format(self.offset_max_entries))

            """
            struct bpf_array {
                struct bpf_map map;
                u32 elem_size;
                u32 index_mask;
                struct bpf_array_aux *aux;
                union {
                    char value[0] __aligned(8);
                    void *ptrs[0] __aligned(8);
                    void __percpu *pptrs[0] __aligned(8);
                };
            };
            """
            # bpf_array->union_array
            value_size = u32(read_memory(maps[0] + self.offset_value_size, 4))
            value_size_aligned_8 = AddressUtil.align_address_to_size(value_size, 8)
            max_entries = u32(read_memory(maps[0] + self.offset_max_entries, 4))
            k = 1
            while k < max_entries:
                k <<= 1
            index_mask = k - 1

            sizeof_cache_line = 0x40 # ?
            base = maps[0] + sizeof_cache_line * 3
            for i in range(100):
                pos = base + current_arch.ptrsize * i
                x = u32(read_memory(pos, 4))
                y = u32(read_memory(pos + 4, 4))
                if x == value_size_aligned_8 and y == index_mask:
                    self.offset_union_array = (pos - maps[0]) + 4 * 2 + current_arch.ptrsize
                    if not self.quiet:
                        info("offsetof(bpf_array, union_array): {:#x}".format(self.offset_union_array))
                    break
            else:
                return False
        return progs, maps

    def dump_bpf_progs(self, progs):
        self.out.append(titlify("prog_idr"))
        fmt = "{:3s} {:18s} {:23s} {:24s} {:18s} {:18s} {:18s}"
        legend = ["#", "bpf_prog", "bpf_prog_type", "bpf_attach_type", "tag", "bpf_prog_aux", "bpf_func"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        defined_prog_types = [
            "UNSPEC",
            "SOCKET_FILTER",
            "KPROBE",
            "SCHED_CLS",
            "SCHED_ACT",
            "TRACEPOINT",
            "XDP",
            "PERF_EVENT",
            "CGROUP_SKB",
            "CGROUP_SOCK",
            "LWT_IN",
            "LWT_OUT",
            "LWT_XMIT",
            "SOCK_OPS",
            "SK_SKB",
            "CGROUP_DEVICE",
            "SK_MSG",
            "RAW_TRACEPOINT",
            "CGROUP_SOCK_ADDR",
            "LWT_SEG6LOCAL",
            "LIRC_MODE2",
            "SK_REUSEPORT",
            "FLOW_DISSECTOR",
            "CGROUP_SYSCTL",
            "RAW_TRACEPOINT_WRITABLE",
            "CGROUP_SOCKOPT",
            "TRACING",
            "STRUCT_OPS",
            "EXT",
            "LSM",
            "SK_LOOKUP",
        ]

        defined_attach_types = [
            "CGROUP_INET_INGRESS",
            "CGROUP_INET_EGRESS",
            "CGROUP_INET_SOCK_CREATE",
            "CGROUP_SOCK_OPS",
            "SK_SKB_STREAM_PARSER",
            "SK_SKB_STREAM_VERDICT",
            "CGROUP_DEVICE",
            "SK_MSG_VERDICT",
            "CGROUP_INET4_BIND",
            "CGROUP_INET6_BIND",
            "CGROUP_INET4_CONNECT",
            "CGROUP_INET6_CONNECT",
            "CGROUP_INET4_POST_BIND",
            "CGROUP_INET6_POST_BIND",
            "CGROUP_UDP4_SENDMSG",
            "CGROUP_UDP6_SENDMSG",
            "LIRC_MODE2",
            "FLOW_DISSECTOR",
            "CGROUP_SYSCTL",
            "CGROUP_UDP4_RECVMSG",
            "CGROUP_UDP6_RECVMSG",
            "CGROUP_GETSOCKOPT",
            "CGROUP_SETSOCKOPT",
            "TRACE_RAW_TP",
            "TRACE_FENTRY",
            "TRACE_FEXIT",
            "MODIFY_RETURN",
            "LSM_MAC",
            "TRACE_ITER",
            "CGROUP_INET4_GETPEERNAME",
            "CGROUP_INET6_GETPEERNAME",
            "CGROUP_INET4_GETSOCKNAME",
            "CGROUP_INET6_GETSOCKNAME",
            "XDP_DEVMAP",
            "CGROUP_INET_SOCK_RELEASE",
            "XDP_CPUMAP",
            "SK_LOOKUP",
            "XDP",
        ]

        fmt = "{:<3d} {:#018x} {:23s} {:24s} {:#018x} {:#018x} {:#018x}"
        for i, prog in enumerate(progs):
            bpf_type = u32(read_memory(prog + self.offset_prog_type, 4))
            bpf_attach_type = u32(read_memory(prog + self.offset_expected_attach_type, 4))
            t1 = defined_prog_types[bpf_type]
            t2 = defined_attach_types[bpf_attach_type]
            tag = u64(read_memory(prog + self.offset_tag, 8))
            aux = read_int_from_memory(prog + self.offset_aux)
            bpf_func = read_int_from_memory(prog + self.offset_bpf_func)
            self.out.append(fmt.format(i, prog, t1, t2, tag, aux, bpf_func))
            if self.verbose:
                ret = gdb.execute("capstone-disassemble {:#x}".format(bpf_func), to_string=True).rstrip()
                self.out.append(ret)
                self.out.append("      ...")
        return

    def dump_bpf_maps(self, maps):
        self.out.append(titlify("map_idr"))
        fmt = "{:3s} {:18s} {:21s} {:10s} {:10s} {:10s} {:18s}"
        legend = ["#", "bpf_map", "bpf_map_type", "key_size", "value_size", "max_ents", "array"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        defined_map_types = [
            "UNSPEC",
            "HASH",
            "ARRAY",
            "PROG_ARRAY",
            "PERF_EVENT_ARRAY",
            "PERCPU_HASH",
            "PERCPU_ARRAY",
            "STACK_TRACE",
            "CGROUP_ARRAY",
            "LRU_HASH",
            "LRU_PERCPU_HASH",
            "LPM_TRIE",
            "ARRAY_OF_MAPS",
            "HASH_OF_MAPS",
            "DEVMAP",
            "SOCKMAP",
            "CPUMAP",
            "XSKMAP",
            "SOCKHASH",
            "CGROUP_STORAGE",
            "REUSEPORT_SOCKARRAY",
            "PERCPU_CGROUP_STORAGE",
            "QUEUE",
            "STACK",
            "SK_STORAGE",
            "DEVMAP_HASH",
            "STRUCT_OPS",
            "RINGBUF",
            "INODE_STORAGE",
        ]

        fmt = "{:<3d} {:#018x} {:21s} {:#010x} {:#010x} {:#010x} {:#018x}"
        for i, m in enumerate(maps):
            map_type = u32(read_memory(m + self.offset_map_type, 4))
            t1 = defined_map_types[map_type]
            key_size = u32(read_memory(m + self.offset_key_size, 4))
            val_size = u32(read_memory(m + self.offset_value_size, 4))
            max_ents = u32(read_memory(m + self.offset_max_entries, 4))
            union_array = m + self.offset_union_array
            self.out.append(fmt.format(i, m, t1, key_size, val_size, max_ents, union_array))

            if self.verbose:
                if map_type == 2: # ARRAY
                    res = gdb.execute("dereference -n {:#x} {:#x}".format(union_array, max_ents), to_string=True)
                    self.out.append(res.rstrip())
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet
        if not self.quiet:
            info("Wait for memory scan")
        self.verbose = args.verbose

        kversion = Kernel.kernel_version()
        if kversion < "4.20":
            # xarray is introduced from 4.20
            if not self.quiet:
                err("Unsupported v4.19 or before")
            return

        stv_bpf_ret = gdb.execute("syscall-table-view -f bpf --quiet --no-pager", to_string=True)
        if "bpf" not in stv_bpf_ret:
            if not self.quiet:
                err("bpf syscall is unimplemented")
            return
        elif "invalid bpf" in stv_bpf_ret:
            if not self.quiet:
                err("bpf syscall is disabled")
            return

        # init
        ret = self.initialize()
        if ret is False:
            if not self.quiet:
                err("Failed to initialize")
            return
        progs, maps = ret

        # dump
        self.out = []
        if not args.only_maps:
            self.dump_bpf_progs(progs)
        if not args.only_progs:
            self.dump_bpf_maps(maps)

        # print
        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelIpcsCommand(GenericCommand):
    """Dump IPCs information (System V semaphore, message queue and shared memory)."""
    _cmdline_ = "kipcs"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    _note_ = "This command needs CONFIG_RANDSTRUCT=n.\n"
    _note_ += "\n"
    _note_ += "Simplified ipc structure:\n"
    _note_ += "\n"
    _note_ += "+-task_struct-+  +-->+-nsproxy--+  +-->+-ipc_namespace-+\n"
    _note_ += "| ...         |  |   | ...      |  |   | ...           |\n"
    _note_ += "| nsproxy     |--+   | ipc_ns   |--+   | ids[0] (sem)  |\n"
    _note_ += "| ...         |      | ...      |      |   ...         |\n"
    _note_ += "+-------------+      +----------+      |   ipcs_idr    |\n"
    _note_ += "                                       |     xa_head   |-->xarray-->+-sem_array-+\n"
    _note_ += "                                       |     ...       |            | ...       |\n"
    _note_ += "                                       | ids[1] (msg)  |            +-----------+\n"
    _note_ += "                                       |   ...         |\n"
    _note_ += "                                       |   ipcs_idr    |\n"
    _note_ += "                                       |     xa_head   |-->xarray-->+-msg_queue-+\n"
    _note_ += "                                       |     ...       |            | ...       |\n"
    _note_ += "                                       | ids[2] (shm)  |            +-----------+\n"
    _note_ += "                                       |   ...         |\n"
    _note_ += "                                       |   ipcs_idr    |\n"
    _note_ += "                                       |     xa_head   |-->xarray-->+-shmid_kernel-+\n"
    _note_ += "                                       |     ...       |            | ...          |\n"
    _note_ += "                                       | ...           |            +--------------+\n"
    _note_ += "                                       +---------------+"

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        self.offset_xa_head = None
        self.offset_sem_nsems = None
        self.offset_q_cbytes = None
        self.offset_q_qnum = None
        self.offset_shm_nattch = None
        self.offset_shm_segsz = None
        return

    def get_all_ipc_ns(self):
        res = gdb.execute("ktask --print-namespace --user-process-only --no-pager --quiet", to_string=True)
        r = re.findall(r"nsproxy->ipc_ns\s+(0x\S+)", res)

        ipc_ns_list = []
        # do not use `set()` because the order is important.
        for x in r:
            x = int(x, 16)
            if x not in ipc_ns_list:
                ipc_ns_list.append(x)
        return ipc_ns_list

    def initialize(self, ipc_ns_list):
        if self.initialized:
            return True

        if ipc_ns_list == []:
            return False

        if ipc_ns_list == [0]:
            err("Not found valid ipc_ns (maybe CONFIG_SYSVIPC=n)")
            return False

        # ipc_namespace
        """
        struct ipc_namespace {
            refcount_t count; // ~5.10
            struct ipc_ids {
                int in_use;
                unsigned short seq;
                struct rw_semaphore {
                    atomic_long_t count;
                    atomic_long_t owner;
                #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
                    struct optimistic_spin_queue osq;
                #endif
                    raw_spinlock_t wait_lock;
                    struct list_head wait_list;
                #ifdef CONFIG_DEBUG_RWSEMS
                    void *magic;
                #endif
                #ifdef CONFIG_DEBUG_LOCK_ALLOC
                    struct lockdep_map dep_map;
                #endif
                } rwsem;
                struct idr {
                    struct radix_tree_root { // =struct xarray
                        spinlock_t xa_lock;
                        gfp_t xa_flags;
                        void __rcu *xa_head;
                    } idr_rt;
                    unsigned int idr_base;
                    unsigned int idr_next;
                } ipcs_idr;
                int max_idx;
                int last_idx;
            #ifdef CONFIG_CHECKPOINT_RESTORE
                int next_id;
            #endif
                struct rhashtable key_ht;
            } ids[3];
            ...
        """
        kversion = Kernel.kernel_version()
        if kversion >= "5.11":
            self.offset_ids = 0
        else:
            self.offset_ids = current_arch.ptrsize
        if not self.quiet:
            info("offsetof(ipc_namespace, ids): {:#x}".format(self.offset_ids))

        # offsetof(ipc_ids, ipcs_idr.idr_rt.xa_head): tagged valid pointer is `xa_head`.
        # sizeof(ids[0]): find two `xa_head` and calculate the distance.
        init_ipc_ns = ipc_ns_list[0]
        found = []
        first_xa_flags = None
        for i in range(6, 120):
            base = self.offset_ids + current_arch.ptrsize * i
            """
            [x64 before using IPC]
            0xffffffff8b1841f8|+0x0038|+007: 0x0080000400000000 <- xa_lock, xa_flags
            0xffffffff8b184200|+0x0040|+008: 0x0000000000000000 <- xa_head
            0xffffffff8b184208|+0x0048|+009: 0x0000000000000000 <- idr_base, idr_next
            [x64 after using IPC]
            0xffffffff8b1841f8|+0x0038|+007: 0x0080000400000000
            0xffffffff8b184200|+0x0040|+008: 0xffff9250c7dc2002 ->  0x0000000000000001
            0xffffffff8b184208|+0x0048|+009: 0x0000000100000000
            [x64 after deleting IPC]
            0xffffffff8b1841f8|+0x0038|+007: 0x0080000400000000
            0xffffffff8b184200|+0x0040|+008: 0x0000000000000000
            0xffffffff8b184208|+0x0048|+009: 0x0000000100000000

            [x86 before using IPC]
            0xc1b4e104|+0x0024|+009: 0x00000000 <- xa_lock
            0xc1b4e108|+0x0028|+010: 0x00800004 <- xa_flags
            0xc1b4e10c|+0x002c|+011: 0x00000000 <- xa_head
            0xc1b4e110|+0x0030|+012: 0x00000000 <- idr_base
            0xc1b4e114|+0x0034|+013: 0x00000000 <- idr_next
            [x86 after using IPC]
            0xc1b4e104|+0x0024|+009: 0x00000000
            0xc1b4e108|+0x0028|+010: 0x00800004
            0xc1b4e10c|+0x002c|+011: 0xc2c67392  ->  0x00000001
            0xc1b4e110|+0x0030|+012: 0x00000000
            0xc1b4e114|+0x0034|+013: 0x00000001
            [x86 after deleting IPC]
            0xc1b4e104|+0x0024|+009: 0x00000000
            0xc1b4e108|+0x0028|+010: 0x00800004
            0xc1b4e10c|+0x002c|+011: 0x00000000
            0xc1b4e110|+0x0030|+012: 0x00000000
            0xc1b4e114|+0x0034|+013: 0x00000001
            """

            # xa_flags
            x = read_int_from_memory(init_ipc_ns + base - current_arch.ptrsize)
            if x == 0 or is_valid_addr(x):
                continue
            if first_xa_flags is not None and first_xa_flags != x:
                continue

            # xa_head
            y = read_int_from_memory(init_ipc_ns + base)
            if y:
                if not is_valid_addr(y):
                    continue
                if y & 0x2 != 0x2: # xa_head is NULL or tagged address
                    continue

            # idr_base, idr_next
            if is_32bit():
                z1 = read_int_from_memory(init_ipc_ns + base + current_arch.ptrsize) # idr_base
                z2 = read_int_from_memory(init_ipc_ns + base + current_arch.ptrsize * 2) # idr_next
                if is_valid_addr(z1) or is_valid_addr(z2):
                    continue
                if y and z1 == 0 and z2 == 0:
                    continue
            else:
                z = read_int_from_memory(init_ipc_ns + base + current_arch.ptrsize) # idr_base, idr_next
                if is_valid_addr(z): # idr_base, idr_next
                    continue
                if y and z == 0:
                    continue

            # found
            if self.offset_xa_head is None:
                self.offset_xa_head = base - self.offset_ids
                first_xa_flags = x
            found.append(base - self.offset_ids)

            # exit loop?
            if len(found) >= 2:
                self.sizeof_ipc_ids = found[1] - found[0]
                break
        else:
            if not self.quiet:
                err("Not found ipc_namespace->ids[0].ipcs_idr.idr_rt.xa_head")
                err("Not recognized sizeof(struct ipc_ids)")
            return False
        if not self.quiet:
            info("offsetof(ipc_ids, ipcs_idr.idr_rt.xa_head): {:#x}".format(self.offset_xa_head))
            info("sizeof(struct ipc_ids): {:#x}".format(self.sizeof_ipc_ids))

        # xa_node
        """
        struct xa_node {
            unsigned char shift;
            unsigned char offset;
            unsigned char count;
            unsigned char nr_values;
            struct xa_node __rcu *parent;
            struct xarray *array;
            union {
                struct list_head private_list;
                struct rcu_head rcu_head;
            };
            void __rcu *slots[XA_CHUNK_SIZE];
            union {
                unsigned long tags[XA_MAX_MARKS][XA_MARK_LONGS];
                unsigned long marks[XA_MAX_MARKS][XA_MARK_LONGS];
            };
        };
        """
        # xa_node->{shift,count,slots}
        self.offset_shift = 0
        self.offset_count = 2
        self.offset_slots = current_arch.ptrsize * 5

        # kern_ipc_perm
        """
        struct kern_ipc_perm {
            spinlock_t lock;
            bool deleted;
            int id;
            key_t key;
            kuid_t uid;
            kgid_t gid;
            kuid_t cuid;
            kgid_t cgid;
            umode_t mode;
            unsigned long seq;
            void *security;
            struct rhash_head khtnode;
            struct rcu_head rcu;
            refcount_t refcount;
        } ____cacheline_aligned_in_smp __randomize_layout;
        """
        self.offset_id = 4 + 4
        self.offset_key = self.offset_id + 4
        self.offset_uid = self.offset_key + 4
        self.offset_gid = self.offset_uid + 4
        self.offset_mode = self.offset_gid + 4 + 4 + 4

        self.initialized = True
        return True

    def parse_xarray(self, ptr, root=False):
        if ptr == 0:
            return []

        ptr &= ~3 # untagged

        if root:
            # ptr is &ipc_ids[i]
            node = read_int_from_memory(ptr + self.offset_xa_head)
            return self.parse_xarray(node)

        shift = u8(read_memory(ptr + self.offset_shift, 1))
        count = u8(read_memory(ptr + self.offset_count, 1))
        slots = ptr + self.offset_slots
        elems = []
        for i in range(64): # 16 or 64
            x = read_int_from_memory(slots + current_arch.ptrsize * i)
            if x == 0:
                continue
            if shift:
                elems += self.parse_xarray(x)
            else:
                elems.append(x)
            count -= 1
            if count == 0:
                break
        return elems

    def dump_ipc_sem_ids(self, ipc_ids_ptr):
        """
        struct sem_array {
            struct kern_ipc_perm sem_perm;
            time64_t sem_ctime;
            struct list_head pending_alter;
            struct list_head pending_const;
            struct list_head list_id;
            int sem_nsems;
            ...
        } __randomize_layout;
        """
        self.out.append(titlify("Semaphore Arrays"))
        fmt = "{:18s} {:5s} {:10s} {:4s} {:4s} {:5s} {:s}"
        legend = ["sem_array", "semid", "key", "uid", "gid", "perms", "nsems"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        elems = self.parse_xarray(ipc_ids_ptr, root=True)
        for e in elems:
            semid = u32(read_memory(e + self.offset_id, 4))
            key = u32(read_memory(e + self.offset_key, 4))
            uid = u32(read_memory(e + self.offset_uid, 4))
            gid = u32(read_memory(e + self.offset_gid, 4))
            mode = u16(read_memory(e + self.offset_mode, 2))

            if self.offset_sem_nsems is None:
                for i in range(1, 64):
                    base = self.offset_mode + current_arch.ptrsize * i
                    if all(is_valid_addr(read_int_from_memory(e + base + current_arch.ptrsize * j)) for j in range(6)):
                        self.offset_sem_nsems = base + current_arch.ptrsize * 6
                        break
            if self.offset_sem_nsems:
                nsems = read_int_from_memory(e + self.offset_sem_nsems)
                self.out.append("{:#018x} {:<5d} {:#010x} {:<4d} {:<4d} {:#5o} {:d}".format(
                    e, semid, key, uid, gid, mode, nsems,
                ))
            else:
                self.out.append("{:#018x} {:<5d} {:#010x} {:<4d} {:<4d} {:#5o} {:s}".format(
                    e, semid, key, uid, gid, mode, "?",
                ))

        return

    def dump_ipc_msg_ids(self, ipc_ids_ptr):
        """
        struct msg_queue {
            struct kern_ipc_perm q_perm;
            time64_t q_stime;
            time64_t q_rtime;
            time64_t q_ctime;
            unsigned long q_cbytes;
            unsigned long q_qnum;
            unsigned long q_qbytes;
            struct pid *q_lspid;
            struct pid *q_lrpid;
            struct list_head q_messages;
            struct list_head q_receivers;
            struct list_head q_senders;
        } __randomize_layout;
        """
        self.out.append(titlify("Message Queues"))
        fmt = "{:18s} {:5s} {:10s} {:4s} {:4s} {:5s} {:10s} {:8s}"
        legend = ["msg_queue", "msqid", "key", "uid", "gid", "perms", "used-bytes", "messages"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        elems = self.parse_xarray(ipc_ids_ptr, root=True)
        for e in elems:
            msqid = u32(read_memory(e + self.offset_id, 4))
            key = u32(read_memory(e + self.offset_key, 4))
            uid = u32(read_memory(e + self.offset_uid, 4))
            gid = u32(read_memory(e + self.offset_gid, 4))
            mode = u16(read_memory(e + self.offset_mode, 2))

            if self.offset_q_cbytes is None:
                for i in range(1, 64):
                    base = self.offset_mode + current_arch.ptrsize * i
                    if all(is_valid_addr(read_int_from_memory(e + base + current_arch.ptrsize * j)) for j in range(6)):
                        if not is_valid_addr(read_int_from_memory(e + base + current_arch.ptrsize * 6)):
                            self.offset_q_cbytes = base - current_arch.ptrsize * 5
                            self.offset_q_qnum = base - current_arch.ptrsize * 4
                            break
            if self.offset_q_cbytes:
                q_cbytes = read_int_from_memory(e + self.offset_q_cbytes)
                q_qnum = read_int_from_memory(e + self.offset_q_qnum)
                self.out.append("{:#018x} {:<5d} {:#010x} {:<4d} {:<4d} {:#5o} {:<#10x} {:<8d}".format(
                    e, msqid, key, uid, gid, mode, q_cbytes, q_qnum,
                ))
            else:
                self.out.append("{:#018x} {:<5d} {:#010x} {:<4d} {:<4d} {:#5o} {:10s} {:8s}".format(
                    e, msqid, key, uid, gid, mode, "?", "?",
                ))
        return

    def dump_ipc_shm_ids(self, ipc_ids_ptr):
        """
        struct shmid_kernel {
            struct kern_ipc_perm shm_perm;
            struct file *shm_file;
            unsigned long shm_nattch;
            unsigned long shm_segsz;
            ...
        } __randomize_layout;
        """
        self.out.append(titlify("Shared Memory Segments"))
        fmt = "{:18s} {:5s} {:10s} {:4s} {:4s} {:5s} {:10s} {:6s}"
        legend = ["shmid_kernel", "shmid", "key", "uid", "gid", "perms", "bytes", "nattch"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        elems = self.parse_xarray(ipc_ids_ptr, root=True)
        for e in elems:
            shmid = u32(read_memory(e + self.offset_id, 4))
            key = u32(read_memory(e + self.offset_key, 4))
            uid = u32(read_memory(e + self.offset_uid, 4))
            gid = u32(read_memory(e + self.offset_gid, 4))
            mode = u16(read_memory(e + self.offset_mode, 2))

            if self.offset_shm_nattch is None:
                for i in range(1, 64):
                    base = self.offset_mode + current_arch.ptrsize * i
                    x = read_int_from_memory(e + base)
                    y = read_int_from_memory(e + base + current_arch.ptrsize * 2)
                    if is_valid_addr(x) and y != 0 and y % 0x1000 == 0:
                        self.offset_shm_nattch = base + current_arch.ptrsize
                        self.offset_shm_segsz = base + current_arch.ptrsize * 2
                        break
            if self.offset_shm_nattch:
                nattch = read_int_from_memory(e + self.offset_shm_nattch)
                segsz = read_int_from_memory(e + self.offset_shm_segsz)
                self.out.append("{:#018x} {:<5d} {:#010x} {:<4d} {:<4d} {:#5o} {:<#10x} {:<6d}".format(
                    e, shmid, key, uid, gid, mode, segsz, nattch,
                ))
            else:
                self.out.append("{:#018x} {:<5d} {:#010x} {:<4d} {:<4d} {:#5o} {:10s} {:6s}".format(
                    e, shmid, key, uid, gid, mode, "?", "?",
                ))
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet
        if not self.quiet:
            info("Wait for memory scan")

        kversion = Kernel.kernel_version()
        if kversion < "4.20":
            # xarray is introduced from 4.20
            if not self.quiet:
                err("Unsupported v4.19 or before")
            return

        ipc_ns_list = self.get_all_ipc_ns()
        if self.initialize(ipc_ns_list) is False:
            if not self.quiet:
                err("Failed to initialize")
            return

        self.out = []
        for i, ipc_ns in enumerate(ipc_ns_list):
            if i == 0:
                self.out.append(titlify("init_ipc_ns: {:#x}".format(ipc_ns)))
            else:
                self.out.append(titlify("ipc_ns: {:#x}".format(ipc_ns)))
            self.dump_ipc_sem_ids(ipc_ns + self.offset_ids + self.sizeof_ipc_ids * 0)
            self.dump_ipc_msg_ids(ipc_ns + self.offset_ids + self.sizeof_ipc_ids * 1)
            self.dump_ipc_shm_ids(ipc_ns + self.offset_ids + self.sizeof_ipc_ids * 2)

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelDeviceIOCommand(GenericCommand):
    """Dump I/O-port and I/O-memory information."""
    _cmdline_ = "kdevio"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    _note_ = "Simplified ioport structure:\n"
    _note_ += "\n"
    _note_ += "+-ioport_resource-+       +-------->+-resource--------+\n"
    _note_ += "| start           |       |         | start           |\n"
    _note_ += "| end             |       |         | end             |\n"
    _note_ += "| name            |       |         | name            |\n"
    _note_ += "| flags           |       |         | flags           |\n"
    _note_ += "| desc            |       |         | desc            |\n"
    _note_ += "| parent          |-------+         | parent          |\n"
    _note_ += "| sibling         |--> resource     | sibling         |\n"
    _note_ += "| child           |--> resource     | child           |\n"
    _note_ += "+-----------------+                 +-----------------+\n"
    _note_ += "\n"
    _note_ += "Simplified iomem structure:\n"
    _note_ += "\n"
    _note_ += "+-iomem_resource--+       +-------->+-resource--------+\n"
    _note_ += "| start           |       |         | start           |\n"
    _note_ += "| end             |       |         | end             |\n"
    _note_ += "| name            |       |         | name            |\n"
    _note_ += "| flags           |       |         | flags           |\n"
    _note_ += "| desc            |       |         | desc            |\n"
    _note_ += "| parent          |-------+         | parent          |\n"
    _note_ += "| sibling         |--> resource     | sibling         |\n"
    _note_ += "| child           |--> resource     | child           |\n"
    _note_ += "+-----------------+                 +-----------------+"

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.sizeof_resource_size_t = None
        return

    def dump_resource(self, addr):
        if not is_valid_addr(addr):
            return []
        if addr in self.seen:
            return []
        self.seen.append(addr)

        if not self.sizeof_resource_size_t:
            name_ptr = read_int_from_memory(addr + 0x8 * 2) # sizeof(resource_size_t) == 8
            if name_ptr and is_valid_addr(name_ptr):
                name = read_cstring_from_memory(name_ptr)
                if name in ["PCI IO", "PCI mem"]:
                    self.sizeof_resource_size_t = 0x8

            if not self.sizeof_resource_size_t:
                name_ptr = read_int_from_memory(addr + 0x4 * 2) # sizeof(resource_size_t) == 4
                if name_ptr and is_valid_addr(name_ptr):
                    name = read_cstring_from_memory(name_ptr)
                    if name in ["PCI IO", "PCI mem"]:
                        self.sizeof_resource_size_t = 0x4

        """
        struct resource {
            resource_size_t start; // 4 or 8
            resource_size_t end; // 4 or 8
            const char *name;
            unsigned long flags;
            unsigned long desc; // v4.5~
            struct resource *parent, *sibling, *child;
        };
        """

        if self.sizeof_resource_size_t is None:
            err("Not recognized sizeof(resource_size_t)")
            return []
        elif self.sizeof_resource_size_t == 8:
            start = u64(read_memory(addr, 8))
            end = u64(read_memory(addr + 8, 8))
        elif self.sizeof_resource_size_t == 4:
            start = u32(read_memory(addr, 4))
            end = u32(read_memory(addr + 4, 4))
        name = read_cstring_from_memory(read_int_from_memory(addr + self.sizeof_resource_size_t * 2))
        flags = read_int_from_memory(addr + self.sizeof_resource_size_t * 2 + current_arch.ptrsize)

        ret = [(addr, start, end, name, flags)]

        kversion = Kernel.kernel_version()
        if kversion > "4.5":
            parent = read_int_from_memory(addr + self.sizeof_resource_size_t * 2 + current_arch.ptrsize * 3)
            ret += self.dump_resource(parent)
            sibling = read_int_from_memory(addr + self.sizeof_resource_size_t * 2 + current_arch.ptrsize * 4)
            ret += self.dump_resource(sibling)
            child = read_int_from_memory(addr + self.sizeof_resource_size_t * 2 + current_arch.ptrsize * 5)
            ret += self.dump_resource(child)
        else:
            parent = read_int_from_memory(addr + self.sizeof_resource_size_t * 2 + current_arch.ptrsize * 2)
            ret += self.dump_resource(parent)
            sibling = read_int_from_memory(addr + self.sizeof_resource_size_t * 2 + current_arch.ptrsize * 3)
            ret += self.dump_resource(sibling)
            child = read_int_from_memory(addr + self.sizeof_resource_size_t * 2 + current_arch.ptrsize * 4)
            ret += self.dump_resource(child)
        return ret

    def get_flags_str(self, flags_value):
        _flags = {
            "IORESOURCE_BUSY":                  0x80000000,
            "IORESOURCE_AUTO":                  0x40000000,
            "IORESOURCE_UNSET":                 0x20000000,
            "IORESOURCE_DISABLED":              0x10000000,
            "IORESOURCE_EXCLUSIVE":             0x08000000,
            "IORESOURCE_SYSRAM_MERGEABLE":      0x04000000,
            "IORESOURCE_SYSRAM_DRIVER_MANAGED": 0x02000000,
            "IORESOURCE_SYSRAM":                0x01000000,
            "IORESOURCE_MUXED":                 0x00400000,
            "IORESOURCE_WINDOW":                0x00200000,
            "IORESOURCE_MEM_64":                0x00100000,
            "IORESOURCE_STARTALIGN":            0x00080000,
            "IORESOURCE_SIZEALIGN":             0x00040000,
            "IORESOURCE_SHADOWABLE":            0x00020000,
            "IORESOURCE_RANGELENGTH":           0x00010000,
            "IORESOURCE_CACHEABLE":             0x00008000,
            "IORESOURCE_READONLY":              0x00004000,
            "IORESOURCE_PREFETCH":              0x00002000,
            "IORESOURCE_BUS":                   0x00001000,
            "IORESOURCE_DMA":                   0x00000800,
            "IORESOURCE_IRQ":                   0x00000400,
            "IORESOURCE_MEM":                   0x00000200,
            "IORESOURCE_IO":                    0x00000100,
        }
        flags = []
        for k, v in _flags.items():
            if flags_value & v:
                flags.append(k)

        if "IORESOURCE_IO" in flags and "IORESOURCE_MEM" in flags:
            flags.remove("IORESOURCE_IO")
            flags.remove("IORESOURCE_MEM")
            flags.append("IORESOURCE_REG")

        flags_str = " | ".join(flags)
        if flags_str == "":
            flags_str = "none"
        return flags_str.replace("IORESOURCE_", "")

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet
        if not self.quiet:
            info("Wait for memory scan")

        self.out = []

        # ioport
        ioport_resource = KernelAddressHeuristicFinder.get_ioport_resource()
        if not ioport_resource:
            err("Not found ioport_resource")
        else:
            info("ioport_resource: {:#x}".format(ioport_resource))

            self.seen = []
            resources = self.dump_resource(ioport_resource)
            if resources:
                name_width = max(len(res[3]) for res in resources)
            else:
                name_width = 4

            self.out.append(titlify("I/O-port"))
            fmt = "{:18s} {:17s} {:{:d}s} {:s}"
            legend = ["resource", "I/O address", "name", name_width, "flags"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

            for addr, start, end, name, flags in sorted(resources, key=lambda x: x[1]):
                self.out.append("{:#018x} {:#08x}-{:#08x} {:{:d}s} {:#010x} ({:s})".format(
                    addr, start, end, name, name_width, flags, self.get_flags_str(flags),
                ))

        # iomem
        iomem_resource = KernelAddressHeuristicFinder.get_iomem_resource()
        if not iomem_resource:
            err("Not found iomem_resource")
        else:
            info("iomem_resource: {:#x}".format(iomem_resource))

            self.seen = []
            resources = self.dump_resource(iomem_resource)
            if resources:
                name_width = max(len(res[3]) for res in resources)
            else:
                name_width = 4

            self.out.append(titlify("I/O-memory"))
            fmt = "{:18s} {:37s} {:{:d}s} {:s}"
            legend = ["resource", "Physical address", "name", name_width, "flags"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

            for addr, start, end, name, flags in sorted(resources, key=lambda x: x[1]):
                self.out.append("{:#018x} {:#018x}-{:#018x} {:{:d}s} {:#010x} ({:s})".format(
                    addr, start, end, name, name_width, flags, self.get_flags_str(flags),
                ))

        # print
        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelDmaBufCommand(GenericCommand):
    """Dump DMA-BUF information."""
    _cmdline_ = "kdmabuf"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    _note_ = "Simplified DMA-BUF structure:\n"
    _note_ += "\n"
    _note_ += "                 +-dma_buf-----+      +-dma_buf-----+\n"
    _note_ += "                 | size        |      | size        |\n"
    _note_ += "                 | file        |      | file        |\n"
    _note_ += "                 | ...         |      | ...         |\n"
    _note_ += "                 | exp_name    |      | exp_name    |\n"
    _note_ += "                 | name        |      | name        |\n"
    _note_ += "+---------+      | ...         |      | ...         |\n"
    _note_ += "| db_list |----->| list_node   |----->| list_node   |-->...\n"
    _note_ += "+---------+      | priv        |--+   | priv        |\n"
    _note_ += "                 | ...         |  |   | ...         |\n"
    _note_ += "                 +-------------+  |   +-------------+\n"
    _note_ += "                                  |\n"
    _note_ += "     +----------------------------+\n"
    _note_ += "     |\n"
    _note_ += "     +--->+-system_heap_buffer-+  +-->+-scatterlist--+\n"
    _note_ += "          | ...                |  |   | page_link    |----->+------+\n"
    _note_ += "          | len                |  |   | offset       |      | page |\n"
    _note_ += "          | sg_table           |  |   | length       |      +------+\n"
    _note_ += "          |   sgl              |--+   | ...          |\n"
    _note_ += "          |   ...              |      +--------------+\n"
    _note_ += "          | ...                |      | page_link    |-->page\n"
    _note_ += "          +--------------------+      | offset       |   or\n"
    _note_ += "                                      | length       |   scatterlist\n"
    _note_ += "                                      | ...          |\n"
    _note_ += "                                      +--------------+\n"
    _note_ += "                                      | ...          |\n"
    _note_ += "                                      +--------------+"

    def initialize(self):
        self.db_list = KernelAddressHeuristicFinder.get_db_list()
        if self.db_list is None:
            err("Not found db_list (maybe DMA_SHARED_BUFFER=n)")
            return False
        if not self.quiet:
            info("db_list: {:#x}".format(self.db_list))

        first_dma_buf = read_int_from_memory(self.db_list)
        if first_dma_buf == self.db_list:
            warn("Nothing to dump")
            return False

        """
        struct dma_buf {
            size_t size;
            struct file *file;
            struct list_head attachments;
            const struct dma_buf_ops *ops;
            unsigned vmapping_counter;
            struct iosys_map {
                union {
                    void __iomem *vaddr_iomem;
                    void *vaddr;
                };
                bool is_iomem;
            } vmap_ptr;
            const char *exp_name;
            const char *name;
            spinlock_t name_lock;
            struct module *owner;
            struct list_head list_node;
            void *priv; <-- struct system_heap_buffer*
            struct dma_resv *resv;
            wait_queue_head_t poll;
            ...
        }

        [v6.4 x64 example]
        0xffff8880135f8a00|+0x0000|+000: 0x0000000000001000  // size
        0xffff8880135f8a08|+0x0008|+001: 0xffff888000f85800  ->  0x0000000000000000 //file
        0xffff8880135f8a10|+0x0010|+002: 0xffff8880135f8a10  ->  [loop detected] // attachments
        0xffff8880135f8a18|+0x0018|+003: 0xffff8880135f8a10  ->  [loop detected]
        0xffff8880135f8a20|+0x0020|+004: 0xffffffff83e79d00 <system_heap_buf_ops>  ->  0x0000000000000000 // ops
        0xffff8880135f8a28|+0x0028|+005: 0x0000000000000000  // vmapping_counter
        0xffff8880135f8a30|+0x0030|+006: 0x0000000000000000  // vmap_ptr.vaddr_iomem
        0xffff8880135f8a38|+0x0038|+007: 0x0000000000000000  // vmap_ptr.is_iomem
        0xffff8880135f8a40|+0x0040|+008: 0xffffffff8482754e <linux_banner+0x6d70ae>  ->  0x6e006d6574737973 ('system'?) // exp_name
        0xffff8880135f8a48|+0x0048|+009: 0x0000000000000000  // name
        0xffff8880135f8a50|+0x0050|+010: 0xdead4ead00000000  // name_lock
        0xffff8880135f8a58|+0x0058|+011: 0x00000000ffffffff
        0xffff8880135f8a60|+0x0060|+012: 0xffffffffffffffff
        0xffff8880135f8a68|+0x0068|+013: 0xffffffff883cc330 <__key.7>  ->  0x0000000000000000
        0xffff8880135f8a70|+0x0070|+014: 0x0000000000000000
        0xffff8880135f8a78|+0x0078|+015: 0x0000000000000000
        0xffff8880135f8a80|+0x0080|+016: 0xffffffff847790c3 <linux_banner+0x628c23>  ->  '&dmabuf->name_lock'
        0xffff8880135f8a88|+0x0088|+017: 0x0000000000000200
        0xffff8880135f8a90|+0x0090|+018: 0x0000000000000000  // owner
        0xffff8880135f8a98|+0x0098|+019: 0xffff8880135f8c98  ->  0xffffffff883cc360 <db_list>  ->  [loop detected] // list_node
        0xffff8880135f8aa0|+0x00a0|+020: 0xffffffff883cc360 <db_list>  ->  0xffff8880135f8a98  ->  0xffff8880135f8c98  ->  ...
        0xffff8880135f8aa8|+0x00a8|+021: 0xffff88800f978600  ->  0xffff88800c96bc00  ->  0xffffffff8482754e <linux_banner+0x6d70ae>  ->  ... // priv
        0xffff8880135f8ab0|+0x00b0|+022: 0xffff8880135f8b58  ->  0x0000000000000000
        0xffff8880135f8ab8|+0x00b8|+023: 0xdead4ead00000000
        0xffff8880135f8ac0|+0x00c0|+024: 0x00000000ffffffff
        0xffff8880135f8ac8|+0x00c8|+025: 0xffffffffffffffff
        """
        for i in range(1, 50):
            a = read_int_from_memory(first_dma_buf - current_arch.ptrsize * (i + 4))
            b = read_int_from_memory(first_dma_buf - current_arch.ptrsize * (i + 3))
            c = read_int_from_memory(first_dma_buf - current_arch.ptrsize * (i + 2))
            d = read_int_from_memory(first_dma_buf - current_arch.ptrsize * (i + 1))
            e = read_int_from_memory(first_dma_buf - current_arch.ptrsize * (i + 0))

            # size check
            if is_valid_addr(a):
                continue
            # file check
            if not is_valid_addr(b):
                continue
            # attachments check
            if not is_valid_addr(c) or not is_valid_addr(d):
                continue
            # ops check
            if not is_valid_addr(e):
                continue

            self.offset_list_node = current_arch.ptrsize * (i + 4)
            if not self.quiet:
                info("offsetof(dma_buf, list_node): {:#x}".format(self.offset_list_node))
            break
        else:
            err("Not found dma_buf->list_node")
            return False

        # dma_buf->{size,file,priv}
        self.offset_size = 0
        self.offset_file = current_arch.ptrsize
        self.offset_priv = self.offset_list_node + current_arch.ptrsize * 2
        if not self.quiet:
            info("offsetof(dma_buf, size): {:#x}".format(self.offset_size))
            info("offsetof(dma_buf, file): {:#x}".format(self.offset_file))
            info("offsetof(dma_buf, priv): {:#x}".format(self.offset_priv))

        # dma_buf->{exp_name,name}
        for i in range(1, 50):
            top = first_dma_buf - self.offset_list_node
            x = read_int_from_memory(top + current_arch.ptrsize * i)
            s = read_cstring_from_memory(x)
            if s and len(s) >= 3:
                self.offset_exp_name = current_arch.ptrsize * i
                self.offset_name = current_arch.ptrsize * (i + 1)
                if not self.quiet:
                    info("offsetof(dma_buf, exp_name): {:#x}".format(self.offset_exp_name))
                    info("offsetof(dma_buf, name): {:#x}".format(self.offset_name))
                break
        else:
            err("Not found dma_buf->{exp_name,name}")
            return False

        """
        struct system_heap_buffer {
            struct dma_heap *heap;
            struct list_head attachments;
            struct mutex lock;
            unsigned long len;
            struct sg_table {
                struct scatterlist *sgl;
                unsigned int nents;
                unsigned int orig_nents;
            } sg_table;
            int vmap_cnt;
            void *vaddr;
        };
        """
        # system_heap_buffer->sg_table
        size = read_int_from_memory(first_dma_buf - self.offset_list_node + self.offset_size)
        priv = read_int_from_memory(first_dma_buf - self.offset_list_node + self.offset_priv)
        for i in range(50):
            x = read_int_from_memory(priv + current_arch.ptrsize * i)
            if x == size:
                self.offset_sg_table = current_arch.ptrsize * (i + 1)
                break
        else:
            err("Not found system_heap_buffer->sg_table")
            return False
        if not self.quiet:
            info("offsetof(system_heap_buffer, sg_table): {:#x}".format(self.offset_sg_table))
        return True

    def dump_sgl(self, sg):
        while True:
            page_link = read_int_from_memory(sg)

            # check if chain
            if page_link & 1: # SG_CHAIN
                sg = page_link & ~3
                continue

            # output page, phys, virt
            page = page_link & ~3

            phys = None
            phys_str = "???"
            ret = gdb.execute("page2phys {:#x}".format(page), to_string=True)
            r = re.search(r"Page: \S+ -> Phys: (\S+)", ret)
            if r:
                phys = int(r.group(1), 16)
                phys_str = "{:#018x}".format(phys)

            virt_str = "???"
            if phys:
                r = Kernel.p2v(phys)
                if r:
                    r = [hex(x) for x in r if AddressUtil.is_msb_on(x)]
                    virt_str = ",".join(r)

            offset = u32(read_memory(sg + current_arch.ptrsize, 4))
            length = u32(read_memory(sg + current_arch.ptrsize + 4, 4))

            self.out.append("  page: {:#018x}  offset: {:#010x}  length: {:#010x}  phys: {:18s}  virt: {:s}".format(
                page, offset, length, phys_str, virt_str,
            ))

            # check if end
            if page_link & 2: # SG_END:
                break

            # calc sizeof(scatterlist) then go to next
            """
            struct scatterlist {
                unsigned long page_link;
                unsigned int offset;
                unsigned int length;
                dma_addr_t dma_address;
            #ifdef CONFIG_NEED_SG_DMA_LENGTH
                unsigned int dma_length;
            #endif
            #ifdef CONFIG_PCI_P2PDMA
                unsigned int dma_flags;
            #endif
            };
            """
            sg += current_arch.ptrsize + 4 * 2 + current_arch.ptrsize
            if not is_valid_addr(read_int_from_memory(sg)):
                sg += current_arch.ptrsize
            if not is_valid_addr(read_int_from_memory(sg)):
                sg += current_arch.ptrsize
        return

    def dump_db_list(self):
        fmt = "{:18s} {:18s} {:16s} {:16s} {:18s} {:18s}"
        legend = ["dma_buf", "size", "exp_name", "name", "file", "priv"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        seen = [self.db_list]
        current = read_int_from_memory(self.db_list)
        while True:
            if not is_valid_addr(current):
                break
            if current in seen:
                break
            seen.append(current)

            # calc top
            dma_buf = current - self.offset_list_node

            # size, file, priv
            size = read_int_from_memory(dma_buf + self.offset_size)
            file = read_int_from_memory(dma_buf + self.offset_file)
            priv = read_int_from_memory(dma_buf + self.offset_priv)

            # exp_name
            exp_name_p = read_int_from_memory(dma_buf + self.offset_exp_name)
            exp_name = read_cstring_from_memory(exp_name_p)

            # name
            name_p = read_int_from_memory(dma_buf + self.offset_name)
            if is_valid_addr(name_p):
                name = read_cstring_from_memory(name_p)
            else:
                name = "<none>"

            # dump
            self.out.append("{:#018x} {:#018x} {:16s} {:16s} {:#018x} {:#018x}".format(
                dma_buf, size, exp_name, name, file, priv,
            ))

            # dump sgl
            sgl = read_int_from_memory(priv + self.offset_sg_table)
            self.dump_sgl(sgl)

            # go to next
            current = read_int_from_memory(current)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet
        if not self.quiet:
            info("Wait for memory scan")

        kversion = Kernel.kernel_version()
        if kversion < "5.11":
            err("Unsupported v5.10 or before")
            return

        ret = self.initialize()
        if ret is False:
            return

        self.out = []
        self.dump_db_list()

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelIrqCommand(GenericCommand):
    """Dump IRQ (interrupt request) information."""
    _cmdline_ = "kirq"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="enable verbose mode.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    _note_ = "Simplified irq structure:\n"
    _note_ += "\n"
    _note_ += "+-irq_desc_tree(~6.5)-+   +--->+-xa_node---------+   +--->+-irq_desc----+\n"
    _note_ += "| xa_lock             |   |    | shift           |   |    | ...         |\n"
    _note_ += "| xa_flags            |   |    | ...             |   |    | irq_data    |\n"
    _note_ += "| xa_head             |---+    | count           |   |    |   ...       |\n"
    _note_ += "+---------------------+        | ...             |   |    |   irq       |\n"
    _note_ += "                               | slots[0]        |---+    |   ...       |\n"
    _note_ += "                               | slots[1]        |   ^    | ...         |\n"
    _note_ += "                               | ...             |   |    | action      |\n"
    _note_ += "                               | slots[15 or 63] |   |    |   handler   |\n"
    _note_ += "                               | ...             |   |    |   ...       |\n"
    _note_ += "                               +-----------------+   |    |   name      |\n"
    _note_ += "                                                     |    |   ...       |\n"
    _note_ += "+-sparce_irq(6.5~)-+   +-->+-maple_node------+       |    | ...         |\n"
    _note_ += "| ...              |   |   | ...             |       |    +-------------+\n"
    _note_ += "| ma_root          |---+   | mr64|ma64|alloc |       |\n"
    _note_ += "| ...              |       |   ...           |       |\n"
    _note_ += "+------------------+       |   slot[]        |-------+\n"
    _note_ += "                           +-----------------+"

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        return

    def parse_xarray(self, ptr, root=False):
        if ptr == 0:
            return []

        ptr &= ~3 # untagged

        if root:
            node = read_int_from_memory(ptr + self.offset_xa_head)
            return self.parse_xarray(node)

        shift = u8(read_memory(ptr + self.offset_shift, 1))
        count = u8(read_memory(ptr + self.offset_count, 1))
        slots = ptr + self.offset_slots
        elems = []
        for i in range(64): # 16 or 64
            x = read_int_from_memory(slots + current_arch.ptrsize * i)
            if x == 0:
                continue
            if shift:
                elems += self.parse_xarray(x)
            else:
                elems.append(x)
            count -= 1
            if count == 0:
                break
        return elems

    class MapleTree:
        """Linux v6.5 introduces maple_tree to irq. This is a simple parser."""
        MT_FLAGS_HEIGHT_MASK = 0x7c
        MT_FLAGS_HEIGHT_OFFSET = 0x02
        MAPLE_NODE_TYPE_SHIFT = 0x03
        MAPLE_NODE_TYPE_MASK = 0x0f
        MAPLE_NODE_POINTER_MASK = 0xff
        MAPLE_DENSE = 0
        MAPLE_LEAF_64 = 1
        MAPLE_RANGE_64 = 2
        MAPLE_ARANGE_64 = 3

        def __init__(self, ptr):
            kversion = Kernel.kernel_version()

            # ____cacheline_aligned_in_smp attribute, spinlock_t and lockdep_map_p can be different size
            # in each environment or situation, so search heuristically.
            for i in range(0x10):
                x = read_int_from_memory(ptr + current_arch.ptrsize * i)
                """
                [x64 v6.4.2]
                0xffff8bedc104db00|+0x0000|+000: 0x0000000000000000   // union
                0xffff8bedc104db08|+0x0008|+001: 0xffff8bedc1a6601e   // ma_root
                0xffff8bedc104db10|+0x0010|+002: 0x000000000000030b   // ma_flags

                [x64 v6.6.1]
                0xffff972801b78a38|+0x0040|+008: 0x0000000000000000   // (the end of cacheline?)
                0xffff972801b78a40|+0x0040|+008: 0x0000030b00000000   // ma_flags || union
                0xffff972801b78a48|+0x0048|+009: 0xffff972801b0cc1e   // ma_root
                """
                if is_valid_addr(x) and (x & 0xff) in [0x1e, 0x0e]:
                    offset_ma_root = current_arch.ptrsize * i
                    if kversion < "6.6":
                        offset_ma_flags = offset_ma_root + current_arch.ptrsize
                    else:
                        offset_ma_flags = offset_ma_root - 4
                        if is_64bit() and u32(read_memory(ptr + offset_ma_flags, 4)) == 0:
                            offset_ma_flags = offset_ma_root - 8
                    break
            else:
                raise

            self.ma_root_raw = read_int_from_memory(ptr + offset_ma_root)
            self.ma_flags = read_int_from_memory(ptr + offset_ma_flags)
            self.max_depth = (self.ma_flags & self.MT_FLAGS_HEIGHT_MASK) >> self.MT_FLAGS_HEIGHT_OFFSET

            if is_64bit():
                self.MAPLE_NODE_SLOTS = 31
                self.MAPLE_RANGE64_SLOTS = 16
                self.MAPLE_ARANGE64_SLOTS = 10
                self.MAPLE_ALLOC_SLOTS = self.MAPLE_NODE_SLOTS - 1
                self.maple_range_64_offset_slot = current_arch.ptrsize * self.MAPLE_RANGE64_SLOTS
                self.maple_arange_64_offset_slot = current_arch.ptrsize * self.MAPLE_ARANGE64_SLOTS
                self.maple_alloc_offset_slot = current_arch.ptrsize * 2
            else:
                self.MAPLE_NODE_SLOTS = 63
                self.MAPLE_RANGE64_SLOTS = 32
                self.MAPLE_ARANGE64_SLOTS = 21
                self.MAPLE_ALLOC_SLOTS = self.MAPLE_NODE_SLOTS - 2
                self.maple_range_64_offset_slot = current_arch.ptrsize * self.MAPLE_RANGE64_SLOTS
                self.maple_arange_64_offset_slot = current_arch.ptrsize * self.MAPLE_ARANGE64_SLOTS
                self.maple_alloc_offset_slot = current_arch.ptrsize * 3

            self.seen = set()
            self.iters = self.parse_node(self.ma_root_raw, 1)
            return

        def parse_node(self, entry, depth):
            if entry in self.seen:
                return
            self.seen.add(entry)

            if self.max_depth < depth:
                return

            pointer = entry & ~(self.MAPLE_NODE_POINTER_MASK)
            node_type = (entry >> self.MAPLE_NODE_TYPE_SHIFT) & self.MAPLE_NODE_TYPE_MASK

            if node_type == self.MAPLE_DENSE:
                slot_top = pointer + self.maple_alloc_offset_slot
                for i in range(self.MAPLE_ALLOC_SLOTS):
                    slot = read_int_from_memory(slot_top + current_arch.ptrsize * i)
                    if (slot & ~(self.MAPLE_NODE_TYPE_MASK)) != 0:
                        if is_valid_addr(slot):
                            yield slot
            elif node_type == self.MAPLE_LEAF_64:
                slot_top = pointer + self.maple_range_64_offset_slot
                for i in range(self.MAPLE_RANGE64_SLOTS):
                    slot = read_int_from_memory(slot_top + current_arch.ptrsize * i)
                    if (slot & ~(self.MAPLE_NODE_TYPE_MASK)) != 0:
                        if is_valid_addr(slot):
                            yield slot
            elif node_type == self.MAPLE_RANGE_64:
                slot_top = pointer + self.maple_range_64_offset_slot
                for i in range(self.MAPLE_RANGE64_SLOTS):
                    slot = read_int_from_memory(slot_top + current_arch.ptrsize * i)
                    if (slot & ~(self.MAPLE_NODE_TYPE_MASK)) != 0:
                        yield from self.parse_node(slot, depth + 1)
            elif node_type == self.MAPLE_ARANGE_64:
                slot_top = pointer + self.maple_arange_64_offset_slot
                for i in range(self.MAPLE_ARANGE64_SLOTS):
                    slot = read_int_from_memory(slot_top + current_arch.ptrsize * i)
                    if (slot & ~(self.MAPLE_NODE_TYPE_MASK)) != 0:
                        yield from self.parse_node(slot, depth + 1)
            return

    def initialize(self):
        if self.initialized:
            return True

        kversion = Kernel.kernel_version()

        if kversion < "6.5":
            self.irq_desc_tree = KernelAddressHeuristicFinder.get_irq_desc_tree()
            if self.irq_desc_tree is None:
                if not self.quiet:
                    err("Not found irq_desc_tree")
                return False

            for i in range(0, 10):
                # xa_head
                x = read_int_from_memory(self.irq_desc_tree + current_arch.ptrsize * i)
                if not x:
                    continue
                if not is_valid_addr(x):
                    continue
                if x & 0x2 != 0x2: # xa_head is NULL or tagged address
                    continue
                self.offset_xa_head = current_arch.ptrsize * i
                if not self.quiet:
                    info("offsetof(xarray, xa_head): {:#x}".format(self.offset_xa_head))
                break
            else:
                if not self.quiet:
                    err("Not found xa_head. (maybe uninitialized?)")
                return False

            # xa_node
            """
            struct xa_node {
                unsigned char shift;
                unsigned char offset;
                unsigned char count;
                unsigned char nr_values;
                struct xa_node __rcu *parent;
                struct xarray *array;
                union {
                    struct list_head private_list;
                    struct rcu_head rcu_head;
                };
                void __rcu *slots[XA_CHUNK_SIZE];
                union {
                    unsigned long tags[XA_MAX_MARKS][XA_MARK_LONGS];
                    unsigned long marks[XA_MAX_MARKS][XA_MARK_LONGS];
                };
            };
            """
            # xa_node->{shift,count,slots}
            self.offset_shift = 0
            self.offset_count = 2
            self.offset_slots = current_arch.ptrsize * 5

            descs = self.parse_xarray(self.irq_desc_tree, root=True)

        else:
            # kversion >= 6.5
            self.sparse_irqs = KernelAddressHeuristicFinder.get_sparse_irqs()
            if self.sparse_irqs is None:
                if not self.quiet:
                    err("Not found sparse_irqs")
                return False

            descs = list(self.MapleTree(self.sparse_irqs).iters)

        if not descs:
            if not self.quiet:
                err("Not found any valid irq_desc")
            return False

        # irq_desc->{irq,action}
        """
        struct irq_desc {
            struct irq_common_data {
                unsigned int __private state_use_accessors;
            #ifdef CONFIG_NUMA
                unsigned int node;
            #endif
                void *handler_data;
                struct msi_desc *msi_desc;
            #ifdef CONFIG_SMP
                cpumask_var_t affinity;
            #endif
            #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
                cpumask_var_t effective_affinity;
            #endif
            #ifdef CONFIG_GENERIC_IRQ_IPI
                unsigned int ipi_offset;
            #endif
            } irq_common_data;
            struct irq_data {
                u32 mask;
                unsigned int irq;
                unsigned long hwirq;
                struct irq_common_data *common;
                struct irq_chip *chip;
                struct irq_domain *domain;
            #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
                struct irq_data *parent_data;
            #endif
                void *chip_data;
            } irq_data;
            unsigned int __percpu *kstat_irqs;
            irq_flow_handler_t handle_irq;
            struct irqaction *action;
            unsigned int status_use_accessors;
            unsigned int core_internal_state__do_not_mess_with_it;
            ...
        };
        """

        if is_x86():
            desc = descs[0]
        else:
            # ARM may have invalid descs[irq=0]
            desc = descs[-1]
        if not self.quiet:
            info("desc: {:#x}".format(desc))

        for i in range(100):
            x = read_int_from_memory(desc + current_arch.ptrsize * i)
            if x == desc:
                if is_32bit():
                    self.offset_irq = current_arch.ptrsize * i - 8
                else:
                    self.offset_irq = current_arch.ptrsize * i - 12 # for padding
                if not self.quiet:
                    info("offsetof(irq_desc, irq_data.irq): {:#x}".format(self.offset_irq))
                break
        else:
            if not self.quiet:
                err("Not found irq_desc->irq_data.irq")
            return False

        ofs_irq = AddressUtil.align_address_to_size(self.offset_irq + 4 * 2, current_arch.ptrsize)
        for i in range(100):
            x = read_int_from_memory(desc + ofs_irq + current_arch.ptrsize * i)
            y = read_int_from_memory(desc + ofs_irq + current_arch.ptrsize * (i + 1))
            if not is_valid_addr(x) and not is_valid_addr(y):
                ofs_action_candidate = ofs_irq + current_arch.ptrsize * i - current_arch.ptrsize
                action_candidate = read_int_from_memory(desc + ofs_action_candidate)
                if is_valid_addr_addr(action_candidate):
                    self.offset_action = ofs_action_candidate
                    if not self.quiet:
                        info("offsetof(irq_desc, action): {:#x}".format(self.offset_action))
                    break
        else:
            if not self.quiet:
                err("Not found irq_desc->action")
            return False

        # irqaction->{handler,name}
        """
        struct irqaction {
            irq_handler_t handler;
            void *dev_id;
            void __percpu *percpu_dev_id;
            struct irqaction *next;
            irq_handler_t thread_fn;
            struct task_struct *thread;
            struct irqaction *secondary;
            unsigned int irq;
            unsigned int flags;
            unsigned long thread_flags;
            unsigned long thread_mask;
            const char *name;
            struct proc_dir_entry *dir;
        } ____cacheline_internodealigned_in_smp;
        """
        self.offset_handler = 0
        if not self.quiet:
            info("offsetof(irqaction, handler): {:#x}".format(self.offset_handler))

        action = read_int_from_memory(desc + self.offset_action)
        for i in range(100):
            x = read_int_from_memory(action + current_arch.ptrsize * i)
            if not is_valid_addr(x):
                continue
            s = read_cstring_from_memory(x)
            if s and len(s) >= 4:
                self.offset_name = current_arch.ptrsize * i
                if not self.quiet:
                    info("offsetof(irqaction, name): {:#x}".format(self.offset_name))
                break
        else:
            if not self.quiet:
                err("Not found irqaction->name")
            return False

        return True

    def dump_irq(self, verbose):
        kversion = Kernel.kernel_version()

        if kversion < "6.5":
            descs = self.parse_xarray(self.irq_desc_tree, root=True)
        else:
            descs = list(self.MapleTree(self.sparse_irqs).iters)

        entries = {}
        for desc in descs:
            irq = u32(read_memory(desc + self.offset_irq, 4))
            action = read_int_from_memory(desc + self.offset_action)
            if action == 0:
                entries[irq] = [desc, action, None, None]
            else:
                handler = read_int_from_memory(action + self.offset_handler)
                name_ptr = read_int_from_memory(action + self.offset_name)
                name = read_cstring_from_memory(name_ptr)
                entries[irq] = [desc, action, handler, name]

        fmt = "{:3s} {:18s} {:18s} {:24s} {:18s}"
        legend = ["irq", "irq_desc", "action", "name", "handler"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        for i in range(256):
            if i in entries:
                desc, action, handler, name = entries[i]
                if action:
                    symbol = Symbol.get_symbol_string(handler, nosymbol_string=" <NO_SYMBOL>")
                    self.out.append("{:3d} {:#018x} {:#018x} {:24s} {:#018x}{:s}".format(i, desc, action, name, handler, symbol))
                else:
                    self.out.append("{:3d} {:#018x} {:18s} {:24s} {:18s}".format(i, desc, "unused", "-", "-"))
            else:
                if verbose:
                    self.out.append("{:3d} {:18s} {:18s} {:24s} {:18s}".format(i, "unused", "unused", "-", "-"))
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet
        if not self.quiet:
            info("Wait for memory scan")

        kversion = Kernel.kernel_version()
        if kversion < "4.20":
            # xarray is introduced from 4.20
            if not self.quiet:
                err("Unsupported v4.19 or before")
            return

        ret = self.initialize()
        if ret is False:
            return

        self.out = []
        self.dump_irq(args.verbose)

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class KernelNetDeviceCommand(GenericCommand):
    """Dump net device information."""
    _cmdline_ = "knetdev"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    _note_ = "Simplified net_device structure:\n"
    _note_ += "\n"
    _note_ += "                     +-net_device--------+    +-net_device--------+\n"
    _note_ += "                     | ... (kernel 6.8~) |    | ... (kernel 6.8~) |\n"
    _note_ += "+-init_net------+    | name[]            |    | name[]            |\n"
    _note_ += "| ...           |    | ...               |    | ...               |\n"
    _note_ += "| dev_base_head |--->| dev_list          |--->| dev_list          |--->...\n"
    _note_ += "| ...           |    | ...               |    | ...               |\n"
    _note_ += "+---------------+    +-------------------+    +-------------------+"

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        return

    def initialize(self):
        if self.initialized:
            return True

        # init_net
        self.init_net = KernelAddressHeuristicFinder.get_init_net()
        if self.init_net is None:
            if not self.quiet:
                err("Not found init_net")
            return False
        if not self.quiet:
            info("init_net: {:#x}".format(self.init_net))

        """
        struct net {
            ...
            struct list_head dev_base_head;
            ...
        };

        struct net_device {
            char name[IFNAMSIZ];
            ...
            struct list_head dev_list;  // dev_base_head points here
            struct list_head napi_list;
            struct list_head unreg_list;
            struct list_head close_list;
            struct list_head ptype_all;
            struct list_head ptype_specific; // ~v6.8
            ...
        };
        """
        # net->dev_base_head
        for i in range(0x100):
            candidate_offset = current_arch.ptrsize * i

            addr = self.init_net + candidate_offset
            if not is_double_link_list(addr):
                continue

            cand_netdev = read_int_from_memory(addr)
            if not is_double_link_list(cand_netdev + current_arch.ptrsize * 2): # napi_list
                continue
            if not is_double_link_list(cand_netdev + current_arch.ptrsize * 4): # unreg_list
                continue
            if not is_double_link_list(cand_netdev + current_arch.ptrsize * 6): # close_list
                continue
            if not is_double_link_list(cand_netdev + current_arch.ptrsize * 8): # ptype_all
                continue
            break # found
        else:
            if not self.quiet:
                err("Not found net->dev_base_head")
            return False

        self.offset_dev_base_head = candidate_offset
        if not self.quiet:
            info("offsetof(net, dev_base_head): {:#x}".format(self.offset_dev_base_head))

        # net_device->dev_list
        netdev_dev_list = read_int_from_memory(self.init_net + self.offset_dev_base_head)
        for i in range(0x20):
            candidate_offset = current_arch.ptrsize * i
            if read_cstring_from_memory(netdev_dev_list - candidate_offset) == "lo":
                break
        else:
            if not self.quiet:
                err("Not found net_device->dev_list")
            return False

        self.offset_dev_list = candidate_offset
        if not self.quiet:
            info("offsetof(net_device, dev_list): {:#x}".format(self.offset_dev_list))

        return True

    def dump_net(self):
        fmt = "{:18s} {:s}"
        legend = ["net_device", "name"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        # `struct net_device` is a very complex struct, and detecting the offset of its members is very difficult.
        # My best effort is to detect only names and addresses.

        head = current = self.init_net + self.offset_dev_base_head
        while True:
            current = read_int_from_memory(current)
            if current == head:
                break

            netdev = current - self.offset_dev_list
            name = read_cstring_from_memory(netdev)
            self.out.append("{:#018x} {:s}".format(netdev, name))

        kversion = Kernel.kernel_version()
        if kversion >= "6.8":
            info("In kernel 6.8 and later, the order of the members of `struct net_device` has changed significantly.")
            info("Please note that the address detected as `net_device` is precisely the address of &net_device.name.")
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet
        if not self.quiet:
            info("Wait for memory scan")

        ret = self.initialize()
        if ret is False:
            return

        self.out = []
        self.dump_net()

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class VmallocDumpCommand(GenericCommand):
    """Dump vmalloc used list and freed list."""
    _cmdline_ = "vmalloc-dump"
    _category_ = "08-e. Qemu-system Cooperation - Linux Allocator"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--only-used", action="store_true", help="display only used area")
    parser.add_argument("--only-freed", action="store_true", help="display only freed area")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -q".format(_cmdline_)

    _note_ = "Simplified vmalloc structure:\n"
    _note_ += "\n"
    _note_ += "                           +-vmap_area--+\n"
    _note_ += "                           | va_start   |\n"
    _note_ += "                           | va_end     |\n"
    _note_ += "+---------------------+    | ...        |\n"
    _note_ += "| vmap_area_list      |--->| list       |--->...\n"
    _note_ += "+---------------------+    | ...        |\n"
    _note_ += "                           | vm         |----+\n"
    _note_ += "                           | ...        |    |\n"
    _note_ += "                           +------------+    |\n"
    _note_ += "                                             |\n"
    _note_ += "                       +---------------------+\n"
    _note_ += "                       |\n"
    _note_ += "                       +-->+-vm_struct--+\n"
    _note_ += "                           | ...        |\n"
    _note_ += "                           | flags      |\n"
    _note_ += "                           | ...        |\n"
    _note_ += "                           +------------+\n"
    _note_ += "\n"
    _note_ += "                           +-vmap_area--+\n"
    _note_ += "                           | va_start   |\n"
    _note_ += "(This also exists v5.2~)   | va_end     |\n"
    _note_ += "+---------------------+    | ...        |\n"
    _note_ += "| free_vmap_area_list |--->| list       |--->...\n"
    _note_ += "+---------------------+    | ...        |\n"
    _note_ += "                           +------------+"

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        return

    def initialize(self):
        if self.initialized:
            return True

        """
        struct vmap_area {
            unsigned long va_start;
            unsigned long va_end;
            unsigned long subtree_max_size; // 5.2~5.3
            unsigned long flags;            // ~5.3
            struct rb_node {
                unsigned long __rb_parent_color;
                struct rb_node *rb_right;
                struct rb_node *rb_left;
            } rb_node;
            struct list_head list;
            union {                             // 5.4~
                unsigned long subtree_max_size; // 5.4~
                struct vm_struct *vm;           // 5.4~
                struct llist_node purge_list;   // 5.4~5.10
            };                                  // 5.4~
            struct llist_node purge_list; // 4.7~5.3
            struct list_head purge_list;  // ~4.7
            struct vm_struct *vm;         // ~5.3
            unsigned long flags; // 6.3~
        };

        struct vm_struct {
            struct vm_struct *next;
            void *addr;
            unsigned long size;
            unsigned long flags;
            struct page **pages;
        #ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC // 5.13~
            unsigned int page_order;         // 5.13~
        #endif                               // 5.13~
            unsigned int nr_pages;
            phys_addr_t phys_addr;
            const void *caller;
        };
        """

        kversion = Kernel.kernel_version()

        self.vmap_area_list = KernelAddressHeuristicFinder.get_vmap_area_list()
        if not self.vmap_area_list:
            if not self.quiet:
                err("Not found vmap_area_list")
        else:
            if not self.quiet:
                info("vmap_area_list: {:#x}".format(self.vmap_area_list))

        if kversion and kversion >= "5.2":
            self.free_vmap_area_list = KernelAddressHeuristicFinder.get_free_vmap_area_list()
            if not self.free_vmap_area_list:
                if not self.quiet:
                    err("Not found free_vmap_area_list")
            else:
                if not self.quiet:
                    info("free_vmap_area_list: {:#x}".format(self.free_vmap_area_list))
        else:
            self.free_vmap_area_list = None

        if not self.vmap_area_list and not self.free_vmap_area_list:
            return False

        # vmap_area->list
        if kversion and kversion >= "5.4":
            self.offset_list = current_arch.ptrsize * 5
        elif kversion and kversion >= "5.2":
            self.offset_list = current_arch.ptrsize * 7
        else:
            self.offset_list = current_arch.ptrsize * 6
        if not self.quiet:
            info("offsetof(vmap_area, list): {:#x}".format(self.offset_list))

        # vmap_area->vm
        if kversion and kversion >= "5.4":
            self.offset_vm = self.offset_list + current_arch.ptrsize * 2
        elif kversion and kversion >= "4.7":
            self.offset_vm = self.offset_list + current_arch.ptrsize * 3
        else:
            self.offset_vm = self.offset_list + current_arch.ptrsize * 4
        if not self.quiet:
            info("offsetof(vmap_area, vm): {:#x}".format(self.offset_vm))

        # vm_struct->flags
        self.offset_flags = current_arch.ptrsize * 3
        if not self.quiet:
            info("offsetof(vm_struct, flags): {:#x}".format(self.offset_flags))

        self.initialized = True
        return True

    def parse_vmap_area_list(self, head, used):
        if head is None or not is_valid_addr(head):
            return []

        seen = [head]
        current = read_int_from_memory(head)
        idx = 0
        areas = []
        while True:
            if current in seen:
                break
            seen.append(current)

            vmap_area = current - self.offset_list
            va_start = read_int_from_memory(vmap_area)
            va_end = read_int_from_memory(vmap_area + current_arch.ptrsize)
            va_size = va_end - va_start

            flags = None
            if used:
                vm = read_int_from_memory(vmap_area + self.offset_vm)
                if vm:
                    flags = read_int_from_memory(vm + self.offset_flags)
                else:
                    flags = 0
            areas.append([used, va_start, va_end, va_size, flags])

            try:
                current = read_int_from_memory(current)
            except gdb.MemoryError:
                break

            idx += 1
        return areas

    def get_flags(self, flags_value):
        _flags = {
            "VM_IOREMAP":           0x00000001,
            "VM_ALLOC":             0x00000002,
            "VM_MAP":               0x00000004,
            "VM_USERMAP":           0x00000008,
            "VM_DMA_COHERENT":      0x00000010,
            "VM_UNINITIALIZED":     0x00000020,
            "VM_NO_GUARD":          0x00000040,
            "VM_KASAN":             0x00000080,
            "VM_FLUSH_RESET_PERMS": 0x00000100,
            "VM_MAP_PUT_PAGES":     0x00000200,
        }
        flags = []
        for k, v in _flags.items():
            if flags_value & v:
                flags.append(k)
        return "|".join(flags)

    def dump_areas(self, areas):
        fmt = "{:4s} {:6s} {:37s} {:18s} {:s}"
        legend = ["#", "state", "virtual address", "size", "flags"]
        self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        used_address_color = Config.get_gef_setting("theme.heap_chunk_address_used")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")

        for idx, (used, va_start, va_end, va_size, flags) in enumerate(areas):
            size_str = "{:<#18x}".format(va_size)
            size_str = Color.colorify(size_str, chunk_size_color)
            virt_str = "{:#018x}-{:#018x}".format(va_start, va_end)
            if used:
                virt_str = Color.colorify(virt_str, used_address_color)
                state = "in-use"
                flags_str = " " + self.get_flags(flags)
            else:
                virt_str = Color.colorify(virt_str, freed_address_color)
                state = "freed"
                flags_str = ""
            self.out.append("{:<4d} {:6s} {:s} {:s}{:s}".format(idx, state, virt_str, size_str, flags_str))
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel_or_kpti_disabled
    def do_invoke(self, args):
        self.quiet = args.quiet
        if not args.quiet:
            info("Wait for memory scan")

        ret = self.initialize()
        if ret is False:
            return

        self.out = []
        areas = []

        if not args.only_freed:
            areas += self.parse_vmap_area_list(self.vmap_area_list, used=True)

        kversion = Kernel.kernel_version()
        if kversion and kversion >= "5.2":
            if not args.only_used:
                areas += self.parse_vmap_area_list(self.free_vmap_area_list, used=False)

        self.dump_areas(sorted(areas, key=lambda x:x[1]))

        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class KsymaddrRemoteCommand(GenericCommand):
    """Resolve kernel symbols from kallsyms table."""
    # Thanks to https://github.com/marin-m/vmlinux-to-elf
    _cmdline_ = "ksymaddr-remote"
    _category_ = "08-c. Qemu-system Cooperation - Linux Symbol"
    _aliases_ = ["ks"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("keyword", metavar="KEYWORD", nargs="*", help="filter by specific symbol name.")
    parser.add_argument("-t", "--type", action="append", default=[], help="filter by symbol type.")
    parser.add_argument("-e", "--exact", action="store_true", help="use exact match.")
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="enable verbose mode.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} commit_creds prepare_kernel_cred # OR search".format(_cmdline_)

    def __init__(self, *args, **kwargs):
        super().__init__()
        """
        # Do not use dict; There are cases where multiple symbols with the same name exist.
        # cat /proc/kallsyms |grep set_is_seen
        ffffffff812326e0 t set_is_seen
        ffffffff81d58900 t set_is_seen
        ffffffff81d5cab0 t set_is_seen
        #
        """
        self.kallsyms = []
        return

    def verbose_info(self, msg):
        if self.verbose:
            msg = "{} {}".format(Color.colorify("[+]", "bold blue"), msg)
            gef_print(msg)
        return

    def verbose_err(self, msg):
        if self.verbose:
            msg = "{} {}".format(Color.colorify("[+]", "bold red"), msg)
            gef_print(msg)
        return

    def quiet_info(self, msg):
        if not self.quiet:
            msg = "{} {}".format(Color.colorify("[+]", "bold blue"), msg)
            gef_print(msg)
        return

    def quiet_err(self, msg):
        if not self.quiet:
            msg = "{} {}".format(Color.colorify("[+]", "bold red"), msg)
            gef_print(msg)
        return

    def get_token_table(self):
        # Parse symbol name tokens
        tokens = []
        position = self.offset_kallsyms_token_table
        for _ in range(256):
            token = ""
            while self.kernel_img[position]:
                token += chr(self.kernel_img[position])
                position += 1
            position += 1
            tokens.append(token)
        assert len(tokens) == 256
        return tokens

    def read_kallsyms(self):
        if self.kallsyms: # resolved already
            return

        tokens = self.get_token_table()
        symbol_names = []
        position = self.offset_kallsyms_names
        for _ in range(self.num_symbols):
            # read token length
            length = self.kernel_img[position]
            position += 1

            # check if big symbol (6.1~)
            if self.may_use_big_symbol:
                if length & 0x80:
                    low = length & 0x7f
                    high = self.kernel_img[position]
                    position += 1
                    length = (high << 7) | low

            # make symbol_name
            symbol_name = ""
            for _ in range(length):
                symbol_token_index = self.kernel_img[position]
                symbol_token = tokens[symbol_token_index]
                position += 1
                symbol_name += symbol_token
            symbol_names.append(symbol_name)

        for addr, name in zip(self.kernel_addresses, symbol_names):
            self.kallsyms.append([addr, name[1:], name[0]])
        return

    def print_kallsyms(self, keywords, types):
        if is_32bit():
            fmt = "{:#010x} {:s} {:s}"
        else:
            fmt = "{:#018x} {:s} {:s}"

        if types:
            types = [t.lower() for t in types]
            kallsyms = [entry for entry in self.kallsyms if entry[2].lower() in types]
        else:
            kallsyms = self.kallsyms

        self.out = []
        if not keywords:
            for addr, symbol, typ in kallsyms:
                self.out.append(fmt.format(addr, typ, symbol))

        elif self.exact:
            for addr, symbol, typ in kallsyms:
                if symbol in keywords:
                    self.out.append(fmt.format(addr, typ, symbol))

        else:
            for addr, symbol, typ in kallsyms:
                text = fmt.format(addr, typ, symbol)
                for k in keywords:
                    if k in text: # not only symbol search, but also address search
                        self.out.append(text)
                        break
        return

    def get_kernel_version(self):
        # don't use Kernel.kernel_version, since it refers ksymaddr-remote
        r = re.search(rb"Linux version (\d+\.[\d.]*\d)[ -~]+", self.kernel_img)
        if r is None:
            self.verbose_err("Could not find kernel version")
            return False
        self.version_string = r.group(0)
        self.version_string_offset = r.span()[0]
        self.verbose_info("linux_banner: {:#x}".format(self.ro_base + self.version_string_offset))
        version_number = r.group(1).decode("ascii")
        major = int(version_number.split(".")[0])
        minor = int(version_number.split(".")[1])
        self.kernel_version = (major, minor)
        self.may_use_big_symbol = (major, minor) >= (6, 1)
        return True

    def get_cfg_name(self):
        h = hashlib.sha256(String.str2bytes(self.version_string)).hexdigest()[-16:]
        major, minor = self.kernel_version
        cfg_file_name = os.path.join(GEF_TEMP_DIR, "ksymaddr-remote-{:d}.{:d}-{:s}.cfg".format(major, minor, h))
        return cfg_file_name

    def save_config(self, param_name):
        cfg_file_name = self.get_cfg_name()
        config = configparser.ConfigParser()
        if os.path.exists(cfg_file_name):
            config.read(cfg_file_name)
        else:
            config["parameters"] = {}

        if param_name in config["parameters"]:
            return

        config["parameters"][param_name] = str(getattr(self, param_name))
        with open(cfg_file_name, "w") as cfg_file:
            config.write(cfg_file)
        return

    def get_saved_config(self, param_names):
        if self.reparse:
            return False

        cfg_file_name = self.get_cfg_name()
        if not os.path.exists(cfg_file_name):
            return False

        config = configparser.ConfigParser()
        config.read(cfg_file_name)
        for param_name in param_names:
            if param_name not in config["parameters"]:
                return False

        for param_name in param_names:
            param_value = int(config["parameters"][param_name])
            setattr(self, param_name, param_value)
        return True

    def find_kallsyms_token_table(self):
        ret = self.get_saved_config(["offset_kallsyms_token_table"])
        if ret:
            self.verbose_info("kallsyms_token_table: {:#x}".format(self.ro_base + self.offset_kallsyms_token_table))
            return True

        """
        [Search policy]
        - kallsyms_token_table has unique sequences like "30 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00".
        - We search it from .rodata area, then search backwards for invalid characters to get the top.

        [Positional relationship]
        - ...
        - kallsyms_token_table
        - ...

        [Sample values for 64bit]
        gef> hexdump -n byte kallsyms_token_table
        0xffffffff8b2b51b0:    65 75 00 77 5f 00 61 64 64 00 64 5f 5f 66 75 6e    |  eu.w_.add.d__fun  |
        0xffffffff8b2b51c0:    63 5f 5f 00 74 70 5f 66 75 6e 63 00 33 32 00 6e    |  c__.tp_func.32.n  |
        0xffffffff8b2b51d0:    61 00 66 66 00 69 70 00 78 65 6e 00 70 72 00 73    |  a.ff.ip.xen.pr.s  |
        0xffffffff8b2b51e0:    65 74 00 63 70 75 00 49 44 00 65 64 00 53 43 00    |  et.cpu.ID.ed.SC.  |
        0xffffffff8b2b51f0:    66 72 65 00 76 65 5f 00 70 6f 00 78 5f 00 5f 73    |  fre.ve_.po.x_._s  |
        0xffffffff8b2b5200:    68 00 2e 31 00 62 6c 00 6d 65 6d 00 5f 72 65 67    |  h..1.bl.mem._reg  |
        0xffffffff8b2b5210:    00 74 5f 5f 00 6c 6f 63 6b 00 62 5f 00 72 5f 5f    |  .t__.lock.b_.r__  |
        0xffffffff8b2b5220:    6b 73 74 72 74 61 62 6e 73 00 66 75 6e 63 5f 5f    |  kstrtabns.func__  |
        0xffffffff8b2b5230:    00 69 6e 74 5f 00 72 65 73 00 74 72 61 63 65 00    |  .int_.res.trace.  |
        0xffffffff8b2b5240:    70 61 72 00 2e 30 00 64 65 76 65 6e 74 5f 00 6d    |  par..0.devent_.m  |
        0xffffffff8b2b5250:    75 00 61 63 70 69 5f 00 6d 70 00 73 74 61 00 64    |  u.acpi_.mp.sta.d  |
        0xffffffff8b2b5260:    65 62 75 67 00 5f 5f 5f 00 62 75 67 00 6f 75 00    |  ebug.___.bug.ou.  |
        0xffffffff8b2b5270:    5f 73 74 61 00 77 72 69 74 00 2e 00 67 72 6f 00    |  _sta.writ...gro.  |
        0xffffffff8b2b5280:    30 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00    |  0.1.2.3.4.5.6.7.  | <- here unique seqs
        0xffffffff8b2b5290:    38 00 39 00 72 63 00 77 61 00 63 61 6c 00 75 70    |  8.9.rc.wa.cal.up  |
        0xffffffff8b2b52a0:    5f 00 45 5f 00 67 65 5f 00 6d 61 70 00 41 00 42    |  _.E_.ge_.map.A.B  |

        [Sample values for 32bit]
        gef> hexdump -n byte kallsyms_token_table
        0xc6e58efc:    54 52 41 43 45 5f 53 59 53 00 41 43 45 5f 53 59    |  TRACE_SYS.ACE_SY  |
        0xc6e58f0c:    53 00 5f 53 59 53 00 54 45 4d 00 41 43 45 00 69    |  S._SYS.TEM.ACE.i  |
        0xc6e58f1c:    67 00 70 6f 69 6e 74 5f 00 62 75 00 75 74 5f 00    |  g.point_.bu.ut_.  |
        0xc6e58f2c:    5f 53 59 00 54 52 00 5f 73 79 00 72 65 61 64 00    |  _SY.TR._sy.read.  |
        0xc6e58f3c:    66 5f 00 75 6c 00 62 6c 00 61 6c 6c 6f 63 00 74    |  f_.ul.bl.alloc.t  |
        0xc6e58f4c:    6c 00 63 6c 00 65 79 00 61 74 61 00 70 63 00 5f    |  l.cl.ey.ata.pc._  |
        0xc6e58f5c:    65 6e 00 76 65 72 00 54 45 00 64 74 72 61 63 65    |  en.ver.TE.dtrace  |
        0xc6e58f6c:    5f 65 76 65 6e 74 5f 00 61 70 00 61 74 65 00 74    |  _event_.ap.ate.t  |
        0xc6e58f7c:    6e 00 41 43 00 6d 73 00 72 61 77 5f 00 5f 63 6f    |  n.AC.ms.raw_._co  |
        0xc6e58f8c:    00 73 74 72 00 6d 6f 00 67 69 73 74 65 72 00 69    |  .str.mo.gister.i  |
        0xc6e58f9c:    70 00 63 6f 6e 00 67 69 73 00 69 6e 69 74 00 66    |  p.con.gis.init.f  |
        0xc6e58fac:    75 6e 63 00 65 5f 73 00 75 74 00 5f 73 68 00 70    |  unc.e_s.ut._sh.p  |
        0xc6e58fbc:    6f 00 61 6c 6c 00 2e 00 66 73 5f 00 30 00 31 00    |  o.all...fs_.0.1.  |
        0xc6e58fcc:    32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00    |  2.3.4.5.6.7.8.9.  | <- here unique seqs
        0xc6e58fdc:    6b 5f 00 5f 63 68 00 72 69 74 00 61 63 70 69 00    |  k_._ch.rit.acpi.  |
        0xc6e58fec:    5f 63 6f 6e 00 65 78 74 34 00 61 6d 00 41 00 42    |  _con.ext4.am.A.B  |
        """

        # first, search unique bytes
        seq_to_find = b"0\x001\x002\x003\x004\x005\x006\x007\x008\x009\x00"
        seq_to_avoid = [b":\0", b"\0\0", b"\0\1", b"\0\2", b"ASCII\0"]
        target_pattern = seq_to_find + b"(?!" + b"|".join(seq_to_avoid) + b")"

        unique_bytes_offset = []
        for r in re.finditer(target_pattern, self.kernel_img):
            unique_bytes_offset.append(r.span())

        if len(unique_bytes_offset) == 0:
            self.verbose_err("Could not find kallsyms_token_table (0 candidate)")
            return False

        if len(unique_bytes_offset) > 1:
            for offsets in unique_bytes_offset.copy():
                follow = self.kernel_img[offsets[1]:offsets[1] + 1]
                if not (follow.isalnum() or follow == b"_"):
                    unique_bytes_offset.remove(offsets)
            if len(unique_bytes_offset) != 1:
                self.verbose_err("Could not find kallsyms_token_table (multiple candidates)")
                return False

        position = unique_bytes_offset[0][0]
        self.verbose_info("unique_bytes: {:#x}".format(self.ro_base + position))

        # second, backward search the top
        prev_x = None
        while True:
            position -= 1
            if position < 0:
                self.verbose_err("Could not find kallsyms_token_table (failed to get top)")
                return False
            x = self.kernel_img[position:position + 1]
            if x not in b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.$@\0":
                break
            if x == prev_x == b"\0": # \0\0 is inappropriate
                break
            prev_x = x

        position += 1
        position += -position % 4
        self.offset_kallsyms_token_table = position
        self.save_config("offset_kallsyms_token_table")
        self.verbose_info("kallsyms_token_table: {:#x}".format(self.ro_base + self.offset_kallsyms_token_table))
        return True

    def find_kallsyms_token_index(self):
        ret = self.get_saved_config(["offset_kallsyms_token_index"])
        if ret:
            self.verbose_info("kallsyms_token_index: {:#x}".format(self.ro_base + self.offset_kallsyms_token_index))
            return True

        """
        [Search policy]
        - Find the index where the string appears in kallsyms_token_table.
        - Find where that index is arranged like a table.

        [Positional relationship]
        - ...
        - kallsyms_token_table
        - kallsyms_token_index
        - ...

        [Sample values for 64bit]
        gef> hexdump -n word kallsyms_token_index
        0xffffffff8b2b5540:    0x0000 0x0003 0x0006 0x000a 0x0014 0x001c 0x001f 0x0022    |  ..............".  |
        0xffffffff8b2b5550:    0x0025 0x0028 0x002c 0x002f 0x0033 0x0037 0x003a 0x003d    |  %.(.,./.3.7.:.=.  |
        0xffffffff8b2b5560:    0x0040 0x0044 0x0048 0x004b 0x004e 0x0052 0x0055 0x0058    |  @.D.H.K.N.R.U.X.  |
        0xffffffff8b2b5570:    0x005c 0x0061 0x0065 0x006a 0x006d 0x007a 0x0081 0x0086    |  ..a.e.j.m.z.....  |
        0xffffffff8b2b5580:    0x008a 0x0090 0x0094 0x0097 0x009f 0x00a2 0x00a8 0x00ab    |  ................  |
        0xffffffff8b2b5590:    0x00af 0x00b5 0x00b9 0x00bd 0x00c0 0x00c5 0x00ca 0x00cc    |  ................  |
        0xffffffff8b2b55a0:    0x00d0 0x00d2 0x00d4 0x00d6 0x00d8 0x00da 0x00dc 0x00de    |  ................  |
        0xffffffff8b2b55b0:    0x00e0 0x00e2 0x00e4 0x00e7 0x00ea 0x00ee 0x00f2 0x00f5    |  ................  |

        [Sample values for 32bit]
        gef> hexdump -n word kallsyms_token_index
        0xc6e59274:    0x0000 0x000a 0x0012 0x0017 0x001b 0x001f 0x0022 0x0029    |  ............".).  |
        0xc6e59284:    0x002c 0x0030 0x0034 0x0037 0x003b 0x0040 0x0043 0x0046    |  ,.0.4.7.;.@.C.F.  |
        0xc6e59294:    0x0049 0x004f 0x0052 0x0055 0x0058 0x005c 0x005f 0x0063    |  I.O.R.U.X..._.c.  |
        0xc6e592a4:    0x0067 0x006a 0x0078 0x007b 0x007f 0x0082 0x0085 0x0088    |  g.j.x.{.........  |
        0xc6e592b4:    0x008d 0x0091 0x0095 0x0098 0x009f 0x00a2 0x00a6 0x00aa    |  ................  |
        0xc6e592c4:    0x00af 0x00b4 0x00b8 0x00bb 0x00bf 0x00c2 0x00c6 0x00c8    |  ................  |
        0xc6e592d4:    0x00cc 0x00ce 0x00d0 0x00d2 0x00d4 0x00d6 0x00d8 0x00da    |  ................  |
        0xc6e592e4:    0x00dc 0x00de 0x00e0 0x00e3 0x00e7 0x00eb 0x00f0 0x00f5    |  ................  |
        """

        # create expected kallsyms_token_index byte sequqence
        position = self.offset_kallsyms_token_table
        seq_token_table_head = self.kernel_img[position:position + 256]

        token_offsets = [p16(0)]
        pos = 0
        while True:
            pos = seq_token_table_head.find(b"\0", pos + 1)
            if pos == -1:
                break
            token_offsets.append(p16(pos + 1))
        seq_to_find = b"".join(token_offsets)

        # search from memory
        position = self.kernel_img.find(seq_to_find, self.offset_kallsyms_token_table)
        if position == -1:
            self.verbose_err("Could not find kallsyms_token_index (0 candidate)")
            return False

        self.offset_kallsyms_token_index = position
        self.save_config("offset_kallsyms_token_index")
        self.verbose_info("kallsyms_token_index: {:#x}".format(self.ro_base + self.offset_kallsyms_token_index))
        return True

    def find_kallsyms_markers(self):
        # determines the size of table elements depended on kernel version.
        if self.kernel_version < (4, 20):
            # kallsyms_markers is unsigned long[]
            self.kallsyms_markers_table_element_size = current_arch.ptrsize
        else:
            # kallsyms_markers is unsigned int[]
            self.kallsyms_markers_table_element_size = 4

        if self.kernel_version >= (6, 2) and self.kernel_version < (6, 9):
            ret = self.get_saved_config([
                "offset_kallsyms_token_markers",
                "offset_kallsyms_seqs_of_names",
            ])
            if ret:
                self.verbose_info("kallsyms_markers: {:#x}".format(self.ro_base + self.offset_kallsyms_markers))
                self.verbose_info("kallsyms_seqs_of_names: {:#x}".format(self.ro_base + self.offset_kallsyms_seqs_of_names))
                return True
        else:
            ret = self.get_saved_config([
                "offset_kallsyms_token_markers",
            ])
            if ret:
                self.verbose_info("kallsyms_markers: {:#x}".format(self.ro_base + self.offset_kallsyms_markers))
                return True

        """
        [Search policy]
        - From kallsyms_token_table, search backwards for 0x00000000.
        - For kernel 6.2~6.8, there is kallsyms_seqs_of_names between kallsyms_markers and kallsyms_token_table,
          so this should be skipped.

        [Positional relationship]
        ...
        - kallsyms_markers
        - kallsyms_seqs_of_names (6.2~6.8)
        - kallsyms_token_table
        - kallsyms_token_index
        ...
        - kallsyms_seqs_of_names (6.9~)
        ...

        [Sample values for 64bit ~6.2]
        gef> hexdump -n dword kallsyms_markers
        0xffffffff8b2b4b48:    0x00000000 0x00000ab0 0x000016d3 0x00002316    |  .............#..  | <- kallsyms_markers
        0xffffffff8b2b4b58:    0x00002f38 0x00003cf8 0x00004c4c 0x000059c8    |  8/...<..LL...Y..  |
        0xffffffff8b2b4b68:    0x0000664b 0x00007316 0x00008119 0x00008f2e    |  Kf...s..........  |
        0xffffffff8b2b4b78:    0x00009cc6 0x0000a9ff 0x0000b687 0x0000c20f    |  ................  |
        ...
        0xffffffff8b2b5180:    0x0013fa80 0x001404c6 0x00140f67 0x00141a29    |  ........g...)...  |
        0xffffffff8b2b5190:    0x0014240e 0x00142e25 0x00143a5f 0x0014442a    |  .$..%..._:..*D..  |
        0xffffffff8b2b51a0:    0x00144e55 0x001458d8 0x00146338 0x00000000    |  UN...X..8c......  |
        0xffffffff8b2b51b0:    0x77007565 0x6461005f 0x5f640064 0x6e75665f    |  eu.w_.add.d__fun  | <- kallsyms_token_table

        [Sample values for 64bit 6.2~]
        gef> hexdump -n dword kallsyms_markers
        0xffffffff8d5fcde0:    0x00000000 0x00000b55 0x000017bb 0x000024c3    |  ....U........$..  | <- kallsyms_markers
        0xffffffff8d5fcdf0:    0x000030c1 0x00003dca 0x00004983 0x000058aa    |  .0...=...I...X..  |
        0xffffffff8d5fce00:    0x00006785 0x0000760e 0x0000828d 0x00009160    |  .g...v......`...  |
        0xffffffff8d5fce10:    0x00009efa 0x0000ab20 0x0000b73a 0x0000c37d    |  .... ...:...}...  |
        ...
        0xffffffff8d5fd790:    0x00212755 0x002131b8 0x00213af8 0x00214558    |  U'!..1!..:!.XE!.  |
        0xffffffff8d5fd7a0:    0x01069d01 0x9d01019d 0x029d0100 0x02039d01    |  ................  | <- kallsyms_seqs_of_names
        0xffffffff8d5fd7b0:    0xa400291c 0x10a50024 0x0154a500 0xaa0116aa    |  .)..$.....T.....  |
        0xffffffff8d5fd7c0:    0x87610214 0x01274902 0xb201cbaf 0xbbbc01c9    |  ..a..I'.........  |

        [Sample values for 32bit 6.2~]
        gef> hexdump -n dword kallsyms_markers
        0xc6e0dc98:    0x00000000 0x00000c61 0x0000188f 0x00002641    |  ....a.......A&..  | <- kallsyms_markers
        0xc6e0dca8:    0x00003492 0x000041a7 0x00004e6b 0x00005ace    |  .4...A..kN...Z..  |
        0xc6e0dcb8:    0x0000691b 0x00007703 0x00008411 0x00008fc1    |  .i...w..........  |
        0xc6e0dcc8:    0x00009c98 0x0000a8ea 0x0000b719 0x0000c4dd    |  ................  |
        ...
        0xc6e0e2c8:    0x0014f2fa 0x0014fbeb 0x00150653 0x00634401*   |  ........S....Dc.  | <- kallsyms_seqs_of_names (*)
        0xc6e0e2d8:    0xd90030d9 0x8bd30032 0x0189d300 0x6a01e97f    |  .0..2..........j  |
        0xc6e0e2e8:    0x31d90063 0x0007e100 0xd600b7e1 0xd1d900cb    |  c..1............  |
        0xc6e0e2f8:    0x0083dd00 0xd90004e9 0x85ef00ab 0x00bfdb00    |  ................  |
        """

        # kallsyms_markers[0] is 0.
        seq_to_find = b"\0" * self.kallsyms_markers_table_element_size

        # ignore the 0 immediately above kallsyms_token_table.
        position = self.offset_kallsyms_token_table - 1
        if len(self.kernel_img) <= position:
            return False
        while position > 0 and self.kernel_img[position] == 0:
            position -= 1

        # aligned search from memory
        while position > 0:
            needle = self.kernel_img.rfind(seq_to_find, 0, position)
            if needle == -1:
                self.verbose_err("Could not find kallsyms_markers")
                return False
            # check alignment
            align_diff = needle % self.kallsyms_markers_table_element_size
            if align_diff == 0:
                break
            position = needle + self.kallsyms_markers_table_element_size - align_diff

        # kallsyms_seqs_of_names is introduced from kernel 6.2
        # in this case, it finds kallsyms_seqs_of_names instead of kallsyms_markers, so search back through memory again.
        if self.kernel_version >= (6, 2) and self.kernel_version < (6, 9):
            if u32(self.kernel_img[needle + 4:needle + 8]) & 0xfff00000: # false positive, search again
                position = needle
                # aligned search from memory
                while position > 0:
                    needle = self.kernel_img.rfind(seq_to_find, 0, position)
                    if needle == -1:
                        self.verbose_err("Could not find kallsyms_markers")
                        return False
                    # check alignment
                    align_diff = needle % self.kallsyms_markers_table_element_size
                    if align_diff == 0:
                        break
                    position = needle + self.kallsyms_markers_table_element_size - align_diff

        self.offset_kallsyms_markers = needle
        self.save_config("offset_kallsyms_markers")
        self.verbose_info("kallsyms_markers: {:#x}".format(self.ro_base + self.offset_kallsyms_markers))

        # find kallsyms_seqs_of_names
        if self.kernel_version >= (6, 2) and self.kernel_version < (6, 9):
            # locate kallsyms_seqs_of_names to get the table size of kallsyms_markers (used after).
            position = self.offset_kallsyms_markers + 4
            while self.kernel_img[position + 3] == 0:
                a = u32(self.kernel_img[position - 4:position])
                b = u32(self.kernel_img[position:position + 4])
                if a > b or b - a > 0x100000:
                    break
                position += 4
            self.offset_kallsyms_seqs_of_names = position
            self.save_config("offset_kallsyms_seqs_of_names")
            self.verbose_info("kallsyms_seqs_of_names: {:#x}".format(self.ro_base + self.offset_kallsyms_seqs_of_names))

        return True

    def find_kallsyms_names(self):
        ret = self.get_saved_config(["offset_kallsyms_names"])
        if ret:
            return True

        """
        [Search policy]
        - From kallsyms_markers, go back as far as we can definitively go back.
        - This address is not accurate.

        [Positional relationship]
        ...
        - kallsyms_names
        - kallsyms_markers
        - kallsyms_seqs_of_names (6.2~6.8)
        - kallsyms_token_table
        - kallsyms_token_index
        ...
        - kallsyms_seqs_of_names (6.9~)
        ...

        [Sample values for 64bit]
        gef> hexdump -n qword kallsyms_names
        0xffffffff8b16e610:    0x0cf3ec0e78b6410a 0xf370ff4109fe61cb    |  .A.x.....a..A.p.  | <- kallsyms_names
        0xffffffff8b16e620:    0x0c410774722cbdeb 0xa8410df67ef4285f    |  ..,rt.A._(.~..A.  |
        0xffffffff8b16e630:    0x936bed62d8632c71 0x925f0c4107f67ef4    |  q,c.b.k..~..A._.  |
        0xffffffff8b16e640:    0xfb646741067772f1 0x706563a4410add86    |  .rw.Agd....A.cep  |
        ...
        0xffffffff8b2b4b20:    0x616bd977fc6d7364 0x738df5ff440e61f6    |  dsm.w.ka.a.D...s  |
        0xffffffff8b2b4b30:    0x6765625fbfe87263 0x63738df5ff440cf5    |  cr.._beg..D...sc  |
        0xffffffff8b2b4b40:    0x000064ee5fbfe872 0x00000ab000000000    |  r.._.d..........  | <- kallsyms_markers
        0xffffffff8b2b4b50:    0x00002316000016d3 0x00003cf800002f38    |  .....#..8/...<..  |

        [Sample values for 32bit]
        gef> hexdump -n qword kallsyms_names
        0xc6cbce58:    0x335fd57472fb5c08 0x54039974f9540432    |  ...rt._32.T.t..T  | <- kallsyms_names
        0xc6cbce68:    0x63ff72fb5c0799a6 0xd57472fb5c0a30a1    |  .....r.c.0...rt.  |
        0xc6cbce78:    0x177407b6f932335f 0xa0ca0aa1f3796669    |  _32...t.ify.....  |
        0xc6cbce88:    0xd7f49b2d63ecc37f 0x2d63ecc37fa0ca0a    |  ...c-.........c-  |
        ...
        0xc6e0dc78:    0x3a7262fe620d105f 0x10ff67ef796ccf65    |  _..b.br:e.ly.g..  |
        0xc6e0dc88:    0x62fe420964164203 0x0000ec6d699b6b72    |  .B.d.B.brk.im...  |
        0xc6e0dc98:    0x00000c6100000000 0x000026410000188f    |  ....a.......A&..  | <- kallsyms_markers
        0xc6e0dca8:    0x000041a700003492 0x00005ace00004e6b    |  .4...A..kN...Z..  |
        """

        # take the last element of kallsyms_marker
        if hasattr(self, "offset_kallsyms_seqs_of_names"): # maybe 6.2~6.8
            kallsyms_markers_end = self.offset_kallsyms_seqs_of_names
        else:
            kallsyms_markers_end = self.offset_kallsyms_token_table

        kallsyms_markers_data = self.kernel_img[self.offset_kallsyms_markers:kallsyms_markers_end]
        kallsyms_markers_entries = slice_unpack(kallsyms_markers_data, self.kallsyms_markers_table_element_size)
        kallsyms_markers_last_entry = list(filter(None, kallsyms_markers_entries))[-1] # filter 0, maybe padding

        # go back that number of bytes
        position = self.offset_kallsyms_markers
        position -= kallsyms_markers_last_entry
        position += -position % self.kallsyms_markers_table_element_size

        if position <= 0:
            self.verbose_err("Could not find kallsyms_names")
            return False

        # This value is provisional. It will be corrected in the next process (=find_kallsyms_num_syms).
        self.offset_kallsyms_names = position
        self.verbose_info("kallsyms_names: {:#x} (candidate)".format(self.ro_base + self.offset_kallsyms_names))
        return True

    def find_kallsyms_num_syms(self):
        ret = self.get_saved_config([
            "num_symbols",
            "offset_kallsyms_names",
            "offset_kallsyms_num_syms",
        ])
        if ret:
            self.verbose_info("num_symbols: {:#x}".format(self.num_symbols))
            self.verbose_info("kallsyms_names: {:#x}".format(self.ro_base + self.offset_kallsyms_names))
            self.verbose_info("kallsyms_num_syms: {:#x}".format(self.ro_base + self.offset_kallsyms_num_syms))
            return True

        """
        [Search policy]
        - From candidate address of kallsyms_names, search backwards to the top of what can be correctly
          interpreted as kallsyms_names.

        [Positional relationship]
        ...
        - kallsyms_num_syms
        - kallsyms_names
        - kallsyms_markers
        - kallsyms_seqs_of_names (6.2~6.8)
        - kallsyms_token_table
        - kallsyms_token_index
        ...
        - kallsyms_seqs_of_names (6.9~)
        ...

        [Sample values for 64bit]
        gef> hexdump -n qword kallsyms_num_syms
        0xffffffff8b16e608:    0x000000000001982b 0x0cf3ec0e78b6410a    |  +........A.x....  |
        0xffffffff8b16e618:    0xf370ff4109fe61cb 0x0c410774722cbdeb    |  .a..A.p...,rt.A.  |
        0xffffffff8b16e628:    0xa8410df67ef4285f 0x936bed62d8632c71    |  _(.~..A.q,c.b.k.  |
        0xffffffff8b16e638:    0x925f0c4107f67ef4 0xfb646741067772f1    |  .~..A._..rw.Agd.  |

        [Sample values for 32bit]
        gef> hexdump -n dword kallsyms_num_syms
        0xc6cbce54:    0x00018eb8 0x72fb5c08 0x335fd574 0xf9540432    |  .......rt._32.T.  |
        0xc6cbce64:    0x54039974 0x5c0799a6 0x63ff72fb 0x5c0a30a1    |  t..T.....r.c.0..  |
        0xc6cbce74:    0xd57472fb 0xf932335f 0x177407b6 0xf3796669    |  .rt._32...t.ify.  |
        """

        token_table = self.get_token_table()
        possible_symbol_types = "-?ABCDGINPRSTUVWabcdginprstuvw"
        dp = []
        position = self.offset_kallsyms_names

        while True:
            if position < 0:
                self.verbose_err("Could not find kallsyms_names")
                return False

            # Do some types of checks.
            # 1: check the token type is likely or not.
            token_index = self.kernel_img[position + 1]
            symbol_type = token_table[token_index][0]
            if symbol_type not in possible_symbol_types:
                position -= 4
                continue

            # 2: check the table (kallsyms_names) entirely.
            # Each element of kallsyms_names consists of {number of tokens, tokens[number of tokens]}.
            # tokens[0][0] is symbol type.
            #
            # The following is an example of last elements of kallsyms_names.
            # gef> x/24xb 0xffffffffb46b4b48-0x10
            # 0xffffffffb46b4b38: 0xf5   0x0c*  0x44   0xff   0xf5   0x8d   0x73   0x63 (*: start of last valid elements)
            # 0xffffffffb46b4b40: 0x72   0xe8   0xbf   0x5f   0xee   0x64*  0x00** 0x00 (*: end of last valid elements, **: end marker)
            # 0xffffffffb46b4b48: 0x00*  0x00   0x00   0x00   0xb0   0x0a   0x00   0x00 (*: start of kallsyms_markers)
            #
            # 0x0c: number of tokens
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0x44]
            # 'D' (= symbol type)
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0xff]
            # '__'
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0xf5]
            # 'in'
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0x8d]
            # 'it_'
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0x73]
            # 's'
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0x63]
            # 'c'
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0x72]
            # 'r'
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0xe8]
            # 'at'
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0xbf]
            # 'ch'
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0x5f]
            # '_'
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0xee]
            # 'en'
            # gef> pi GCI["ksymaddr-remote"].get_token_table()[0x64]
            # 'd'
            # (=`__init_scratch_end`)
            #
            # Finally, 0x00(**) is following, this is the marker that represents the end of kallsyms_names.
            # This can be interpreted that the size of element is 0.
            #
            # However, this 0x00 may not exist.
            # gef> x/16xb 0xffffffffadefc1d8-0x8
            # 0xffffffffadefc1d0: 0x12   0x65   0x05*  0xbf   0x65   0xaf   0x74   0xa5** (*/**: start/end of last valid elements)
            # 0xffffffffadefc1d8: 0x00*  0x00   0x00   0x00   0xb2   0x0b   0x00   0x00   (*: start of kallsyms_markers)
            # Even in this case, the first byte of kallsyms_markers is always 0, so we use it.
            #
            # Check that this structure is correct or not, using bottom-up DP.
            # dp[i] contains num_syms as interpreted from `kallsyms_makers - i` as the start of kallsyms_names.
            # dp[i] == -1 means invalid.
            range_start = position
            range_end = self.offset_kallsyms_markers
            range_end -= len(dp) # shortcut the already checked results.
            for pos in range(range_end, range_start - 1, -1):
                symbol_size = self.kernel_img[pos]
                is_big_symbol = False # default

                # check if big symbol (6.1~)
                if self.may_use_big_symbol:
                    if symbol_size & 0x80:
                        low = symbol_size & 0x7f
                        high = self.kernel_img[pos + 1]
                        symbol_size = (high << 7) | low
                        is_big_symbol = True

                # 0xffffffffb46b4b38: 0xf5     0x0c     0x44     0xff     0xf5     0x8d     0x73     0x63
                # 0xffffffffb46b4b40: 0x72     0xe8     0xbf     0x5f     0xee     0x64     0x00*    0x00*
                #                                                                           dp[2]=0  dp[1]=0
                # 0xffffffffb46b4b48: 0x00*    0x00     0x00     0x00     0xb0     0x0a     0x00     0x00
                #                     dp[0]=0
                if symbol_size == 0:
                    dp.append(0) # maybe it is a last entry
                    continue

                # 0xffffffffb46b4b38: 0xf5     0x0c     0x44     0xff     0xf5     0x8d     0x73     0x63
                # 0xffffffffb46b4b40: 0x72     0xe8     0xbf     0x5f     0xee     0x64*    0x00     0x00
                #                                                                  dp[3]=-1 dp[2]=0  dp[1]=0
                # 0xffffffffb46b4b48: 0x00*    0x00     0x00     0x00     0xb0     0x0a     0x00     0x00
                #                     dp[0]=0
                dp_len = len(dp)
                if is_big_symbol:
                    dp_len = len(dp) - 1
                if symbol_size >= dp_len:
                    dp.append(-1) # exceed the kallsyms_markers
                    continue

                # 0xffffffffb46b4b38: 0xf5     0x0c*    0x44     0xff     0xf5     0x8d     0x73     0x63
                #                              dp[f]=1  dp[e]=-1 dp[d]=-1 dp[c]=-1 dp[b]=-1 dp[a]=-1 dp[9]=-1
                # 0xffffffffb46b4b40: 0x72     0xe8     0xbf     0x5f     0xee     0x64     0x00**   0x00
                #                     dp[8]=-1 dp[7]=-1 dp[6]=-1 dp[5]=-1 dp[4]=-1 dp[3]=-1 dp[2]=0  dp[1]=0
                # 0xffffffffb46b4b48: 0x00*    0x00     0x00     0x00     0xb0     0x0a     0x00     0x00
                #                     dp[0]=0
                # when we see 0x0c(*), next element is 0x00(**).
                # In this case, here, len(dp) == 15 (dp[15] does not exist, but dp[14] exists).
                # dp[-(0xc + 1)] is dp[2]. d[2] is 0, not -1, so dp[15] is valid. If dp[2] is -1, dp[15] is invalid.
                offset_of_next_element = -symbol_size - 1
                if is_big_symbol:
                    offset_of_next_element -= 1
                if dp[offset_of_next_element] == -1:
                    dp.append(-1)
                    continue
                # seems to be okay, append valid dp
                dp.append(dp[offset_of_next_element] + 1)

            num_symbols = dp[-1]
            if num_symbols < 256:
                # It is judged as NG because there are too few symbols.
                position -= 4
                continue

            # 3: Find num_symbols from memory.
            if self.kallsyms_markers_table_element_size == 4:
                seq_to_find = p32(num_symbols)
            elif self.kallsyms_markers_table_element_size == 8:
                seq_to_find = p64(num_symbols)
            # Depending on the environment, there are many zero padding after seq_to_find (=kallsyms_num_syms).
            # This is probably because each variable is aligned in units of 256 bytes.
            MAX_ALIGNMENT = 256
            start = max(0, position - MAX_ALIGNMENT)
            needle = self.kernel_img.rfind(seq_to_find, start, position)
            if needle == -1:
                position -= 4
                continue

            # it seems ok.
            self.offset_kallsyms_names = position
            self.offset_kallsyms_num_syms = needle
            break

        self.save_config("offset_kallsyms_names")
        self.save_config("offset_kallsyms_num_syms")
        self.num_symbols = num_symbols
        self.save_config("num_symbols")
        self.verbose_info("num_symbols: {:#x}".format(self.num_symbols))
        self.verbose_info("kallsyms_names: {:#x}".format(self.ro_base + self.offset_kallsyms_names))
        self.verbose_info("kallsyms_num_syms: {:#x}".format(self.ro_base + self.offset_kallsyms_num_syms))
        return True

    def find_kallsyms_offsets(self):
        """
        [Search policy]
        - ~6.4
          - From kallsyms_num_syms, go back by num_symbols element sizes.
          - num_symbols offsets are stored, so get them.
        - 6.4~
          - From kallsyms_token_index + 0x200, num_symbols offsets are stored, so get them.

        [Positional relationship]
        - ...
        - kallsyms_offsets (4.6~6.3, CONFIG_KALLSYMS_BASE_RELATIVE=y)
        - kallsyms_relative_base (4.6~6.3, CONFIG_KALLSYMS_BASE_RELATIVE=y)
        - kallsyms_num_syms
        - kallsyms_names
        - kallsyms_markers
        - kallsyms_seqs_of_names (6.2~6.8)
        - kallsyms_token_table
        - kallsyms_token_index
        - kallsyms_offsets (6.4~, CONFIG_KALLSYMS_BASE_RELATIVE=y)
        - kallsyms_relative_base (6.4~, CONFIG_KALLSYMS_BASE_RELATIVE=y)
        - kallsyms_seqs_of_names (6.9~)
        - ...

        [Sample values for 64bit ~6.3, CONFIG_KALLSYMS_ABSOLUTE_PERCPU=n (use positive offset)]
        gef> hexdump -n dword kallsyms_offsets
        0xffffffff8b108550:    0x00000000 0x00000000 0x00001000 0x00002000    |  ............. ..  |
        0xffffffff8b108560:    0x00006000 0x0000b000 0x0000c000 0x00018000    |  .`..............  |
        0xffffffff8b108570:    0x00019000 0x00019008 0x00019010 0x00019020    |  ............ ...  |
        0xffffffff8b108580:    0x00019420 0x00019440 0x00019448 0x00019450    |   ...@...H...P...  |

        [Sample values for 64bit ~6.3, CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y (use negative offset)]
        gef> hexdump -n dword kallsyms_offsets
        0xffffffffa72854b0:    0xffffffff 0xffffffff 0xffffffff 0xffffffbf    |  ................  |
        0xffffffffa72854c0:    0xffffffba 0xfffffeef 0xfffffdef 0xfffffddf    |  ................  |
        0xffffffffa72854d0:    0xfffffdcf 0xfffffa1f 0xfffff9cf 0xfffff9bf    |  ................  |
        0xffffffffa72854e0:    0xfffff99f 0xfffff8ff 0xfffff76f 0xfffff73f    |  ........o...?...  |

        [Sample values for 32bit ~6.3, CONFIG_KALLSYMS_ABSOLUTE_PERCPU=n (use positive offset)]
        gef> hexdump -n dword kallsyms_offsets
        0xc6c59370:    0x00000000 0x00000000 0x00000000 0x00000070    |  ............p...  |
        0xc6c59380:    0x00000080 0x000001d8 0x000002e0 0x00000320    |  ............ ...  |
        0xc6c59390:    0x00000360 0x000003a8 0x000003e8 0x000004a8    |  `...............  |
        0xc6c593a0:    0x000005a8 0x0000066c 0x0000073c 0x000007ac    |  ....l...<.......  |

        [Sample values for 64bit 6.4~, CONFIG_KALLSYMS_ABSOLUTE_PERCPU=n (use positive offset)]
        gef> hexdump -n word kallsyms_token_index
        0xffffffff844fa178:    0x0000 0x0003 0x0006 0x000a 0x0010 0x0013 0x0016 0x0019    |  ................  |
        0xffffffff844fa188:    0x001d 0x0029 0x002d 0x0030 0x0034 0x0037 0x003b 0x003e    |  ..).-.0.4.7.;.>.  |
        0xffffffff844fa198:    0x0041 0x0056 0x005a 0x005e 0x0061 0x0064 0x0067 0x006a    |  A.V.Z.^.a.d.g.j.  |
        ...
        0xffffffff844fa358:    0x0386 0x0389 0x038c 0x038f 0x0392 0x0395 0x0398 0x039b    |  ................  |
        0xffffffff844fa368:    0x039e 0x03a1 0x03a5 0x03a8 0x03ab 0x03ae 0x03b1 0x03b4    |  ................  |
        gef> hexdump -n dword kallsyms_offset
        0xffffffff844fa378:    0x00000000 0x00000000 0x00001000 0x00002000    |  ............. ..  |
        0xffffffff844fa388:    0x00006000 0x0000b000 0x0000c000 0x00014000    |  .`...........@..  |
        ...
        0xffffffff8461e44c:    0xf89effff 0xf89dffff 0xf89d9fff 0xf89d9fff    |  ................  |
        0xffffffff8461e45c:    0x00000000 0x81000000 0xffffffff 0x02fa0e02    |  ................  |
        relative_base_address: 0xffffffff81000000

        [Sample values for 64bit 6.4~, CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y (use negative offset)]
        gef> hexdump -n word kallsyms_token_index
        0xffffffff86744a38:    0x0000 0x0004 0x000c 0x0010 0x0014 0x0017 0x001b 0x0020    |  .............. .  |
        0xffffffff86744a48:    0x002d 0x0034 0x0039 0x003d 0x0042 0x0045 0x0048 0x004b    |  -.4.9.=.B.E.H.K.  |
        0xffffffff86744a58:    0x004f 0x0053 0x005d 0x0060 0x0064 0x0067 0x006b 0x0072    |  O.S.].`.d.g.k.r.  |
        ...
        0xffffffff86744c18:    0x0338 0x033b 0x033e 0x0341 0x0349 0x034c 0x034f 0x0357    |  8.;.>.A.I.L.O.W.  |
        0xffffffff86744c28:    0x035a 0x035d 0x0360 0x0363 0x0369 0x036e 0x0372 0x0375    |  Z.].`.c.i.n.r.u.  |
        gef> hexdump -n dword kallsyms_offset
        0xffffffff86744c38:    0xffffffff 0xffffffff 0xffffffff 0xffffffaf    |  ................  |
        0xffffffff86744c48:    0xffffffaa 0xfffffe9f 0xfffffe8f 0xfffffd8f    |  ................  |
        ...
        0xffffffff8677ed5c:    0xff09237f 0xff09218f 0xff09217f 0xff0920a9    |  .#...!...!... ..  |
        0xffffffff8677ed6c:    0x00000000 0x85c00000 0xffffffff 0x00f0d800    |  ................  |
        relative_base_address: 0xffffffff85c00000
        """

        # const values
        if Endian.is_big_endian():
            endianness_marker = ">"
            endian_str = "big"
        else:
            endianness_marker = "<"
            endian_str = "little"
        offset_byte_size = 4
        address_byte_size = current_arch.ptrsize

        # get relative_base_address
        if self.kernel_version < (6, 4):
            # ignore the 0 immediately above offset_kallsyms_num_syms.
            position = self.offset_kallsyms_num_syms
            while True:
                previous_word = self.kernel_img[position - address_byte_size:position]
                if previous_word != b"\0" * address_byte_size:
                    break
                position -= address_byte_size

            # Go backward by num_symbols.
            position -= address_byte_size

            # read from kallsyms_relative_base
            relative_base_address = int.from_bytes(self.kernel_img[position:position + address_byte_size], endian_str)

            if relative_base_address and (relative_base_address & gef_getpagesize_mask_low()) == 0:
                """
                some environment has invalid address as relative_base_address.
                so don't use the logic of is_valid_addr(relative_base_address).

                gef> hexdump -n qword 0xffffafc5c2adb260-0x10 0x20
                0xffffafc5c2adb250:    0xffffafc5c1750000 0x0000000000028193    |  ..u.............  |
                0xffffafc5c2adb260:    0x6474107414bc5404 0x6c7463be6270d277    |  .T..t.tdw.pb.ctl  |
                gef> x/16xg 0xffffafc5c1750000
                0xffffafc5c1750000:     Cannot access memory at address 0xffffafc5c1750000
                """
                while True:
                    previous_word = self.kernel_img[position - offset_byte_size:position]
                    if previous_word != b"\0" * offset_byte_size:
                        break
                    position -= offset_byte_size
                position -= self.num_symbols * offset_byte_size

        else: # kernel_version >= (6, 4):
            position = self.offset_kallsyms_token_index + 0x200
            position_relative_base = AddressUtil.align_address_to_size(position + self.num_symbols * offset_byte_size, 8) # TODO: 0x8? 0x10? ptrsize?
            relative_base_address_data = self.kernel_img[position_relative_base:position_relative_base + address_byte_size]
            relative_base_address = int.from_bytes(relative_base_address_data, endian_str)
            if not (relative_base_address and (relative_base_address & gef_getpagesize_mask_low()) == 0):
                return False

        # Getting here means that the relative_address and position have been detected correctly.
        self.verbose_info("relative_base_address: {:#x}".format(relative_base_address))

        # Try to parse addresses or offsets.
        fmt = "{:s}{:d}i".format(endianness_marker, self.num_symbols) # signed int
        kallsyms_offsets_data = self.kernel_img[position:position + self.num_symbols * offset_byte_size]
        ksym_offsets = struct.unpack(fmt, kallsyms_offsets_data)

        # Check the ratio of the negative value
        number_of_negative_items = len([offset for offset in ksym_offsets if offset < 0])
        if number_of_negative_items / len(ksym_offsets) >= 0.5:
            # the case CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y.
            kernel_addresses = []
            for offset in ksym_offsets:
                if offset < 0:
                    x = relative_base_address - 1 - offset
                    kernel_addresses.append(x)
                else:
                    kernel_addresses.append(offset)
        else:
            # the case CONFIG_KALLSYMS_ABSOLUTE_PERCPU=n.
            kernel_addresses = []
            for offset in ksym_offsets:
                x = offset + relative_base_address
                kernel_addresses.append(x)

        # Check the ratio of the null value.
        number_of_null_items = kernel_addresses.count(0)
        if number_of_null_items / len(kernel_addresses) >= 0.2:
            return False

        # It seems ok.
        self.offset_kallsyms_addresses_or_offsets = position
        self.kernel_addresses = kernel_addresses
        self.verbose_info("kallsyms_offsets: {:#x}".format(self.ro_base + self.offset_kallsyms_addresses_or_offsets))
        return True

    def find_kallsyms_addresses(self):
        """
        [Search policy]
        - From kallsyms_num_syms, go back by num_symbols element sizes.
        - num_symbols addresses are stored, so get them.

        [Positional relationship]
        - ...
        - kallsyms_addresses (~6.3, CONFIG_KALLSYMS_BASE_RELATIVE=n)
        - kallsyms_num_syms
        - kallsyms_names
        - kallsyms_markers
        - kallsyms_seqs_of_names (6.2~6.8)
        - kallsyms_token_table
        - kallsyms_token_index
        - kallsyms_addresses (6.4~?, CONFIG_KALLSYMS_BASE_RELATIVE=n) # unimplemented yet because I have never seen this pattern.
        - kallsyms_seqs_of_names (6.9~)
        - ...

        [Sample values for 64bit ~6.3]
        gef> hexdump -n qword kallsyms_addresses
        0xffffffff81ae3cb8:    0x0000000000000000 0x0000000000000000    |  ................  |
        0xffffffff81ae3cc8:    0x0000000000004000 0x0000000000009000    |  .@..............  |
        ...
        0xffffffff81ae4588:    0xffffffff81000000 0xffffffff81000000    |  ................  |
        0xffffffff81ae4598:    0xffffffff81000110 0xffffffff810001a9    |  ................  |

        [Sample values for 32bit ~6.3]
        gef> hexdump -n dword kallsyms_addresses
        0xc1940888:    0xc1000000 0xc1000000 0xc10000bc 0xc10000cc    |  ................  |
        0xc1940898:    0xc10000ed 0xc1000165 0xc10001e7 0xc1000239    |  ....e.......9...  |
        0xc19408a8:    0xc1000283 0xc10002c1 0xc10002d0 0xc1000302    |  ................  |
        0xc19408b8:    0xc1000328 0xc100032f 0xc1000338 0xc1000338    |  (.../...8...8...  |
        """

        # const values
        if Endian.is_big_endian():
            endianness_marker = ">"
        else:
            endianness_marker = "<"
        address_byte_size = current_arch.ptrsize

        # ignore the 0 immediately above offset_kallsyms_num_syms.
        position = self.offset_kallsyms_num_syms
        while True:
            previous_word = self.kernel_img[position - address_byte_size:position]
            if previous_word != b"\0" * address_byte_size:
                break
            position -= address_byte_size

        # Go backward by num_symbols.
        position -= self.num_symbols * address_byte_size

        # Try to parse addresses.
        if address_byte_size == 8:
            fmt = "{:s}{:d}Q".format(endianness_marker, self.num_symbols)
        else:
            fmt = "{:s}{:d}I".format(endianness_marker, self.num_symbols)
        kallsyms_addresses_data = self.kernel_img[position:position + self.num_symbols * address_byte_size]
        self.kernel_addresses = struct.unpack(fmt, kallsyms_addresses_data)
        self.offset_kallsyms_addresses_or_offsets = position
        self.verbose_info("kallsyms_addresses: {:#x}".format(self.ro_base + self.offset_kallsyms_addresses_or_offsets))
        return True

    def initialize(self):
        ret = self.get_kernel_version()
        if not ret:
            return False

        # the case of both kernel version string are same, but offset are different.
        version_string_offset = self.version_string_offset
        if self.get_saved_config(["version_string_offset"]):
            if self.version_string_offset != version_string_offset:
                cfg_file_name = self.get_cfg_name()
                os.remove(cfg_file_name)

        ret = self.find_kallsyms_token_table()
        if not ret:
            return False

        ret = self.find_kallsyms_token_index()
        if not ret:
            return False

        ret = self.find_kallsyms_markers()
        if not ret:
            return False

        ret = self.find_kallsyms_names()
        if not ret:
            return False

        ret = self.find_kallsyms_num_syms()
        if not ret:
            return False

        self.offset_kallsyms_addresses_or_offsets = None
        if self.kernel_version >= (4, 6):
            # On modern kernels, first check the case CONFIG_KALLSYMS_BASE_RELATIVE=y.
            self.find_kallsyms_offsets()
        if not self.offset_kallsyms_addresses_or_offsets:
            # the case CONFIG_KALLSYMS_BASE_RELATIVE=n.
            self.find_kallsyms_addresses()

        self.save_config("version_string")
        self.save_config("version_string_offset")
        self.save_config("ro_size")
        return True

    def arm64_fast_path(self):
        # This path is more faster because it does not use pagewalk.
        # Instead of finding ro_base from pagewalk results, it finds ro_base by scanning the kernel version.
        # It is especially beneficial for ARM64, because it tends to have a lot of pagetables and pagewalk take a long time.
        # It may work on other architectures, but it's limited to ARM64 because other architectures don't benefit much.

        # First, search the kernel version string from $pc.
        # It is located at around top of ro_base, and ro_base is aligned by 0x10000.
        current = (current_arch.pc & ~0xffff) + 0x10000 # Starting address to brute force ro_base
        step_size = 0x10000
        while True:
            try:
                # As kernel version string is located at around top of ro_base it is enough to check the first page.
                candidate_rodata = read_memory(current, gef_getpagesize())
            except gdb.MemoryError:
                # reached to the end of ro_base
                return False

            # '\n\0' is needed to avoid false positives in the dmesg buffer.
            r = re.search(rb"Linux version (\d+\.[\d.]*\d)[ -~]+\n\0", candidate_rodata)
            if r:
                # Found kernel version string
                version_string_address = current + r.span()[0]
                self.version_string = r.group(0)[:-2]
                version_number = r.group(1).decode("ascii")
                major = int(version_number.split(".")[0])
                minor = int(version_number.split(".")[1])
                self.kernel_version = (major, minor)
                self.may_use_big_symbol = (major, minor) >= (6, 1)
                break
            current += step_size

        # We can make the hash from the kernel version string and load from saved config.
        # At this point, following two parameters are enough.
        ret = self.get_saved_config([
            "version_string_offset",
            "ro_size",
        ])
        if not ret:
            self.quiet_info("Use slow path")
            return False

        # Restore ro_base with considering kASLR.
        self.quiet_info("Use fast path")
        self.ro_base = version_string_address - self.version_string_offset
        self.verbose_info("ro_base: {:#x}-{:#x}".format(self.ro_base, self.ro_base + self.ro_size))

        # doit
        self.kernel_img = read_memory(self.ro_base, self.ro_size)
        ret = self.initialize()
        if not ret:
            self.quiet_info("Use slow path")
            return False

        self.read_kallsyms()
        return True

    def parse_kallsyms(self):
        if self.reparse:
            self.kallsyms = [] # clear cache

        if self.kallsyms:
            return True # use cache

        # Fast path when reattaching GDB after executing this command once (only ARM64).
        if is_arm64():
            ret = self.arm64_fast_path()
            if ret:
                return True

        # Slow path
        kinfo = Kernel.get_kernel_base()
        if kinfo.has_none:
            return False

        if not kinfo.rwx:
            # On modern kernels, ro_size can be trusted, so it only tries to parse once.
            self.ro_base = kinfo.ro_base
            self.ro_size = kinfo.ro_size
            self.kernel_img = read_memory(self.ro_base, self.ro_size)
            self.verbose_info("ro_base: {:#x}-{:#x}".format(self.ro_base, self.ro_base + self.ro_size))
            ret = self.initialize()
            if not ret:
                return False
        else:
            # Older kernel that has the RWX attribute don't trust ro_size.
            # Very large values of ro_size can be detected.
            # It will take a long time to parse if you just use it.
            # Gradually increasing ro_size while searching can speed up several times.
            self.ro_base = kinfo.ro_base
            base_size = 0x100000
            step = 0x100000
            for candidate_size in range(base_size, kinfo.ro_size, step):
                self.ro_size = candidate_size
                self.kernel_img = read_memory(self.ro_base, self.ro_size)
                self.verbose_info("ro_base: {:#x}-{:#x}".format(self.ro_base, self.ro_base + self.ro_size))
                ret = self.initialize()
                if ret:
                    # found
                    break
            else:
                # not found
                return False

        # here, we got all offsets to read kallsyms
        self.read_kallsyms()
        return True

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    def do_invoke(self, args):
        self.verbose = args.verbose
        self.reparse = args.reparse
        self.quiet = args.quiet
        self.exact = args.exact

        self.quiet_info("Wait for memory scan")

        # fast path
        ret = self.parse_kallsyms()
        if not ret:
            # slow path (ignore config)
            self.reparse = True
            ret = self.parse_kallsyms()
        if not ret:
            self.quiet_err("Failed to parse.")
            return

        self.print_kallsyms(args.keyword, args.type)

        if self.out:
            if len(self.out) > GefUtil.get_terminal_size()[0]:
                gef_print("\n".join(self.out), less=not args.no_pager)
            else:
                gef_print("\n".join(self.out), less=False)
        return


@register_command
class VmlinuxToElfApplyCommand(GenericCommand):
    """Apply symbol from kallsyms in memory using vmlinux-to-elf."""
    _cmdline_ = "vmlinux-to-elf-apply"
    _category_ = "08-c. Qemu-system Cooperation - Linux Symbol"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-r", "--reparse", action="store_true",
                        help="force applying again. (default: reuse vmlinux-to-elf-dump-memory.elf if exists)")
    _syntax_ = parser.format_help()

    @staticmethod
    def dump_kernel_elf(reparse=False):
        """Dump the kernel from the memory, then apply vmlinux-to-elf to create symboled ELF."""
        # check
        try:
            vmlinux2elf = GefUtil.which("vmlinux-to-elf")
        except FileNotFoundError as e:
            err("{}".format(e))
            return None

        # resolve kversion for saved file name
        kversion = Kernel.kernel_version()
        h = hashlib.sha256(String.str2bytes(kversion.version_string)).hexdigest()[-16:]
        dumped_mem_file = os.path.join(GEF_TEMP_DIR, "dump-memory-{:s}.raw".format(h))
        symboled_vmlinux_file = os.path.join(GEF_TEMP_DIR, "dump-memory-{:s}.elf".format(h))

        # check if it can be reused
        if (not reparse) and os.path.exists(symboled_vmlinux_file) and os.path.getsize(symboled_vmlinux_file) > 0:
            info("A previously used file was found. reuse.")
            return symboled_vmlinux_file

        # resolve text_base, ro_base
        kinfo = Kernel.get_kernel_base()
        if None in (kinfo.text_base, kinfo.text_size, kinfo.ro_base, kinfo.ro_size):
            err("Failed to resolve")
            return None
        gef_print("kernel base:   {:#x}-{:#x} ({:#x} bytes)".format(kinfo.text_base, kinfo.text_end, kinfo.text_size))
        gef_print("kernel rodata: {:#x}-{:#x} ({:#x} bytes)".format(kinfo.ro_base, kinfo.ro_end, kinfo.ro_size))

        info("Start memory dump")
        # rodata size detection may be inaccurate on kernels with RWX attribute regions.
        # Since they tend to be very large, we put a size cap on the rodata to make it faster.
        if kinfo.rwx:
            # The number 0x400000 has no basis.
            fixed_ro_base_size = min(0x400000, kinfo.ro_size)
        else:
            fixed_ro_base_size = kinfo.ro_size

        # delete old file
        if os.path.exists(dumped_mem_file):
            gef_print("Delete old {}".format(dumped_mem_file))
            os.unlink(dumped_mem_file)
        if os.path.exists(symboled_vmlinux_file):
            gef_print("Delete old {}".format(symboled_vmlinux_file))
            os.unlink(symboled_vmlinux_file)

        # delete files related to old file
        for f in os.listdir(GEF_TEMP_DIR):
            if os.path.basename(dumped_mem_file) in f:
                remove_file = os.path.join(GEF_TEMP_DIR, f)
                gef_print("Delete old {}".format(remove_file))
                os.unlink(remove_file)
            if os.path.basename(symboled_vmlinux_file) in f:
                remove_file = os.path.join(GEF_TEMP_DIR, f)
                gef_print("Delete old {}".format(remove_file))
                os.unlink(remove_file)

        # dump text
        start = kinfo.text_base
        end = start + kinfo.text_size
        gef_print("Dumping .text area:   {:#x} - {:#x}".format(start, end))
        try:
            gdb.execute("dump memory {} {:#x} {:#x}".format(dumped_mem_file, start, end), to_string=True)
        except gdb.MemoryError:
            err("Memory read error. Make sure the context is in supervisor mode / Ring-0")
            return None

        # dump sparse
        text_end = kinfo.text_end
        unmapped_size = kinfo.ro_base - text_end
        if unmapped_size:
            gef_print("Non-mapping area:     {:#x} - {:#x} (ZERO fill)".format(text_end, kinfo.ro_base))
            open(dumped_mem_file, "a").write("\0" * unmapped_size)

        # dump rodata
        start = kinfo.ro_base
        end = start + fixed_ro_base_size
        gef_print("Dumping .rodata area: {:#x} - {:#x}".format(start, end))
        try:
            gdb.execute("append memory {} {:#x} {:#x}".format(dumped_mem_file, start, end), to_string=True)
        except gdb.MemoryError:
            err("Memory read error. Make sure the context is in supervisor mode / Ring-0")
            return None

        gef_print("Dumped to {}".format(dumped_mem_file))

        # apply vmlinux-to-elf
        cmd = "{} '{}' '{}' --base-address={:#x}".format(vmlinux2elf, dumped_mem_file, symboled_vmlinux_file, kinfo.text_base)
        warn("Execute `{:s}`".format(cmd))
        os.system(cmd)

        # Error
        if not os.path.exists(symboled_vmlinux_file) or os.path.getsize(symboled_vmlinux_file) == 0:
            return None

        # Success
        return symboled_vmlinux_file

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel
    def do_invoke(self, args):
        info("Wait for memory scan")

        kinfo = Kernel.get_kernel_base()
        if kinfo.text_base is None:
            err("Failed to resolve kbase")
            return

        symboled_vmlinux_file = self.dump_kernel_elf(args.reparse)
        if symboled_vmlinux_file is None:
            err("Failed to create kernel ELF.")
            return

        # load symbol
        info("Adding symbol")
        # Prior to gdb 8.x, add-symbol-file command requires a .text address
        #   gdb 9.x: Usage: add-symbol-file FILE [-readnow | -readnever] [-o OFF] [ADDR] [-s SECT-NAME SECT-ADDR]...
        #   gdb 8.x: Usage: add-symbol-file FILE ADDR [-readnow | -readnever | -s SECT-NAME SECT-ADDR]...
        # But the created ELF has no .text, only a .kernel
        # Applying an empty symbol has no effect, so tentatively specify the same address as the .kernel.
        cmd = "add-symbol-file {} {:#x} -s .kernel {:#x}".format(symboled_vmlinux_file, kinfo.text_base, kinfo.text_base)
        warn("Execute `{:s}`".format(cmd))
        gdb.execute(cmd)
        return


@register_command
class TcmallocDumpCommand(GenericCommand):
    """tcmalloc (google-perftools-2.9.1) free-list viewer (only x64)."""
    _cmdline_ = "tcmalloc-dump"
    _category_ = "06-b. Heap - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("name", choices=["self", "all", "central"], nargs="?", default="self",
                        help="target thread cache.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}\n".format(_cmdline_)
    _example_ += "{:s} self     # (default) print freelist of thread cache for current thread\n".format(_cmdline_)
    _example_ += "{:s} all      # print freelist of thread cache for all thread\n".format(_cmdline_)
    _example_ += "{:s} central  # print freelist of central cache".format(_cmdline_)

    def __init__(self):
        super().__init__()

        # google-perftools-2.9.1/src/common.h
        kClassSizesMax = 128
        #kMaxSize = 256 * 1024
        #kClassArraySize = ((kMaxSize + 127 + (120 << 7)) >> 7) + 1

        # google-perftools-2.9.1/src/thread_cache.h
        """
        00000000 ThreadCache     struc ; (sizeof=0x1040, align=0x8)
        00000000 list_           FreeList 128 dup(?) # kClassSizesMax
        00001000 size_           dd ?
        00001004 max_size_       dd ?
        00001008 sampler_        Sampler ?
        00001020 tid_            dq ?
        00001028 in_setspecific_ db ?
        00001029 unused          db 7 dup(?)
        00001030 next_           dq ?
        00001038 prev_           dq ?
        00001040 ThreadCache     ends
        """
        self.ThreadCache_offset_next = 0x1030
        self.ThreadCache_offset_freelist_array = 0x0
        self.ThreadCache_offset_tls = 0x1020 # actually this is not tid, but TLS base address
        self.ThreadCache_freelist_slot_count = kClassSizesMax
        # google-perftools-2.9.1/src/thread_cache.h
        """
        00000000 FreeList        struc ; (sizeof=0x20, align=0x8)
        00000000 list_           dq ?
        00000008 length_         dd ?
        0000000C lowater_        dd ?
        00000010 max_length_     dd ?
        00000014 length_overages_ dd ?
        00000018 size_           dd ?
        0000001C unused          dd ?
        00000020 FreeList        ends
        """
        self.sizeof_FreeList = 0x20
        self.FreeList_offset_list = 0x0
        self.FreeList_offset_length = 0x8
        self.FreeList_offset_size = 0x18
        # google-perftools-2.9.1/src/central_freelist.h
        kMaxNumTransferEntries = 64
        self.CentralCache_freelist_slot_count = kMaxNumTransferEntries
        # google-perftools-2.9.1/src/static_vars.cc
        self.CentralCache_array_count = kClassSizesMax
        # google-perftools-2.9.1/src/central_freelist.h
        """
        struct TCEntry {
          void *head;  // Head of chain of objects.
          void *tail;  // Tail of chain of objects.
        };
        class central_cache_[kClassSizesMax=128]
          0x0   SpinLock lock_;
          0x8   size_t   size_class_;     // My size class
          0x10  Span     empty_;          // Dummy header for list of empty spans
          0x40  Span     nonempty_;       // Dummy header for list of non-empty spans
          0x70  size_t   num_spans_;      // Number of spans in empty_ plus nonempty_
          0x78  size_t   counter_;        // Number of free objects in cache entry
          0x80  TCEntry  tc_slots_[kMaxNumTransferEntries=64]
          0x480 int32_t  used_slots_;
          0x484 int32_t  cache_size_;
          0x488 int32_t  max_cache_size_;
          0x48c char     pad[0x34];
        } // size:0x4c0, total_size:0x26000
        """
        self.sizeof_CentralCache = 0x4c0
        self.CentralCache_offset_size_class_ = 0x8
        self.CentralCache_offset_tc_slots_ = 0x80
        self.CentralCache_offset_used_slots_ = 0x480

        # for central cache
        """
        gef> ptype /o 'tcmalloc::Static::sizemap_'
        /* offset      |    size */  type = class tcmalloc::SizeMap {
                                     private:
                                       static const int kMaxSmallSize;
                                       static const size_t kClassArraySize;
        /*      0      |    2169 */    unsigned char class_array_[2169];
        /* XXX  3-byte hole      */
        /*   2172      |     512 */    int num_objects_to_move_[128];
        /*   2684      |     512 */    int32 class_to_size_[128];
        /* XXX  4-byte hole      */
        /*   3200      |    1024 */    size_t class_to_pages_[128];
                                     public:
        /*   4224      |       8 */    size_t num_size_classes;

                                       /* total size (bytes): 4232 */
                                     }
        gef> x/100xw 0x7ffff7df7ee0+2684
        0x7ffff7df895c <tcmalloc::Static::sizemap_+2684>:       0x00000000      0x00000008      0x00000010      0x00000020
        0x7ffff7df896c <tcmalloc::Static::sizemap_+2700>:       0x00000030      0x00000040      0x00000050      0x00000060
        0x7ffff7df897c <tcmalloc::Static::sizemap_+2716>:       0x00000070      0x00000080      0x00000090      0x000000a0
        0x7ffff7df898c <tcmalloc::Static::sizemap_+2732>:       0x000000b0      0x000000c0      0x000000d0      0x000000e0
        0x7ffff7df899c <tcmalloc::Static::sizemap_+2748>:       0x000000f0      0x00000100      0x00000120      0x00000140
        0x7ffff7df89ac <tcmalloc::Static::sizemap_+2764>:       0x00000160      0x00000180      0x000001a0      0x000001c0
        0x7ffff7df89bc <tcmalloc::Static::sizemap_+2780>:       0x000001e0      0x00000200      0x00000240      0x00000280
        0x7ffff7df89cc <tcmalloc::Static::sizemap_+2796>:       0x000002c0      0x00000300      0x00000380      0x00000400
        0x7ffff7df89dc <tcmalloc::Static::sizemap_+2812>:       0x00000480      0x00000500      0x00000580      0x00000600
        0x7ffff7df89ec <tcmalloc::Static::sizemap_+2828>:       0x00000700      0x00000800      0x00000900      0x00000a00
        0x7ffff7df89fc <tcmalloc::Static::sizemap_+2844>:       0x00000b00      0x00000c00      0x00000d00      0x00001000
        0x7ffff7df8a0c <tcmalloc::Static::sizemap_+2860>:       0x00001200      0x00001400      0x00001800      0x00001a00
        0x7ffff7df8a1c <tcmalloc::Static::sizemap_+2876>:       0x00002000      0x00002400      0x00002800      0x00003000
        0x7ffff7df8a2c <tcmalloc::Static::sizemap_+2892>:       0x00003400      0x00004000      0x00005000      0x00006000
        0x7ffff7df8a3c <tcmalloc::Static::sizemap_+2908>:       0x00006800      0x00008000      0x0000a000      0x0000c000
        0x7ffff7df8a4c <tcmalloc::Static::sizemap_+2924>:       0x0000e000      0x00010000      0x00012000      0x00014000
        0x7ffff7df8a5c <tcmalloc::Static::sizemap_+2940>:       0x00016000      0x00018000      0x0001a000      0x0001c000
        0x7ffff7df8a6c <tcmalloc::Static::sizemap_+2956>:       0x0001e000      0x00020000      0x00022000      0x00024000
        0x7ffff7df8a7c <tcmalloc::Static::sizemap_+2972>:       0x00026000      0x00028000      0x0002a000      0x0002c000
        0x7ffff7df8a8c <tcmalloc::Static::sizemap_+2988>:       0x0002e000      0x00030000      0x00032000      0x00034000
        0x7ffff7df8a9c <tcmalloc::Static::sizemap_+3004>:       0x00036000      0x00038000      0x0003a000      0x0003c000
        0x7ffff7df8aac <tcmalloc::Static::sizemap_+3020>:       0x0003e000      0x00040000      0x00000000      0x00000000
        """
        self.class_to_size_dic = [
            0x00000000, 0x00000008, 0x00000010, 0x00000020,
            0x00000030, 0x00000040, 0x00000050, 0x00000060,
            0x00000070, 0x00000080, 0x00000090, 0x000000a0,
            0x000000b0, 0x000000c0, 0x000000d0, 0x000000e0,
            0x000000f0, 0x00000100, 0x00000120, 0x00000140,
            0x00000160, 0x00000180, 0x000001a0, 0x000001c0,
            0x000001e0, 0x00000200, 0x00000240, 0x00000280,
            0x000002c0, 0x00000300, 0x00000380, 0x00000400,
            0x00000480, 0x00000500, 0x00000580, 0x00000600,
            0x00000700, 0x00000800, 0x00000900, 0x00000a00,
            0x00000b00, 0x00000c00, 0x00000d00, 0x00001000,
            0x00001200, 0x00001400, 0x00001800, 0x00001a00,
            0x00002000, 0x00002400, 0x00002800, 0x00003000,
            0x00003400, 0x00004000, 0x00005000, 0x00006000,
            0x00006800, 0x00008000, 0x0000a000, 0x0000c000,
            0x0000e000, 0x00010000, 0x00012000, 0x00014000,
            0x00016000, 0x00018000, 0x0001a000, 0x0001c000,
            0x0001e000, 0x00020000, 0x00022000, 0x00024000,
            0x00026000, 0x00028000, 0x0002a000, 0x0002c000,
            0x0002e000, 0x00030000, 0x00032000, 0x00034000,
            0x00036000, 0x00038000, 0x0003a000, 0x0003c000,
            0x0003e000, 0x00040000,
        ]

        return

    def get_heap_key(self):
        # for future use
        return 0

    def index_to_size(self, freelist, t): # freelist_index -> chunk_size
        size = read_int_from_memory(freelist + self.FreeList_offset_size)
        return size

    def get_central_cache_(self):
        # central_caches_ has ATTRIBUTE_HIDDEN, so the symbol is removed. so we need heuristic search.
        #
        # In the source code, there is size_map_ just above.
        #
        #   google-perftools-2.9.1/src/static_vars.cc
        #     ...
        #     SizeMap Static::sizemap_; <----- here
        #     CentralFreeListPadded Static::central_cache_[kClassSizesMax];
        #     ...
        #
        # And sizemap_ is initialized at the beginning of tcmalloc::Static::InitStaticVars(),
        # so the addresses are loaded.
        #
        #   google-perftools-2.9.1/src/static_vars.cc
        #   ...
        #   void Static::InitStaticVars() {
        #     sizemap_.Init(); <----- here
        #     span_allocator_.Init();
        #   ...
        #
        # This is a sample.
        #   0x7ffff7c26110 <tcmalloc::Static::InitStaticVars()>:      endbr64
        #   0x7ffff7c26114 <tcmalloc::Static::InitStaticVars()+4>:    push   rbp
        #   0x7ffff7c26115 <tcmalloc::Static::InitStaticVars()+5>:    lea    rdi,[rip+0x1d1dc4]   # 0x7ffff7df7ee0 <----- here
        #   0x7ffff7c2611c <tcmalloc::Static::InitStaticVars()+12>:   push   rbx
        #   0x7ffff7c2611d <tcmalloc::Static::InitStaticVars()+13>:   sub    rsp,0x8
        #   0x7ffff7c26121 <tcmalloc::Static::InitStaticVars()+17>:   call   0x7ffff7c20d80 <tcmalloc::SizeMap::Init()>
        #   ...
        #
        # The size of central_cache_ is 0x26000, so 0x7ffff7df7ee0 - 0x26000 is central_cache_.

        try:
            init_static_vars = AddressUtil.parse_address("&'tcmalloc::Static::InitStaticVars()'")
        except gdb.error:
            return None
        res = gdb.execute("x/10i {:#x}".format(init_static_vars), to_string=True)
        sizeof_central_cache_ = 0x26000
        for line in res.splitlines():
            m = re.search(r"\[rip\+0x\w+\].*#\s*(0x\w+)", line) # maybe size_map
            if m:
                v = int(m.group(1), 16) & 0xffffffffffffffff
                return v - sizeof_central_cache_
        else:
            return None

    def get_thread_heaps_(self):
        try:
            return AddressUtil.parse_address("&'tcmalloc::ThreadCache::thread_heaps_'")
        except gdb.error:
            return None

    def get_tls_addr_specific_thread(self, lwpid):
        PTRACE_ARCH_PRCTL = 30
        ARCH_GET_FS = 0x1003
        ppvoid = ctypes.POINTER(ctypes.c_void_p)
        fsvalue = ppvoid(ctypes.c_void_p())
        fsvalue.contents.value = 0
        libc = ctypes.CDLL("libc.so.6")
        result = libc.ptrace(PTRACE_ARCH_PRCTL, lwpid, fsvalue, ARCH_GET_FS)
        if result == 0:
            return fsvalue.contents.value
        else:
            return None

    def get_thread_list(self): # create dict: {tls_addr: lwpid}
        dic = {}
        lwpids = []
        for inf in gdb.inferiors():
            lwpids += [x.ptid[1] for x in inf.threads()]
        for lwpid in lwpids:
            tls = self.get_tls_addr_specific_thread(lwpid)
            if tls is not None:
                dic[tls] = lwpid
        return dic

    def get_thread_name_list(self): # create dict: {lwpid: name}
        lines = gdb.execute("info threads", to_string=True)
        dic = {}
        for line in lines.splitlines():
            r = re.findall(r'\(?LWP (\d+)\)? "(.+?)"', line)
            if not r:
                continue
            lwpid, name = int(r[0][0]), r[0][1]
            dic[lwpid] = name
        return dic

    def dump_thread_heap_freelist_single(self, freelist, idx):
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")

        chunk = read_int_from_memory(freelist + self.FreeList_offset_list)
        length = read_int_from_memory(freelist + self.FreeList_offset_length) & 0xffffffff
        real_length = 0
        error = False
        if chunk != 0: # freelist exists
            seen = []
            out = []
            while chunk != 0:
                real_length += 1
                seen.append(chunk)
                # corrupted memory check
                try:
                    new_chunk = read_int_from_memory(chunk)
                    out.append(" -> " + Color.colorify_hex(chunk, freed_address_color))
                    chunk = new_chunk
                except gdb.MemoryError:
                    out.append(Color.colorify(" -> {:#x} (corrupted)".format(chunk), corrupted_msg_color))
                    error = True
                    break
                # heap key decode
                chunk ^= self.get_heap_key()
                # loop check
                if chunk in seen:
                    out.append(Color.colorify(" -> {:#x} (loop)".format(chunk), corrupted_msg_color))
                    error = True
                    break
            # corrupted length check
            if length != real_length and error is False:
                out.append(Color.colorify("    (length corrupted; len != {:d})".format(length), corrupted_msg_color))
                error = True
            # print
            chunksize = self.index_to_size(freelist, idx)
            if chunksize is None:
                chunksize = Color.colorify("unknown", chunk_size_color)
            else:
                chunksize = Color.colorify_hex(chunksize, chunk_size_color)
            fmt = "freelist[idx={:d}, size={:s}, len={:d}] @ {!s}"
            self.out.append(fmt.format(idx, chunksize, length, ProcessMap.lookup_address(freelist)))
            self.out.extend(out)
        return

    def dump_thread_heap_freelist_array(self, thread_heap):
        # lwpid check
        tls = read_int_from_memory(thread_heap + self.ThreadCache_offset_tls)
        lwpid = self.get_thread_list()[tls]
        _, current_lwpid, _ = gdb.selected_thread().ptid
        name = self.get_thread_name_list()[lwpid]

        if self.FreeList_print_target_thread == "all":
            pass
        elif self.FreeList_print_target_thread == "self" and lwpid != current_lwpid:
            return
        elif isinstance(self.FreeList_print_target_thread, list) and name not in self.FreeList_print_target_thread:
            return

        current_or_not = "(current thread)" if lwpid == current_lwpid else ""
        fmt = 'thread cache [lwpid={:d}{:s},name="{:s}"] @ {:#x} freelist'
        self.out.append(titlify(fmt.format(lwpid, current_or_not, name, thread_heap)))

        freelist = thread_heap + self.ThreadCache_offset_freelist_array
        for i in range(self.ThreadCache_freelist_slot_count):
            self.dump_thread_heap_freelist_single(freelist, i)
            freelist += self.sizeof_FreeList
        return

    def dump_thread_heaps(self):
        thread_heap_head = self.get_thread_heaps_()
        if thread_heap_head is None:
            err("Not found tcmalloc::ThreadCache::thread_heaps_")
            return
        self.out.append(titlify("thread_heaps_ (head) @ {:#x}".format(thread_heap_head)))

        heap_key = self.get_heap_key()
        if heap_key != 0:
            self.out.append("heap_key: {:#x} (xor chunk->fd)".format(heap_key))

        thread_heap = read_int_from_memory(thread_heap_head)
        while thread_heap:
            self.dump_thread_heap_freelist_array(thread_heap)
            thread_heap = read_int_from_memory(thread_heap + self.ThreadCache_offset_next)
        return

    def dump_central_cache_freelist_single(self, freelist, _i, _j):
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")

        chunk = read_int_from_memory(freelist + self.FreeList_offset_list)
        if chunk != 0: # freelist exists
            seen = []
            out = []
            while chunk != 0:
                seen.append(chunk)
                # corrupted memory check
                try:
                    new_chunk = read_int_from_memory(chunk)
                    out.append(" -> " + Color.colorify_hex(chunk, freed_address_color))
                    chunk = new_chunk
                except gdb.MemoryError:
                    out.append(Color.colorify(" -> {:#x} (corrupted)".format(chunk), corrupted_msg_color))
                    break
                # heap key decode
                chunk ^= self.get_heap_key()
                # loop check
                if chunk in seen:
                    out.append(Color.colorify(" -> {:#x} (loop)".format(chunk), corrupted_msg_color))
                    break
            # print
            fmt = "central_cache_[{:d}].tc_slot[{:d}] @ {!s}"
            self.out.append(fmt.format(_i, _j, ProcessMap.lookup_address(freelist)))
            self.out.extend(out)
        return

    def dump_central_cache(self):
        central_cache_ = self.get_central_cache_()
        if central_cache_ is None:
            err("Not found tcmalloc::Static::central_cache_")
            return
        self.out.append(titlify("central_cache_ @ {:#x}".format(central_cache_)))

        heap_key = self.get_heap_key()
        if heap_key != 0:
            self.out.append("heap_key: {:#x} (xor chunk->fd)".format(heap_key))

        for i in range(self.CentralCache_array_count):
            central_cache_i = central_cache_ + i * self.sizeof_CentralCache # &central_cache[i]

            # check slot count
            used_slots = read_int_from_memory(central_cache_i + self.CentralCache_offset_used_slots_) & 0xffffffff
            max_slots = self.CentralCache_freelist_slot_count
            if used_slots == 0:
                continue

            # calc class -> size
            size_class = read_int_from_memory(central_cache_i + self.CentralCache_offset_size_class_)
            size_byte = self.class_to_size_dic[size_class]

            # dump
            fmt = "central_cache_[{:d}] @ {:#x} (used_slots:{:d}/{:d}, size_class:{:#x}, chunk_size:{:#x})"
            self.out.append(titlify(fmt.format(i, central_cache_i, used_slots, max_slots, size_class, size_byte)))
            tc_slots = central_cache_i + self.CentralCache_offset_tc_slots_ # &central_cache[i].tc_slots_
            for j in range(min(used_slots, self.CentralCache_freelist_slot_count)):
                addr = tc_slots + j * 0x10 # &central_cache[i].tc_slots_[j]
                self.dump_central_cache_freelist_single(addr, i, j)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @only_if_specific_arch(arch=("x86_64",))
    def do_invoke(self, args):
        self.out = []
        if args.name == "central":
            self.dump_central_cache()
        else:
            self.FreeList_print_target_thread = args.name
            self.dump_thread_heaps()
        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class GoHeapDumpCommand(GenericCommand):
    """go language v1.22.2 mheap dumper (only x64)."""
    _cmdline_ = "go-heap-dump"
    _category_ = "06-b. Heap - Other"

    # TODO: arena, central, mspan->next

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--mheap", type=AddressUtil.parse_address, help="the address of runtime.mheap_.")
    parser.add_argument("--mspan", type=AddressUtil.parse_address, help="the address of the target mspan.")
    parser.add_argument("-d", "--dump", action="store_true", help="with hexdump.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="display also empty slots.")
    _syntax_ = parser.format_help()

    class_to_size_dic = [
        0x0,    0x8,    0x10,   0x18,
        0x20,   0x30,   0x40,   0x50,
        0x60,   0x70,   0x80,   0x90,
        0xa0,   0xb0,   0xc0,   0xd0,
        0xe0,   0xf0,   0x100,  0x120,
        0x140,  0x160,  0x180,  0x1a0,
        0x1c0,  0x1e0,  0x200,  0x240,
        0x280,  0x2c0,  0x300,  0x380,
        0x400,  0x480,  0x500,  0x580,
        0x600,  0x700,  0x800,  0x900,
        0xa80,  0xc00,  0xc80,  0xd80,
        0x1000, 0x1300, 0x1500, 0x1800,
        0x1980, 0x1a80, 0x1b00, 0x2000,
        0x2500, 0x2600, 0x2800, 0x2a80,
        0x3000, 0x3500, 0x3800, 0x4000,
        0x4800, 0x4a80, 0x5000, 0x5500,
        0x6000, 0x6a80, 0x7000, 0x8000,
    ]

    def __init__(self):
        super().__init__()
        self.PageShift = 13
        self.PageSize = 1 << self.PageShift
        self.initialized = False
        return

    def get_struct_offset(self, type_name, member_name):
        tp = GefUtil.cached_lookup_type(type_name)
        if tp is None:
            return None
        if member_name not in tp:
            return None
        field = tp[member_name]
        if not hasattr(field, "bitpos"):
            return None
        return field.bitpos // 8

    def get_struct_size(self, type_name):
        tp = GefUtil.cached_lookup_type(type_name)
        if tp is None:
            return None
        return tp.sizeof

    def initialize(self):
        if self.initialized:
            return

        # assume 1.22.2 (Ubuntu 24.04)
        """
        struct runtime.mheap {
            /* offset | size   */
            ...
            /* 0x10148 | 0x0018 */    []*runtime.mspan allspans;
            ...
            /* 0x101d8 | 0x0008 */    [1]*[4194304]*runtime.heapArena arenas;
            ...
            /* 0x10288 | 0x6600 */    [136]struct { runtime.mcentral runtime.mcentral; runtime.pad [24]uint8 } central;
            ...
        } // total: 0x16ab8 bytes
        """

        self.offset_allspans = self.get_struct_offset("runtime.mheap", "allspans") or 0x10148
        self.sizeof_mheap = self.get_struct_size("runtime.mheap") or 0x16ab8

        """
        struct runtime.mspan {
            /* offset | size   */
            ...
            /* 0x0000 | 0x0008 */    runtime.mspan * next;
            /* 0x0008 | 0x0008 */    runtime.mspan * prev;
            ...
            /* 0x0018 | 0x0008 */    uintptr startAddr;
            /* 0x0020 | 0x0008 */    uintptr npages;
            ...
            /* 0x0032 | 0x0002 */    uint16 nelems;
            ...
            /* 0x0040 | 0x0008 */    runtime.gcBits * allocBits;
            ...
            /* 0x0062 | 0x0001 */    runtime.spanClass spanclass;
            ...
        } // total: 0xa0 bytes
        """
        self.offset_next = self.get_struct_offset("runtime.mspan", "next") or 0x0
        self.offset_prev = self.get_struct_offset("runtime.mspan", "next") or 0x8
        self.offset_startAddr = self.get_struct_offset("runtime.mspan", "startAddr") or 0x18
        self.offset_npages = self.get_struct_offset("runtime.mspan", "npages") or 0x20
        self.offset_nelems = self.get_struct_offset("runtime.mspan", "nelems") or 0x32
        self.offset_allocBits = self.get_struct_offset("runtime.mspan", "allocBits") or 0x40
        self.offset_spanclass = self.get_struct_offset("runtime.mspan", "spanClass") or 0x62
        return

    def get_mheap_(self):
        # use symbol
        try:
            return AddressUtil.parse_address("&'runtime.mheap_'")
        except gdb.error:
            pass

        # use heuristic search (TODO: Check if it is always correct)
        elf = Elf.get_elf()
        bss = elf.get_shdr(".bss")
        mheap = bss.sh_addr + bss.sh_size - self.sizeof_mheap
        if is_valid_addr(mheap):
            return mheap
        return None

    def parse_mheap(self, mheap, verbose):
        self.out.append(titlify("runtime.mheap_ @ {:#x}".format(mheap)))

        current = read_int_from_memory(mheap + self.offset_allspans)
        mspans = []
        while True:
            try:
                mspan_addr = read_int_from_memory(current)
            except gdb.MemoryError:
                self.out.append("read memory error")
                return []
            if not mspan_addr:
                break
            mspan = self.parse_mspan(mspan_addr, verbose)
            if mspan:
                mspans.append(mspan)
            current += current_arch.ptrsize

        mspans = sorted(mspans, key=lambda m: (m.chunk_size, m.address))
        return mspans

    def parse_mspan(self, mspan, verbose):
        # read member
        try:
            start_addr = read_int_from_memory(mspan + self.offset_startAddr)
        except gdb.MemoryError:
            self.out.append("read memory error")
            return None
        if not verbose and start_addr == 0:
            return None
        # spanclass = (sizeclass << 1) | (noscan bit)
        spanclass = u8(read_memory(mspan + self.offset_spanclass, 1)) >> 1
        chunk_size = self.class_to_size_dic[spanclass]
        if not verbose and chunk_size == 0:
            return None
        next_ = read_int_from_memory(mspan + self.offset_next)
        prev_ = read_int_from_memory(mspan + self.offset_prev)
        npages = read_int_from_memory(mspan + self.offset_npages)
        end_addr = start_addr + npages * self.PageSize

        aligned_nelems = nelems = read_int_from_memory(mspan + self.offset_nelems) & 0xffff
        while aligned_nelems % 8:
            aligned_nelems += 1
        allocBits_addr = read_int_from_memory(mspan + self.offset_allocBits)
        allocBits_data = read_memory(allocBits_addr, aligned_nelems)
        allocBits_array = [((b >> i) & 1) for b in allocBits_data for i in range(8)]

        Mspan = collections.namedtuple("Mspan", [
            "address", "next", "prev", "start_addr", "end_addr", "npages", "chunk_size", "nelems", "alloc_bits",
        ])
        mspan = Mspan(mspan, next_, prev_, start_addr, end_addr, npages, chunk_size, nelems, allocBits_array[:nelems])
        return mspan

    def dump_mspan_data(self, mspan):
        chunk_data = read_memory(mspan.start_addr, mspan.end_addr - mspan.start_addr)
        chunk_hexdump = hexdump(chunk_data, base=mspan.start_addr, color=False, unit=8)
        lines = chunk_hexdump.splitlines()

        color_dic = {
            # (b, idx % 2): color name
            (0, 0): "bright_yellow",
            (0, 1): "yellow",
            (1, 0): "graphite",
            (1, 1): "bright_black",
        }

        # coloring
        for i in range(len(lines)):
            line = lines[i]

            offset1 = i * 0x10
            idx1 = offset1 // mspan.chunk_size
            if idx1 >= mspan.nelems:
                color1 = ""
            else:
                b1 = mspan.alloc_bits[idx1]
                color1 = color_dic[b1, idx1 % 2]

            offset2 = i * 0x10 + 8
            idx2 = offset2 // mspan.chunk_size
            if idx2 >= mspan.nelems:
                color2 = ""
            else:
                b2 = mspan.alloc_bits[idx2]
                color2 = color_dic[b2, idx2 % 2]

            lines[i] = "{:s}{:s}{:s}{:s}{:s}".format(
                line[:19],
                Color.colorify(line[19:37], color1),
                line[37:38],
                Color.colorify(line[38:56], color2),
                line[56:],
            )

        self.out.extend(lines)
        return

    def dump_mspans(self, mspans, do_dump):
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")
        page_address_color = Config.get_gef_setting("theme.heap_page_address")

        for mspan in mspans:
            # meta data
            chunk_size_str = Color.colorify_hex(mspan.chunk_size, chunk_size_color)
            range_addr_str = Color.colorify_hex(mspan.start_addr, page_address_color)
            range_addr_str += "-"
            range_addr_str += Color.colorify_hex(mspan.end_addr, page_address_color)
            range_size = mspan.end_addr - mspan.start_addr
            msg = "mspan @ {!s} [{:s} sz={:#x} chunk_size={:s} next={!s}, prev:{!s}]".format(
                ProcessMap.lookup_address(mspan.address),
                range_addr_str, range_size, chunk_size_str,
                ProcessMap.lookup_address(mspan.next),
                ProcessMap.lookup_address(mspan.prev),
            )
            self.out.append(msg)
            if do_dump:
                self.dump_mspan_data(mspan)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @only_if_specific_arch(arch=("x86_64",))
    def do_invoke(self, args):
        self.initialize()

        self.out = []

        if args.mspan is not None:
            mspans = [self.parse_mspan(args.mspan, args.verbose)]
        elif args.mheap:
            mspans = self.parse_mheap(args.mheap, args.verbose)
        else:
            mheap = self.get_mheap_()
            if mheap is None:
                err("Not found runtime.mheap_")
                return
            mspans = self.parse_mheap(mheap, args.verbose)

        mspans = [x for x in mspans if x is not None]
        self.dump_mspans(mspans, args.dump)
        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class TlsfHeapDumpCommand(GenericCommand):
    """TLSF (Two-Level Segregated Fit) v2.4.6 free-list viewer (only x64)."""
    _cmdline_ = "tlsf-heap-dump"
    _category_ = "06-b. Heap - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--pool", type=AddressUtil.parse_address, help="the address of memory pool.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="display also empty slots.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__()

        self.REAL_FLI = 24
        self.MAX_SLI = 32

        self.size_dic = {}
        for i in range(1, 8):
            self.size_dic[0, i * 4] = (0x10 * i, 0x10 * (i + 1))
        for i in range(8):
            self.size_dic[1, i * 4] = (0x80 + 0x10 * i, 0x80 + 0x10 * (i + 1))
        for i in range(16):
            self.size_dic[2, i * 2] = (0x100 + 0x10 * i, 0x100 + 0x10 * (i + 1))
        for fl in range(3, self.REAL_FLI):
            base = 0x200 * (2 ** (fl - 3))
            step = 0x10 * (2 ** (fl - 3))
            for i in range(self.MAX_SLI):
                self.size_dic[fl, i] = (base + step * i, base + step * (i + 1))
        return

    def get_pool(self):
        try:
            mp = AddressUtil.parse_address("&mp")
        except gdb.error:
            return None

        if not is_valid_addr(mp):
            return None

        pool = read_int_from_memory(mp)
        if not is_valid_addr(pool):
            return None

        if u32(read_memory(pool, 4)) == 0x2A59FA59: # TLSF_SIGNATURE
            return pool
        return None

    def parse_pool(self, pool):
        """
        typedef struct TLSF_struct {
            u32_t tlsf_signature;

        #if TLSF_USE_LOCKS
            pthread_mutex_t lock;
        #endif

        #if TLSF_STATISTIC
            size_t used_size;
            size_t max_size;
        #endif

            area_info_t *area_head;
            u32_t fl_bitmap;
            u32_t sl_bitmap[REAL_FLI];
            bhdr_t *matrix[REAL_FLI][MAX_SLI];
        } tlsf_t;
        """
        sig = u32(read_memory(pool, 4))
        if sig != 0x2A59FA59:
            return None

        area_head = None
        if area_head is None:
            # !TLSF_USE_LOCKS && !TLSF_STATISTIC
            x = read_int_from_memory(pool + current_arch.ptrsize)
            if is_valid_addr(x):
                area_head = x
                offset_area_head = current_arch.ptrsize
        if area_head is None:
            # !TLSF_USE_LOCKS && TLSF_STATISTIC
            x = read_int_from_memory(pool + current_arch.ptrsize * 3)
            if is_valid_addr(x):
                area_head = x
                offset_area_head = current_arch.ptrsize * 3
        if area_head is None:
            # TLSF_USE_LOCKS && !TLSF_STATISTIC
            x = read_int_from_memory(pool + current_arch.ptrsize * 6)
            if is_valid_addr(x):
                area_head = x
                offset_area_head = current_arch.ptrsize * 6
        if area_head is None:
            # TLSF_USE_LOCKS && TLSF_STATISTIC
            x = read_int_from_memory(pool + current_arch.ptrsize * 8)
            if is_valid_addr(x):
                area_head = x
                offset_area_head = current_arch.ptrsize * 8
        if area_head is None:
            return None

        offset_fl_bitmap = offset_area_head + current_arch.ptrsize
        fl_bitmap = u32(read_memory(pool + offset_fl_bitmap, 4))

        offset_sl_bitmap = offset_fl_bitmap + 4
        sl_bitmap = read_memory(pool + offset_sl_bitmap, 4 * self.REAL_FLI)
        sl_bitmap = slice_unpack(sl_bitmap, 4)

        offset_matrix = AddressUtil.align_address_to_size(offset_sl_bitmap + 4 * self.REAL_FLI, current_arch.ptrsize)
        matrix = read_memory(pool + offset_matrix, current_arch.ptrsize * self.REAL_FLI * self.MAX_SLI)
        matrix = slice_unpack(matrix, current_arch.ptrsize)
        matrix = slicer(matrix, self.MAX_SLI)

        matrix_addr = [pool + offset_matrix + current_arch.ptrsize * i for i in range(self.REAL_FLI * self.MAX_SLI)]
        matrix_addr = slicer(matrix_addr, self.MAX_SLI)

        Pool = collections.namedtuple("Pool", ["addr", "sig", "area_head", "fl_bitmap", "sl_bitmap", "matrix", "matrix_addr"])
        return Pool(pool, sig, area_head, fl_bitmap, sl_bitmap, matrix, matrix_addr)

    def dump_pool(self, pool, verbose):
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")

        self.out.append("pool: {:#x}".format(pool.addr))
        self.out.append("pool->area_head: {:#x}".format(pool.area_head))
        for i, j in itertools.product(range(self.REAL_FLI), range(self.MAX_SLI)):
            if verbose or pool.matrix[i][j]:
                matrix_addr = pool.matrix_addr[i][j]
                min_size, max_size = self.size_dic.get((i, j), (0, 0))
                if min_size == max_size == 0:
                    title = "pool->matrix[{:2d}][{:2d}] @{:#x} (chunk_size=???-???)".format(i, j, matrix_addr)
                elif min_size + 0x10 == max_size:
                    title = "pool->matrix[{:2d}][{:2d}] @{:#x} (chunk_size={:#x})".format(i, j, matrix_addr, min_size)
                else:
                    title = "pool->matrix[{:2d}][{:2d}] @{:#x} (chunk_size={:#x}-{:#x})".format(i, j, matrix_addr, min_size, max_size)
                self.out.append(titlify(title))

                current = pool.matrix[i][j]
                seen = []
                while True:
                    if not is_valid_addr(current):
                        if current == 0:
                            msg = " -> {:s}".format(Color.colorify_hex(current, freed_address_color))
                        else:
                            msg = " -> {:s} (corrupted)".format(Color.colorify_hex(current, corrupted_msg_color))
                        self.out.append(msg)
                        break

                    if current in seen:
                        msg = " -> {:s} (loop detected)".format(Color.colorify_hex(current, corrupted_msg_color))
                        self.out.append(msg)
                        break

                    seen.append(current)

                    prev_hdr = read_int_from_memory(current + current_arch.ptrsize * 0)
                    size = read_int_from_memory(current + current_arch.ptrsize * 1)
                    prev_ = read_int_from_memory(current + current_arch.ptrsize * 2)
                    next_ = read_int_from_memory(current + current_arch.ptrsize * 3)

                    msg = " -> {:s} (prev_hdr={:#x}, size={:s}, prev={!s}, next={!s})".format(
                        Color.colorify_hex(current, freed_address_color),
                        prev_hdr,
                        Color.colorify_hex(size & ~0xf, chunk_size_color),
                        ProcessMap.lookup_address(prev_),
                        ProcessMap.lookup_address(next_),
                    )
                    self.out.append(msg)
                    current = next_
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @only_if_specific_arch(arch=("x86_64",))
    def do_invoke(self, args):
        if args.pool:
            pool_addr = args.pool
        else:
            pool_addr = self.get_pool()
            if pool_addr is None:
                err("Not found pool")
                return

        pool = self.parse_pool(pool_addr)
        if pool is None:
            err("Failed to parse pool.")
            return

        self.out = []
        self.dump_pool(pool, args.verbose)
        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class HoardHeapDumpCommand(GenericCommand):
    """Hoard v3.13 heap free-list viewer (only x64)."""
    _cmdline_ = "hoard-heap-dump"
    _category_ = "06-b. Heap - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-b", "--superblock", type=AddressUtil.parse_address, action="append",
                        help="the address of superblock.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def get_super_blocks(self):
        super_blocks = []
        for m in ProcessMap.get_process_maps():
            if m.path.startswith(("/", "[")):
                continue
            if m.permission != Permission.READ | Permission.WRITE:
                continue
            for p in range(m.page_start, m.page_end, gef_getpagesize()):
                v = read_int_from_memory(p)
                # vtable check
                if not is_valid_addr(v):
                    continue
                # magic check
                m = read_int_from_memory(p + current_arch.ptrsize)
                if p ^ m != 0xcafed00d:
                    continue
                super_blocks.append(p)
        return super_blocks

    @staticmethod
    @Cache.cache_until_next
    def get_all_freelist_head_from_tls():
        selected_thread = gdb.selected_thread()
        threads = gdb.selected_inferior().threads()
        if not threads:
            return

        offset_of_freelist_from_tls = -0x90
        heads = []
        for thread in threads:
            try:
                thread.switch()
            except gdb.error:
                continue
            tls = current_arch.get_tls()

            head = read_int_from_memory(tls + offset_of_freelist_from_tls)
            if is_valid_addr(head):
                heads.append(head)
        selected_thread.switch() # revert
        return heads

    def get_freelist_start(self, sb):
        # pattern1: HoardSuperblockHeaderHelper->_freeList
        freeList = read_int_from_memory(sb + current_arch.ptrsize * 11)
        if freeList:
            return freeList

        # pattern2: thread variable holds it
        objectSize = read_int_from_memory(sb + current_arch.ptrsize * 2)
        totalObjects = u32(read_memory(sb + current_arch.ptrsize * 3 + 4, 4))

        sizeof_super_block_header = 0x70
        sb_start = sb + sizeof_super_block_header
        sb_end = sb_start + objectSize * totalObjects

        heads = HoardHeapDumpCommand.get_all_freelist_head_from_tls()
        candidates = [h for h in heads if sb_start <= h < sb_end]
        if len(candidates) == 1:
            return candidates[0]
        return None

    def dump_super_block(self, sb):
        """
        struct Hoard::HoardSuperblockHeaderHelper<...> {
            /* offset | size   */
            /* 0x0000 | 0x0008 */    int (**)(void) _vptr.HoardSuperblockHeaderHelper;
            /* 0x0008 | 0x0008 */    const size_t _magicNumber;
            /* 0x0010 | 0x0008 */    const size_t _objectSize;
            /* 0x0018 | 0x0001 */    const bool _objectSizeIsPowerOfTwo;
            /* 0x001c | 0x0004 */    const unsigned int _totalObjects;
            /* 0x0020 | 0x0001 */    class HL::SpinLockType _theLock;
            /* 0x0028 | 0x0008 */    class Hoard::SmallHeap * _owner;
            /* 0x0030 | 0x0008 */    Hoard::HoardSuperblockHeaderHelper<...>::BlockType * _prev;
            /* 0x0038 | 0x0008 */    Hoard::HoardSuperblockHeaderHelper<...>::BlockType * _next;
            /* 0x0040 | 0x0004 */    unsigned int _reapableObjects;
            /* 0x0044 | 0x0004 */    unsigned int _objectsFree;
            /* 0x0048 | 0x0008 */    const char * _start;
            /* 0x0050 | 0x0008 */    char * _position;
            /* 0x0058 | 0x0008 */    class FreeSLList _freeList; // or TLS-0x90
        } // total: 0x60 bytes (+ 0x10 bytes padding)

        struct FreeSLList::Entry {
            /* offset | size   */
            /* 0x0000 | 0x0008 */    class FreeSLList::Entry * next;
        } // total: 0x8 bytes
        """

        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")

        current = self.get_freelist_start(sb)
        if current is None:
            return

        sz = read_int_from_memory(sb + current_arch.ptrsize * 2)
        self.out.append(titlify("superblock @{:#x} (chunk_size={:#x})".format(sb, sz)))

        reap_count = u32(read_memory(sb + current_arch.ptrsize * 8, 4))
        if reap_count > 0:
            self.out.append("Before allocating from freelist, you must use up all unused blocks.")
            self.out.append("There are {:s} unused blocks left.".format(Color.colorify_hex(reap_count, "bold")))

        self.out.append("freelist @{:#x}:".format(current))
        seen = []
        while True:
            if current in seen:
                self.out.append(Color.colorify(" -> {:#x} (loop) ".format(current), corrupted_msg_color))
                break
            seen.append(current)
            if current and not is_valid_addr(current):
                self.out.append(Color.colorify(" -> {:#x} (corrupted) ".format(current), corrupted_msg_color))
                break
            self.out.append(" -> {:s}".format(Color.colorify_hex(current, freed_address_color)))
            if current == 0:
                break
            current = read_int_from_memory(current)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @only_if_specific_arch(arch=("x86_64",))
    def do_invoke(self, args):
        if args.superblock:
            super_blocks = args.superblock
        else:
            super_blocks = self.get_super_blocks()
            if super_blocks is None:
                err("Not found superblock")
                return

        self.out = []
        for super_block in super_blocks:
            self.dump_super_block(super_block)
        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class MimallocHeapDumpCommand(GenericCommand):
    """mimalloc heap free-list viewer (only x64)."""
    _cmdline_ = "mimalloc-heap-dump"
    _category_ = "06-b. Heap - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-m", "--mi-heap-main", type=AddressUtil.parse_address,
                        help="the address of _mi_heap_main.")
    parser.add_argument("--v21x", action="store_true", help="for v2.1.x.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def initialize(self):
        """
        typedef struct mi_heap_s {
            mi_tld_t* tld;
            _Atomic(mi_block_t*) thread_delayed_free;
            mi_threadid_t thread_id;
            mi_arena_id_t arena_id;
            uintptr_t cookie;
            uintptr_t keys[2];
            mi_random_ctx_t random; // 0x88 bytes
            size_t page_count;
            size_t page_retired_min;
            size_t page_retired_max;
            mi_heap_t* next;
            bool no_reclaim;
            mi_page_t* pages_free_direct[MI_PAGES_DIRECT]; // 0x81
            mi_page_queue_t pages[MI_BIN_FULL + 1];
        } mi_heap_t;
        """
        self.offset_next = 0xd8
        self.offset_pages_free_direct = 0xe8
        self.MI_PAGES_DIRECT = 0x81

        """
        typedef struct mi_page_s {
            uint32_t slice_count; // v2.1.6
            uint32_t slice_offset; // v2.1.6
            uint8_t segment_idx; // latest
            uint8_t segment_in_use:1; // latest
            uint8_t is_committed:1;
            uint8_t is_zero_init:1;
            uint8_t is_huge:1;

            uint16_t capacity;
            uint16_t reserved;
            mi_page_flags_t flags; // 8 or 16
            uint8_t free_is_zero:1;
            uint8_t retire_expire:7;

            mi_block_t* free;
            mi_block_t* local_free;
            uint16_t used;
            uint8_t block_size_shift;

            size_t block_size;
            uint8_t* page_start;

        #if (MI_ENCODE_FREELIST || MI_PADDING)
            uintptr_t keys[2];
        #endif

            _Atomic(mi_thread_free_t) xthread_free;
            _Atomic(uintptr_t) xheap;

            struct mi_page_s* next;
            struct mi_page_s* prev;

        #if MI_INTPTR_SIZE==4 // pad to 12 words on 32-bit
            void* padding[1];
        #endif
        } mi_page_t;
        """
        if self.v21x:
            self.offset_capacity = 0x4 * 2 + 2 # with padding
            self.offset_free = 0x10
            self.offset_local_free = 0x18
            self.offset_used = 0x20
            self.offset_block_size = 0x28
        else:
            self.offset_capacity = 0x02
            self.offset_free = 0x08
            self.offset_local_free = 0x10
            self.offset_used = 0x18
            self.offset_block_size = 0x20
        return

    def get_mi_heap_main(self):
        try:
            return AddressUtil.parse_address("&_mi_heap_main")
        except gdb.error:
            return None

        tls = current_arch.get_tls()
        if is_valid_addr(tls - 0x10):
            mi_heap_main = read_int_from_memory(tls - 0x10)
            if is_valid_addr(mi_heap_main):
                tld_main = read_int_from_memory(mi_heap_main)
                if is_valid_addr(tld_main):
                    return mi_heap_main
        return None

    def dump_page(self, mi_page):
        bs = read_int_from_memory(mi_page + self.offset_block_size)
        cap = u16(read_memory(mi_page + self.offset_capacity, 2))
        used = u16(read_memory(mi_page + self.offset_used, 2))
        self.out.append(titlify("mi_page_t @{:#x} (block_size={:#x}, capacity={:#x}, used={:#x})".format(mi_page, bs, cap, used)))

        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")

        # freelist
        freelist_addr = mi_page + self.offset_free
        self.out.append("freelist @{:#x}:".format(freelist_addr))

        current = read_int_from_memory(freelist_addr)
        seen = []
        while True:
            if current in seen:
                self.out.append(Color.colorify("-> {:#x} (loop) ".format(current), corrupted_msg_color))
                break
            seen.append(current)
            if current and not is_valid_addr(current):
                self.out.append(Color.colorify("-> {:#x} (corrupted) ".format(current), corrupted_msg_color))
                break
            self.out.append(" -> {:s}".format(Color.colorify_hex(current, freed_address_color)))
            if current == 0:
                break
            current = read_int_from_memory(current)

        # local freelist
        local_freelist_addr = mi_page + self.offset_local_free
        self.out.append("local_freelist @{:#x}:".format(local_freelist_addr))

        current = read_int_from_memory(local_freelist_addr)
        seen = []
        while True:
            if current in seen:
                self.out.append(Color.colorify("-> {:#x} (loop) ".format(current), corrupted_msg_color))
                break
            seen.append(current)
            if current and not is_valid_addr(current):
                self.out.append(Color.colorify("-> {:#x} (corrupted) ".format(current), corrupted_msg_color))
                break
            self.out.append(" -> {:s}".format(Color.colorify_hex(current, freed_address_color)))
            if current == 0:
                break
            current = read_int_from_memory(current)
        return

    def dump_heap(self, mi_heap):
        seen = []
        for i in range(self.MI_PAGES_DIRECT):
            mi_page_t = read_int_from_memory(mi_heap + self.offset_pages_free_direct + current_arch.ptrsize * i)
            if not is_valid_addr(mi_page_t):
                continue
            x = read_int_from_memory(mi_page_t)
            if x == 0:
                """
                0x7ffff7e72448|+0x00e8|+029: 0x00007ffff7e6be80 <_mi_page_empty>  ->  0x0000000000000000
                0x7ffff7e72450|+0x00f0|+030: 0x00007ffff7e6be80 <_mi_page_empty>  ->  0x0000000000000000
                0x7ffff7e72458|+0x00f8|+031: 0x0000040203400088  ->  0x01000eb001000700  <-  $rcx
                0x7ffff7e72460|+0x0100|+032: 0x00007ffff7e6be80 <_mi_page_empty>  ->  0x0000000000000000
                0x7ffff7e72468|+0x0108|+033: 0x00007ffff7e6be80 <_mi_page_empty>  ->  0x0000000000000000
                """
                continue
            if mi_page_t in seen:
                continue
            self.dump_page(mi_page_t)
            seen.append(mi_page_t)
        return None

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @only_if_specific_arch(arch=("x86_64",))
    def do_invoke(self, args):
        self.v21x = args.v21x
        self.initialize()

        if args.mi_heap_main:
            mi_heap_main = args.mi_heap_main
        else:
            mi_heap_main = self.get_mi_heap_main()
            if mi_heap_main is None:
                err("Not found _mi_heap_main")
                return

        self.out = []
        while mi_heap_main:
            if not is_valid_addr(mi_heap_main):
                continue
            self.dump_heap(mi_heap_main)
            mi_heap_main = read_int_from_memory(mi_heap_main + self.offset_next)

        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class V8Command(GenericCommand):
    """Print v8 tagged object, or load more commands from internet."""
    _cmdline_ = "v8"
    _category_ = "09-e. Misc - V8"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address, nargs="?",
                       help="target map address.")
    group.add_argument("-l", "--load-v8-gdbinit", action="store_true",
                       help="load gdbinit for v8 from internet")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        if args.load_v8_gdbinit:
            gdbinit_filename = os.path.join(GEF_TEMP_DIR, "gdbinit-v8")
            if not os.path.exists(gdbinit_filename):
                # https://chromium.googlesource.com/v8/v8/+/refs/heads/main/tools/gdbinit
                url = "https://chromium.googlesource.com/v8/v8/+/refs/heads/main/tools/gdbinit?format=TEXT"
                gdbinit_data = http_get(url)
                import base64
                gdbinit_data = base64.b64decode(gdbinit_data)
                open(gdbinit_filename, "wb").write(gdbinit_data)
                info("download gdbinit from internet.")
            else:
                info("reuse gdbinit cached previously.")

            try:
                gdb.execute("source {:s}".format(gdbinit_filename))
                info("Successfully loaded.")
            except gdb.error:
                err("Failed to load.")
            return

        if args.address:
            try:
                # Since this command is used so often, it can be implemented without loading from internet.
                cmd = "call (void) _v8_internal_Print_Object((void*)({:#x}))".format(args.address)
                gdb.execute(cmd)
            except gdb.error:
                pass
        return


@register_command
class PartitionAllocDumpCommand(GenericCommand, BufferingOutput):
    """PartitionAlloc free-list viewer for chromium stable."""
    _cmdline_ = "partition-alloc-dump"
    _category_ = "06-b. Heap - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("target_buffer_root", choices=["fast_malloc", "array_buffer", "buffer", "fm", "ab", "b"],
                        help="the target buffer_root. The last three are abbreviated forms.")
    parser.add_argument("-f", "--force-heuristic", action="store_true",
                        help="use heuristic roots detection.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="display also empty slots.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} array_buffer # walk from array_buffer_root_\n".format(_cmdline_)
    _example_ += "{:s} ab           # same above".format(_cmdline_)

    _note_ = "Chromium mainline is too fast to develop. So if parse is failed, you need fix this gef.py.\n"
    _note_ += "\n"
    _note_ += "Simplified partition alloc structure:\n"
    _note_ += "\n"
    _note_ += " +-root-----------------+\n"
    _note_ += " | ...                  |    +---->+-extent------------+  +-->+-extent------------+  +-> ...\n"
    _note_ += " | next_super_page      |    |     | next              |--+   | next              |--+\n"
    _note_ += " | next_partition_page  |    |     +-------------------+      +-------------------+\n"
    _note_ += " | ...                  |    |\n"
    _note_ += " | first_extent         |----+\n"
    _note_ += " | direct_map_list      |--------->+-direct_map_extent-+  +-->+-direct_map_extent-+  +-> ...\n"
    _note_ += " | ...                  |          | bucket            |  |   | bucket            |  |\n"
    _note_ += " |                      |          | next_extent       |--+   | next_extent       |--+\n"
    _note_ += " |                      |          +-------------------+      +-------------------+\n"
    _note_ += " |                      |\n"
    _note_ += " +-bucket[0](0x20)------+\n"
    _note_ += " | head                 |--------->+-slot_span---------+  +-->+-slot_span---------+  +-> ...\n"
    _note_ += " | slot_size            |<---------| bucket            |  |   | bucket            |  |\n"
    _note_ += " | ...                  |    +-----| freelist_head     |  |   | freelist_head     |  |\n"
    _note_ += " +-bucket[1](0x20)------+    |     | next_slot_span    |--+   | next_slot_span    |--+\n"
    _note_ += " | head                 |    |     +-------------------+      +-------------------+\n"
    _note_ += " | slot_size            |    |\n"
    _note_ += " | ...                  |    |\n"
    _note_ += " +----------------------+    +---->+-slot--------------+\n"
    _note_ += " | ...                  |          | next              |---+\n"
    _note_ += " |                      |          | (freed)           |   |\n"
    _note_ += " +----------------------+          +-slot--------------+   |\n"
    _note_ += "                                   |                   |   |\n"
    _note_ += "                                   | (used)            |   |\n"
    _note_ += "                                   +-slot--------------+<--+\n"
    _note_ += "                               +---| next              |\n"
    _note_ += "                               |   | (freed)           |\n"
    _note_ += "                               |   +-slot--------------+\n"
    _note_ += "                               |   |                   |\n"
    _note_ += "                               |   | (used)            |\n"
    _note_ += "                               +-->+-slot--------------+\n"
    _note_ += "                                   | next              |---> NULL\n"
    _note_ += "                                   | (freed)           |\n"
    _note_ += "                                   +-slot--------------+\n"
    _note_ += "                                   |                   |\n"
    _note_ += "                                   |                   |\n"
    _note_ += "                                   +-------------------+\n"
    _note_ += "\n"
    _note_ += "`extent`, `slot_span` and `slot` are in super_page.\n"
    _note_ += "\n"
    _note_ += "      +-super_page-(2MB)----+\n"
    _note_ += " 4KB  | Guard Page          |\n"
    _note_ += "      +---------------------+\n"
    _note_ += " 4KB  | extent * 1          |\n"
    _note_ += "      | slot_span * 126     |\n"
    _note_ += "      | unused * 1          |\n"
    _note_ += "      +---------------------+\n"
    _note_ += " 8KB  | Guard Page          |\n"
    _note_ += "      +---------------------+\n"
    _note_ += " 16KB | Partition Page #1   |\n"
    _note_ += "      |   slot              |\n"
    _note_ += "      |   slot              |\n"
    _note_ += "      |   ...               |\n"
    _note_ += "      +---------------------+\n"
    _note_ += "      | ...                 |\n"
    _note_ += "      +---------------------+\n"
    _note_ += " 16KB | Partition Page #126 |\n"
    _note_ += "      |   slot              |\n"
    _note_ += "      |   slot              |\n"
    _note_ += "      |   ...               |\n"
    _note_ += "      +---------------------+\n"
    _note_ += " 12KB | Unused              |\n"
    _note_ += "      +---------------------+\n"
    _note_ += "  4KB | Guard Page          |\n"
    _note_ += "      +---------------------+"

    @staticmethod
    @Cache.cache_this_session
    def get_roots_heuristic():
        """searches for fast_malloc_root, array_buffer_root_ and buffer_root_"""
        # the pointers to each root are in the RW area.
        # first, we list up the RW area.
        filepath = Path.get_filepath(append_proc_root_prefix=False)
        maps = ProcessMap.get_process_maps()
        if is_64bit():
            codebase = ProcessMap.get_section_base_address(filepath)
            mask = 0x0000ffff00000000
            chromium_rw_maps = [p for p in maps if p.permission.value == Permission.READ | Permission.WRITE]
            chromium_rw_maps = [p for p in chromium_rw_maps if (p.page_start & mask) == (codebase & mask) and p.path != filepath]
        elif is_32bit():
            mask = 0xff000000
            heapbase = HeapbaseCommand.heap_base()
            chromium_rw_maps = [p for p in maps if p.permission.value == Permission.READ | Permission.WRITE]
            chromium_rw_maps = [p for p in chromium_rw_maps if p.page_start < heapbase and p.path != filepath]

        # n_gram([1,2,3,4,5],3) -> [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
        def n_gram(target, n):
            for idx in range(len(target) - n + 1):
                yield target[idx:idx + n]

        # Check the RW area
        roots = []
        for maps in chromium_rw_maps:
            # explode to each qword (if 64 bit arch) or dword (if 32 bit arch)
            data_list = slice_unpack(read_memory(maps.page_start, maps.size), current_arch.ptrsize)
            addr_list = list(range(maps.page_start, maps.page_end, current_arch.ptrsize))

            """
            https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/wtf/allocator/partitions.cc
            partition_alloc::PartitionRoot* Partitions::fast_malloc_root_ = nullptr;
            partition_alloc::PartitionRoot* Partitions::array_buffer_root_ = nullptr;
            partition_alloc::PartitionRoot* Partitions::buffer_root_ = nullptr;

            0x61d34e37f360 <WTF::Partitions::fast_malloc_root_>:    0x0000000000000000
            0x61d34e37f368 <WTF::Partitions::array_buffer_root_>:   0x000061d34e383000
            0x61d34e37f370 <WTF::Partitions::buffer_root_>: 0x000061d34e37f380
            0x61d34e37f378 <guard variable for WTF::Partitions::Initialize()::initialized>: 0x0000000100000101
            ...
            0x61d34e3811c0 <WTF::Partitions::InitializeOnce()::fast_malloc_allocator>:      0x0000000000000000
            ...
            0x61d34e383000 <WTF::Partitions::InitializeOnce()::buffer_allocator>:   0x0000000000000001
            ...
            0x61d34e37f380 <WTF::Partitions::InitializeArrayBufferPartition()::array_buffer_allocator>:     0x0000000000000001
            """
            # check consecutive quadruples
            for addr, data in zip(n_gram(addr_list, 4), n_gram(data_list, 4)):
                # root pointer address and root address are close (see above example)
                if data[0] != 0 and (addr[0] & mask) != (data[0] & mask):
                    # fast_malloc_root_ may be zero. but if non-zero, it holds address close to itself
                    continue
                if (addr[1] & mask) != (data[1] & mask):
                    # array_buffer_root_ is must be non-zero. it holds address close to itself
                    continue
                if (addr[2] & mask) != (data[2] & mask):
                    # buffer_root_ is must be non-zero. it holds address close to itself
                    continue
                # they should be aligned
                if data[0] & 0x7:
                    continue
                if data[1] & 0x7:
                    continue
                if data[2] & 0x7:
                    continue
                # initialized must be bool 0x01
                if (data[3] & 0xff) != 0x01:
                    continue
                # check root size
                buffer_root_size = data[1] - data[2]
                if buffer_root_size < 0x300: # 0x300 is heuristic value
                    continue
                if buffer_root_size > 0x4000: # 0x4000 is heuristic value
                    continue
                # check root struct.
                """
                The first 64 bytes of root are mostly 0 due to padding considering the cache line.
                This is same both at 64-bit and 32bit arch.

                [WTF::Partitions::InitializeOnce()::buffer_allocator]
                0x61d34e383000: 0x0000000000000001      0x0000000000000000     <--- here may be used
                0x61d34e383010: 0xffffffff00000001      0x0000000000000000     <--- here may be used
                0x61d34e383020: 0x0000000000000000      0x0000000000000000     <--- hare may be not used
                0x61d34e383030: 0x0000000000000000      0x0000000000000000     <--- here may be not used

                [WTF::Partitions::InitializeArrayBufferPartition()::array_buffer_allocator]
                0x61d34e37f380: 0x0000000100000001      0x0000000000000004     <--- here may be used
                0x61d34e37f390: 0xffffffff00000000      0x0000000100000000     <--- here may be used
                0x61d34e37f3a0: 0x0000000000000004      0x0000000000000000     <--- here may be used
                0x61d34e37f3b0: 0x0000000000000000      0x0000000000000000     <--- here may be not used
                """
                if read_memory(data[1], 64)[33:] != b"\0" * 31:
                    continue
                if read_memory(data[2], 64)[33:] != b"\0" * 31:
                    continue
                # add candidate
                Root = collections.namedtuple("Root", ["name", "address"])
                root_candidate = [
                    Root("fast_malloc_root_", addr[0]),
                    Root("array_buffer_root_", addr[1]),
                    Root("buffer_root_", addr[2]),
                ]
                roots.append(root_candidate)

        # debug print
        if len(roots) == 0:
            err("roots were not found. try check code")
            return []

        elif len(roots) == 1:
            for r in roots[0]:
                info("found: {:s}: {:#x}".format(r.name, r.address))
            return roots[0]

        else:
            err("candidates for root are found in multiple places. try check code")
            for root in roots:
                for r in root:
                    gef_print("  candidate: {:20s} {:#x}".format(r.name, r.address))
                gef_print()
            return []

    def get_roots(self, force_heuristic):
        def get_root(root_string):
            try:
                root_addr = AddressUtil.parse_address("&'WTF::Partitions::{:s}'".format(root_string))
                Root = collections.namedtuple("Root", ["name", "address"])
                return [Root(root_string, root_addr)]
            except gdb.error:
                return []

        roots = []
        # try from symbols
        if not force_heuristic:
            for root_string in ["fast_malloc_root_", "array_buffer_root_", "buffer_root_"]:
                roots += get_root(root_string)
        # maybe no symbols, try heuristic
        if len(roots) == 0:
            info("Use heuristic search.")
            roots = PartitionAllocDumpCommand.get_roots_heuristic()
        # retry checking
        if len(roots) == 0:
            info("Symbol is not found.")
        return roots

    def get_sentinel_slot_spans(self):
        """sentinel_slot_span is default slot_span, so search it"""
        sentinel = []
        try:
            t = AddressUtil.parse_address("&'base::internal::SlotSpanMetadata<true>::sentinel_slot_span_'")
            sentinel.append(t)
        except gdb.error:
            pass
        try:
            f = AddressUtil.parse_address("&'base::internal::SlotSpanMetadata<false>::sentinel_slot_span_'")
            sentinel.append(f)
        except gdb.error:
            pass
        return sentinel

    def read_root(self, addr, name):
        ptrsize = current_arch.ptrsize
        _root = {}
        _root["name"] = name
        _root["addr"] = current = read_int_from_memory(addr)
        """
        https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/src/partition_alloc/partition_root.h
        struct base::PartitionRoot {
            struct alignas(internal::kPartitionCachelineSize) Settings {
                QuarantineMode quarantine_mode = QuarantineMode::kAlwaysDisabled; // uint8_t
                ScanMode scan_mode = ScanMode::kDisabled; // uint8_t
                BucketDistribution bucket_distribution = BucketDistribution::kNeutral; // uint8_t
                bool with_thread_cache = false;
                bool use_cookie = false;
                bool brp_enabled_ = false;
                bool mac11_malloc_size_hack_enabled_ = false;
                size_t mac11_malloc_size_hack_usable_size_ = 0;
                bool use_configurable_pool = false;
                bool zapping_by_free_flags = false;
                bool scheduler_loop_quarantine = false;
                bool memory_tagging_enabled_ = false;
                TagViolationReportingMode memory_tagging_reporting_mode_ = TagViolationReportingMode::kUndefined;
                ThreadIsolationOption thread_isolation;
                bool use_pool_offset_freelists = false;
                uint32_t extras_size = 0;
            } settings; // 64 bytes
            internal::Lock lock_;  // 8 bytes
            Bucket buckets[internal::kNumBuckets] = {};
            Bucket sentinel_bucket{};
            bool initialized = false;
            std::atomic<size_t> total_size_of_committed_pages{0};
            std::atomic<size_t> max_size_of_committed_pages{0};
            std::atomic<size_t> total_size_of_super_pages{0};
            std::atomic<size_t> total_size_of_direct_mapped_pages{0};
            size_t total_size_of_allocated_bytes PA_GUARDED_BY(internal::PartitionRootLock(this)) = 0;
            size_t max_size_of_allocated_bytes PA_GUARDED_BY(internal::PartitionRootLock(this)) = 0;
            std::atomic<uint64_t> syscall_count{};
            std::atomic<uint64_t> syscall_total_time_ns{};
            std::atomic<size_t> total_size_of_brp_quarantined_bytes{0};
            std::atomic<size_t> total_count_of_brp_quarantined_slots{0};
            std::atomic<size_t> cumulative_size_of_brp_quarantined_bytes{0};
            std::atomic<size_t> cumulative_count_of_brp_quarantined_slots{0};
            size_t empty_slot_spans_dirty_bytes PA_GUARDED_BY(internal::PartitionRootLock(this)) = 0;
            int max_empty_slot_spans_dirty_bytes_shift = 3;
            uintptr_t next_super_page = 0;
            uintptr_t next_partition_page = 0;
            uintptr_t next_partition_page_end = 0;
            SuperPageExtentEntry* current_extent = nullptr;
            SuperPageExtentEntry* first_extent = nullptr;
            DirectMapExtent* direct_map_list PA_GUARDED_BY(internal::PartitionRootLock(this)) = nullptr;
            SlotSpanMetadata* global_empty_slot_span_ring[internal::kMaxFreeableSpans] PA_GUARDED_BY(internal::PartitionRootLock(this)) = {};
            int16_t global_empty_slot_span_ring_index PA_GUARDED_BY(internal::PartitionRootLock(this)) = 0;
            int16_t global_empty_slot_span_ring_size PA_GUARDED_BY(internal::PartitionRootLock(this)) = internal::kDefaultEmptySlotSpanRingSize;
            uintptr_t inverted_self = 0;
            std::atomic<int> thread_caches_being_constructed_{0};
            bool quarantine_always_for_testing = false;
            size_t scheduler_loop_quarantine_branch_capacity_in_bytes = 0;
            internal::LightweightQuarantineRoot scheduler_loop_quarantine_root;
            std::optional<internal::base::NoDestructor<internal::LightweightQuarantineBranch>> scheduler_loop_quarantine;
        };
        """
        current += 64 # sizeof(struct Settings)

        _root["lock_"] = u64(read_memory(current, 8))
        current += 8

        # for 32bit, there is 2 patterns because aligned or packed
        if is_32bit():
            if self.align_pad is None:
                x = read_int_from_memory(current)
                if x == 0:
                    self.align_pad = True
                else:
                    self.align_pad = False
            if self.align_pad:
                current += ptrsize

        _root["buckets"] = []
        while True:
            if read_int_from_memory(current) == 1: # search `bool initialized`
                break
            bucket, current = self.read_bucket(current)
            _root["buckets"].append(bucket)
        _root["sentinel_bucket"] = _root["buckets"].pop()

        _root["initialized"] = read_int_from_memory(current) & 0xff
        current += ptrsize # with pad
        _root["total_size_of_committed_pages"] = read_int_from_memory(current)
        current += ptrsize
        _root["max_size_of_committed_pages"] = read_int_from_memory(current)
        current += ptrsize
        _root["total_size_of_super_pages"] = read_int_from_memory(current)
        current += ptrsize
        _root["total_size_of_direct_mapped_pages"] = read_int_from_memory(current)
        current += ptrsize
        _root["total_size_of_allocated_bytes"] = read_int_from_memory(current)
        current += ptrsize
        _root["max_size_of_allocated_bytes"] = read_int_from_memory(current)
        current += ptrsize
        _root["syscall_count"] = read_int_from_memory(current)
        current += ptrsize
        _root["syscall_total_time_ns"] = read_int_from_memory(current)
        current += ptrsize
        _root["total_size_of_brp_quarantined_bytes"] = read_int_from_memory(current)
        current += ptrsize
        _root["total_count_of_brp_quarantined_slots"] = read_int_from_memory(current)
        current += ptrsize
        _root["cumulative_size_of_brp_quarantined_bytes"] = read_int_from_memory(current)
        current += ptrsize
        _root["cumulative_count_of_brp_quarantined_slots"] = read_int_from_memory(current)
        current += ptrsize
        _root["empty_slot_spans_dirty_bytes"] = u32(read_memory(current, 4))
        current += ptrsize # with pad
        _root["max_empty_slot_spans_dirty_bytes_shift"] = u32(read_memory(current, 4))
        current += ptrsize # with pad
        _root["next_super_page"] = read_int_from_memory(current)
        current += ptrsize
        _root["next_partition_page"] = read_int_from_memory(current)
        current += ptrsize
        _root["next_partition_page_end"] = read_int_from_memory(current)
        current += ptrsize
        _root["current_extent"] = read_int_from_memory(current)
        current += ptrsize
        _root["first_extent"] = read_int_from_memory(current)
        current += ptrsize
        _root["direct_map_list"] = read_int_from_memory(current)
        current += ptrsize

        _root["global_empty_slot_span_ring"] = []
        inv = _root["addr"] ^ ((1 << (current_arch.ptrsize * 8)) - 1)
        while True:
            if read_int_from_memory(current + ptrsize) == inv: # search `inverted_self`
                break
            x = read_int_from_memory(current)
            current += ptrsize
            _root["global_empty_slot_span_ring"].append(x)

        _root["global_empty_slot_span_ring_index"] = u16(read_memory(current, 2))
        current += 2
        _root["global_empty_slot_span_ring_size"] = u16(read_memory(current, 2))
        current += ptrsize - 2 # with pad
        _root["inverted_self"] = read_int_from_memory(current)
        current += ptrsize
        _root["thread_caches_being_constructed_"] = u32(read_memory(current, 4))
        current += 4
        _root["quarantine_always_for_testing"] = u32(read_memory(current, 4)) & 0xff
        current += 4
        _root["scheduler_loop_quarantine_branch_capacity_in_bytes"] = u32(read_memory(current, 4))
        current += ptrsize # with pad
        _root["scheduler_loop_quarantine_root"] = read_int_from_memory(current)
        current += ptrsize
        _root["scheduler_loop_quarantine"] = read_int_from_memory(current)
        current += ptrsize

        Root = collections.namedtuple("Root", _root.keys())
        root = Root(*_root.values())
        return root, current

    def read_bucket(self, addr):
        ptrsize = current_arch.ptrsize
        _bucket = {}
        _bucket["addr"] = current = addr
        """
        https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/src/partition_alloc/partition_bucket.h
        struct base::internal::PartitionBucket {
            SlotSpanMetadata* active_slot_spans_head;
            SlotSpanMetadata* empty_slot_spans_head;
            SlotSpanMetadata* decommitted_slot_spans_head;
            uint32_t slot_size;
            uint32_t num_system_pages_per_slot_span : 8;
            uint32_t num_full_slot_spans : 24;
            uint64_t slot_size_reciprocal;
            bool can_store_raw_size;
        };
        """
        _bucket["active_slot_spans_head"] = read_int_from_memory(current)
        current += ptrsize
        _bucket["empty_slot_spans_head"] = read_int_from_memory(current)
        current += ptrsize
        _bucket["decommitted_slot_spans_head"] = read_int_from_memory(current)
        current += ptrsize
        _bucket["slot_size"] = u32(read_memory(current, 4))
        current += 4
        x = u32(read_memory(current, 4))
        _bucket["num_system_pages_per_slot_span"] = x & 0xff
        _bucket["num_full_slot_spans"] = (x >> 8) & 0xffffff
        current += 4

        # for 32bit, there is 2 patterns because aligned or packed
        if is_32bit() and self.align_pad:
            current += 4
        _bucket["slot_size_reciprocal"] = u64(read_memory(current, 8))
        current += 8

        x = u32(read_memory(current, 4))
        _bucket["can_store_raw_size"] = x & 0xff
        current += ptrsize # with pad

        Bucket = collections.namedtuple("Bucket", _bucket.keys())
        bucket = Bucket(*_bucket.values())
        return bucket, current

    def read_extent(self, addr):
        ptrsize = current_arch.ptrsize
        _extent = {}
        _extent["addr"] = current = addr
        _extent["super_page_base"] = current - 0x1000
        """
        https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/src/partition_alloc/partition_superpage_extent_entry.h
        struct PartitionSuperPageExtentEntry {
          PartitionRootBase* root;
          PartitionSuperPageExtentEntry* next;
          uint16_t number_of_consecutive_super_pages;
          uint16_t number_of_nonempty_slot_spans;
        };
        """
        _extent["root"] = read_int_from_memory(current)
        current += ptrsize
        _extent["next"] = read_int_from_memory(current)
        current += ptrsize
        _extent["number_of_consecutive_super_pages"] = u16(read_memory(current, 2))
        current += 2
        _extent["number_of_nonempty_slot_spans"] = u16(read_memory(current, 2))
        current += 2
        _extent["super_page_end"] = _extent["super_page_base"] + _extent["number_of_consecutive_super_pages"] * 0x200000

        Extent = collections.namedtuple("Extent", _extent.keys())
        extent = Extent(*_extent.values())
        return extent, current

    def read_direct_map(self, addr):
        ptrsize = current_arch.ptrsize
        _direct_map = {}
        _direct_map["addr"] = current = addr
        """
        https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/src/partition_alloc/partition_direct_map_extent.h
        struct PartitionDirectMapExtent {
          PartitionDirectMapExtent* next_extent;
          PartitionDirectMapExtent* prev_extent;
          PartitionBucket* bucket;
          size_t reservation_size;
          size_t padding_for_alignment;
        };
        """
        _direct_map["next_extent"] = read_int_from_memory(current)
        current += ptrsize
        _direct_map["prev_extent"] = read_int_from_memory(current)
        current += ptrsize
        _direct_map["bucket"] = read_int_from_memory(current)
        current += ptrsize
        _direct_map["reservation_size"] = read_int_from_memory(current)
        current += ptrsize
        _direct_map["padding_for_alignment"] = read_int_from_memory(current)
        current += ptrsize

        DirectMap = collections.namedtuple("DirectMap", _direct_map.keys())
        direct_map = DirectMap(*_direct_map.values())
        return direct_map, current

    def read_slot_span(self, addr):
        ptrsize = current_arch.ptrsize
        _slot_span = {}
        _slot_span["addr"] = current = addr
        _slot_span["super_page_addr"] = (_slot_span["addr"] & gef_getpagesize_mask_high()) - gef_getpagesize()
        _slot_span["partition_page_index"] = (_slot_span["addr"] & gef_getpagesize_mask_low()) // 0x20
        _slot_span["partition_page_start"] = _slot_span["super_page_addr"] + _slot_span["partition_page_index"] * gef_getpagesize() * 4
        """
        https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/src/partition_alloc/partition_page.h
        struct SlotSpanMetadata {
          PartitionFreelistEntry* freelist_head = nullptr;
          SlotSpanMetadata* next_slot_span = nullptr;
          PartitionBucket* const bucket = nullptr;
          uint32_t marked_full : 1
          uint32_t num_allocated_slots : kMaxSlotsPerSlotSpanBits; // 13 bits
          uint32_t num_unprovisioned_slots : kMaxSlotsPerSlotSpanBits; // 13 bits
          const uint32_t can_store_raw_size_ : 1;
          uint32_t freelist_is_sorted_ : 1;
          uint32_t unused1_ : (32 - 1 - 2 * kMaxSlotsPerSlotSpanBits - 1 - 1); // 3 bits
          uint16_t in_empty_cache_ : 1;
          uint16_t empty_cache_index_ : kMaxEmptyCacheIndexBits; // 7 bits
          uint16_t unused2_ : (16 - 1 - kMaxEmptyCacheIndexBits); // 8 bits
        };
        """
        _slot_span["freelist_head"] = read_int_from_memory(current)
        current += ptrsize
        _slot_span["next_slot_span"] = read_int_from_memory(current)
        current += ptrsize
        _slot_span["bucket"] = read_int_from_memory(current)
        current += ptrsize
        x = u32(read_memory(current, 4))
        current += 4
        _slot_span["marked_full"] = (x >> 0) & 1
        _slot_span["num_allocated_slots"] = (x >> 1) & 0x1fff
        _slot_span["num_unprovisioned_slots"] = (x >> 14) & 0x1fff
        _slot_span["can_store_raw_size_"] = (x >> 27) & 1
        _slot_span["freelist_is_sorted_"] = (x >> 28) & 1
        _slot_span["unused1_"] = (x >> 29) & 0x7
        x = u16(read_memory(current, 2))
        current += 2
        _slot_span["in_empty_cache_"] = (x >> 0) & 1
        _slot_span["empty_cache_index_"] = (x >> 1) & 0x7f
        _slot_span["unused2_"] = (x >> 8) & 0xff

        SlotSpan = collections.namedtuple("SlotSpan", _slot_span.keys())
        slot_span = SlotSpan(*_slot_span.values())
        return slot_span, current

    def C(self, address):
        management_color = Config.get_gef_setting("theme.heap_management_address")
        current = self.root.current_extent
        while current:
            extent, _ = self.read_extent(current)
            if extent.super_page_base <= address < extent.super_page_end:
                return Color.colorify_hex(address, management_color)
            current = extent.next
        if is_valid_addr(address):
            return str(ProcessMap.lookup_address(address))
        return "{:#x}".format(address)

    def P(self, address):
        page_address_color = Config.get_gef_setting("theme.heap_page_address")
        return Color.colorify_hex(address, page_address_color)

    def dump_root(self, root):
        self.out.append(titlify("*{} @ {:#x}".format(root.name, root.addr)))
        self.out.append("uint8_t one_cacheline[64]:                             ...")
        self.out.append("::partition_alloc::Lock lock_;                         {:#x}".format(root.lock_))
        self.out.append("Bucket buckets[{:3d}]:".format(len(root.buckets)))
        for idx, bucket in enumerate(root.buckets):
            self.dump_bucket(bucket, root, idx)
        if self.verbose:
            self.out.append("Bucket sentinel_bucket:")
            self.dump_bucket(root.sentinel_bucket, root)
        else:
            self.out.append("Bucket sentinel_bucket:                                ...")
        self.out.append("bool initialized:                                      {:#x}".format(root.initialized))
        self.out.append("std::atomic<size_t> total_size_of_committed_pages:     {:#x}".format(root.total_size_of_committed_pages))
        self.out.append("std::atomic<size_t> max_size_of_committed_pages:       {:#x}".format(root.max_size_of_committed_pages))
        self.out.append("std::atomic<size_t> total_size_of_super_pages:         {:#x}".format(root.total_size_of_super_pages))
        self.out.append("std::atomic<size_t> total_size_of_direct_mapped_pages: {:#x}".format(root.total_size_of_direct_mapped_pages))
        self.out.append("size_t total_size_of_allocated_bytes:                  {:#x}".format(root.total_size_of_allocated_bytes))
        self.out.append("size_t max_size_of_allocated_bytes:                    {:#x}".format(root.max_size_of_allocated_bytes))
        self.out.append("std::atomic<uint64_t> syscall_count:                   {:#x}".format(root.syscall_count))
        self.out.append("std::atomic<uint64_t> syscall_total_time_ns:           {:#x}".format(root.syscall_total_time_ns))
        self.out.append("std::atomic<size_t> total_size_of_brp_quarantined_bytes: {:#x}".format(root.total_size_of_brp_quarantined_bytes))
        self.out.append("std::atomic<size_t> total_count_of_brp_quarantined_slots: {:#x}".format(root.total_count_of_brp_quarantined_slots))
        self.out.append("std::atomic<size_t> cumulative_size_of_brp_quarantined_bytes: {:#x}".format(root.cumulative_size_of_brp_quarantined_bytes))
        self.out.append("std::atomic<size_t> cumulative_count_of_brp_quarantined_slots: {:#x}".format(root.cumulative_count_of_brp_quarantined_slots))
        self.out.append("size_t empty_slot_spans_dirty_bytes:                   {:#x}".format(root.empty_slot_spans_dirty_bytes))
        self.out.append("int max_empty_slot_spans_dirty_bytes_shift:            {:#x}".format(root.max_empty_slot_spans_dirty_bytes_shift))
        self.out.append("uintptr_t next_super_page:                             {:s}".format(self.P(root.next_super_page)))
        self.out.append("uintptr_t next_partition_page:                         {:s}".format(self.P(root.next_partition_page)))
        self.out.append("uintptr_t next_partition_page_end:                     {:s}".format(self.P(root.next_partition_page_end)))
        self.out.append("SuperPageExtentEntry* current_extent:                  {:s}".format(self.C(root.current_extent)))
        self.dump_extent_list(root.current_extent)
        self.out.append("SuperPageExtentEntry* first_extent:                    {:s}".format(self.C(root.first_extent)))
        self.dump_extent_list(root.first_extent)
        self.out.append("DirectMapExtent* direct_map_list:                      {:s}".format(self.C(root.direct_map_list)))
        self.dump_direct_map_list(root.direct_map_list, root)
        ring_len = len(root.global_empty_slot_span_ring)
        if self.verbose:
            self.out.append("SlotSpanMetadata* global_empty_slot_span_ring[{:3d}]:".format(ring_len))
            for i in range(len(root.global_empty_slot_span_ring)):
                colored_slot_span = self.C(root.global_empty_slot_span_ring[i])
                self.out.append("    global_empty_slot_span_ring[{:3d}]:                       {:s}".format(i, colored_slot_span))
        else:
            self.out.append("SlotSpan* global_empty_slot_span_ring[{:3d}]:             ...".format(ring_len))
        self.out.append("int16_t global_empty_slot_span_ring_index:             {:#x}".format(root.global_empty_slot_span_ring_index))
        self.out.append("int16_t global_empty_slot_span_ring_size:              {:#x}".format(root.global_empty_slot_span_ring_size))
        inv_inv = root.inverted_self ^ ((1 << (current_arch.ptrsize * 8)) - 1)
        inv_inv = str(ProcessMap.lookup_address(inv_inv))
        self.out.append("uintptr_t inverted_self:                               {:#x} (=~{:s})".format(root.inverted_self, inv_inv))
        self.out.append("std::atomic<int> thread_caches_being_constructed_:     {:#x}".format(root.thread_caches_being_constructed_))
        self.out.append("bool quarantine_always_for_testing:                    {:#x}".format(root.quarantine_always_for_testing))
        self.out.append("size_t scheduler_loop_quarantine_branch_capacity_in_bytes: {:#x}".format(root.scheduler_loop_quarantine_branch_capacity_in_bytes))
        self.out.append("internal::LightweightQuarantineRoot scheduler_loop_quarantine_root: {:#x}".format(root.scheduler_loop_quarantine_root))
        self.out.append("NoDestructor<...> scheduler_loop_quarantine:           {:#x}".format(root.scheduler_loop_quarantine))
        return

    def dump_extent_list(self, head):
        try:
            current = head
            while current:
                extent, _ = self.read_extent(current)
                self.out.append("    -> extent @{:s}".format(self.C(extent.addr)))
                self.out.append("           root:{!s} ".format(ProcessMap.lookup_address(extent.root)))
                super_page_info = "{:s} - {:s}".format(self.P(extent.super_page_base), self.P(extent.super_page_end))
                page_info = "(total 0x200000(2MB) * {:d} pages)".format(extent.number_of_consecutive_super_pages)
                self.out.append("           super_page:{:s} {:s}".format(super_page_info, page_info))
                self.out.append("           non_empty_slot_spans:{:d} ".format(extent.number_of_nonempty_slot_spans))
                self.out.append("           next:{:s}".format(self.C(extent.next)))
                current = extent.next
        except Exception:
            self.err("Corrupted?")
        return

    def dump_direct_map_list(self, head, root):
        try:
            current = head
            while current:
                direct_map, _ = self.read_direct_map(current)
                self.out.append("    -> direct_map @{:s}: ".format(self.C(direct_map.addr)))
                self.out.append("           next_extent:{:s} ".format(self.C(direct_map.next_extent)))
                self.out.append("           prev_extent:{:s} ".format(self.C(direct_map.prev_extent)))
                self.out.append("           bucket:{:s} ".format(self.C(direct_map.bucket)))
                self.out.append("           reservation_size:{:#x}".format(direct_map.reservation_size))
                self.out.append("           padding_for_alignment:{:#x}".format(direct_map.padding_for_alignment))
                bucket, _ = self.read_bucket(direct_map.bucket)
                self.dump_bucket(bucket, root)
                current = direct_map.next_extent
        except Exception:
            self.err("Corrupted?")
        return

    def dump_bucket(self, bucket, root, idx=None):
        sentinel1 = self.get_sentinel_slot_spans() # from symbol
        sentinel2 = [root.sentinel_bucket.active_slot_spans_head] # from heuristic search
        sentinel_or_0 = list(set(sentinel1 + sentinel2 + [0x0])) # uniq

        if not self.verbose:
            if bucket.active_slot_spans_head in sentinel_or_0:
                return # skip printing

        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")
        label_active_color = Config.get_gef_setting("theme.heap_label_active")
        label_inactive_color = Config.get_gef_setting("theme.heap_label_inactive")

        slot_size = Color.colorify("{:#7x}".format(bucket.slot_size), chunk_size_color)
        if idx is not None:
            self.out.append("    buckets[{:3d}](slot_size:{:s}) @{!s}".format(idx, slot_size, ProcessMap.lookup_address(bucket.addr)))
        else:
            self.out.append("    bucket(slot_size:{:s}) @{!s}".format(slot_size, ProcessMap.lookup_address(bucket.addr)))
        self.out.append("        num_system_pages_per_slot_span:{:#x} ".format(bucket.num_system_pages_per_slot_span))
        self.out.append("        num_full_slot_spans:{:#x} ".format(bucket.num_full_slot_spans))
        self.out.append("        slot_size_reciprocal:{:#x}".format(bucket.slot_size_reciprocal))
        self.out.append("        can_store_raw_size:{:#x}".format(bucket.can_store_raw_size))

        if self.verbose:
            target_list = ["active_slot_spans_head", "empty_slot_spans_head", "decommitted_slot_spans_head"]
        else:
            target_list = ["active_slot_spans_head"]

        for key in target_list:
            head = getattr(bucket, key)
            # sentinel can be ignored, so skip
            if not self.verbose and head in sentinel_or_0:
                continue
            if head in sentinel_or_0:
                # print sentinel (verbose)
                colored_key = Color.colorify(key, label_inactive_color)
                self.out.append("        {:s}:sentinel_pages".format(colored_key))
            else:
                # default
                colored_key = Color.colorify(key, label_active_color)
                self.out.append("        {:s}:{:s}".format(colored_key, self.C(head)))
            self.dump_slot_span(head, bucket)
        return

    def dump_slot_span(self, head, bucket):
        current = head
        while current:
            try:
                slot_span, _ = self.read_slot_span(current)
            except Exception:
                self.err("Corrupted?")
                break
            fmt = "            -> slot_span @{:s} (#{:3d} of super_page @{:s})"
            self.out.append(fmt.format(self.C(slot_span.addr), slot_span.partition_page_index, self.P(slot_span.super_page_addr)))
            self.out.append("                   next_slot_span:{:s} ".format(self.C(slot_span.next_slot_span)))
            colored_page_start = self.P(slot_span.partition_page_start)
            colored_page_end = self.P(slot_span.partition_page_start + bucket.num_system_pages_per_slot_span * gef_getpagesize())
            self.out.append("                   slot_span_area:{:s}-{:s} ".format(colored_page_start, colored_page_end))
            self.out.append("                   num_allocated_slots:{:#x}".format(slot_span.num_allocated_slots))
            self.dump_freelist(slot_span.freelist_head, bucket, slot_span)
            current = slot_span.next_slot_span
        return

    def dump_freelist(self, head, bucket, slot_span):
        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")

        self.out.append("                   freelist_head:{:s} ".format(self.C(head)))

        slot_size = bucket.slot_size
        page_start = slot_span.partition_page_start
        page_end = slot_span.partition_page_start + bucket.num_system_pages_per_slot_span * gef_getpagesize()

        text = ""
        cnt = 0
        chunk = head
        seen = []
        while chunk:
            if cnt % 6 == 0:
                if cnt > 0:
                    text += "\n"
                text += " " * 23

            if chunk in seen:
                text += Color.colorify("-> {:#x} (loop) ".format(chunk), corrupted_msg_color)
                break

            if not ((page_start <= chunk < page_end) and ((chunk - page_start) % slot_size == 0)):
                text += Color.colorify("-> {:#x} (corrupted) ".format(chunk), corrupted_msg_color)
                break

            try:
                next_chunk = byteswap(read_int_from_memory(chunk))
                if is_64bit() and next_chunk:
                    next_chunk |= chunk & 0xffffffff00000000
            except gdb.MemoryError:
                text += Color.colorify("-> {:#x} (corrupted) ".format(chunk), corrupted_msg_color)
                break

            text += "-> " + Color.colorify_hex(chunk, freed_address_color) + " "
            cnt += 1
            seen.append(chunk)
            chunk = next_chunk

        if cnt > 0:
            text += "(num: {:#x})".format(cnt)

        if text:
            self.out.append(text)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    def do_invoke(self, args):
        if is_32bit():
            self.align_pad = None
        self.verbose = args.verbose

        self.out = []
        for r in self.get_roots(args.force_heuristic):
            ok = False
            if args.target_buffer_root in ["fast_malloc", "fm"] and r.name == "fast_malloc_root_":
                ok = True
            elif args.target_buffer_root in ["array_buffer", "ab"] and r.name == "array_buffer_root_":
                ok = True
            elif args.target_buffer_root in ["buffer", "b"] and r.name == "buffer_root_":
                ok = True

            if ok:
                try:
                    root, _ = self.read_root(r.address, r.name)
                except Exception:
                    mem_value = read_int_from_memory(r.address)
                    err("Parse error {:s}: @ {:#x} -> {:#x}".format(r.name, r.address, mem_value))
                    continue
                self.root = root # for coloring
                self.dump_root(root)

        self.print_output(args)
        return


@register_command
class MuslHeapDumpCommand(GenericCommand, BufferingOutput):
    """musl v1.2.5 (src/malloc/mallocng) heap reusable chunks viewer (only x64/x86)."""
    # See https://h-noson.hatenablog.jp/entry/2021/05/03/161933#-177pts-mooosl
    _cmdline_ = "musl-heap-dump"
    _category_ = "06-b. Heap - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("command", nargs="?", default="unused", choices=["ctx", "unused"],
                        help="dump mode (default: %(default)s).")
    parser.add_argument("--idx", type=int, help="the active index of dump target.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="also dump an empty active index.")
    _syntax_ = parser.format_help()

    def get_malloc_context_heuristic(self):
        try:
            # search malloc
            malloc = AddressUtil.parse_address("malloc")
            self.info("malloc: {:#x}".format(malloc))

            # search __libc_malloc_impl
            """
            [pattern 1]
               0x7ffff7d7dde0 <malloc>:     jmp    0x7ffff7d8ece2 <__libc_malloc_impl>

            [pattern 2]
               0x7ffff7f71650 <malloc>:     endbr64
               0x7ffff7f71654 <malloc+4>:   jmp    0x7ffff7f72ff0

            [pattern 3]
               0xf7f78bf0 <malloc>: jmp    0xf7f8bc3c
            """
            res = gdb.execute("x/10i {:#x}".format(malloc), to_string=True)
            for line in res.splitlines():
                m = re.search(r"jmp\s*(0x\w+)", line)
                if not m:
                    continue
                __libc_malloc_impl = int(m.group(1), 16)
                break
            self.info("__libc_malloc_impl: {:#x}".format(__libc_malloc_impl))

            # search __malloc_alloc_meta
            """
            [pattern 1]
               0x7ffff7d8ed0a <__libc_malloc_impl+40>:      call   0x7ffff7d88dc1 <__errno_location>
               0x7ffff7d8ed34 <__libc_malloc_impl+82>:      call   0x7ffff7da0c3b <mmap64>
               0x7ffff7d8ed48 <__libc_malloc_impl+102>:     call   0x7ffff7d8e36b <wrlock>
               0x7ffff7d8ed4d <__libc_malloc_impl+107>:     call   0x7ffff7d8e382 <step_seq>
               0x7ffff7d8ed52 <__libc_malloc_impl+112>:     call   0x7ffff7d8e45a <__malloc_alloc_meta>

            [pattern 2]
               0x7ffff7f7303b:      call   0x7ffff7f8a640 <mmap64>
               0x7ffff7f73074:      call   0x7ffff7f72290

            [pattern 3]
               0xf7f8bc40:  call   0xf7f7cf84
               0xf7f8bc67:  call   0xf7f84e85 <__errno_location>
               0xf7f8bc88:  call   0xf7f9cd53 <mmap64>
               0xf7f8bc9b:  call   0xf7f8b3aa
               0xf7f8bca0:  call   0xf7f8b3d2
               0xf7f8bca5:  call   0xf7f8b439
            """
            __malloc_alloc_meta_candidate = []
            res = gdb.execute("x/100i {:#x}".format(__libc_malloc_impl), to_string=True)
            for line in res.splitlines():
                m = re.search(r"call\s*(0x\w+)", line)
                if not m:
                    continue
                addr = int(m.group(1), 16)
                __malloc_alloc_meta_candidate.append(addr)

            # search __malloc_context
            """
            [pattern 1]
               0x7ffff7d8e45a <__malloc_alloc_meta>:        push   r12
               0x7ffff7d8e45c <__malloc_alloc_meta+2>:      push   rbp
               0x7ffff7d8e45d <__malloc_alloc_meta+3>:      push   rbx
               0x7ffff7d8e45e <__malloc_alloc_meta+4>:      sub    rsp,0x10
               0x7ffff7d8e462 <__malloc_alloc_meta+8>:      cmp    DWORD PTR [rip+0x26d67f],0x0  # 0x7ffff7ffbae8 <__malloc_context+8>

            [pattern 2]
               0x7ffff7f72290:      endbr64
               0x7ffff7f72294:      push   r12
               0x7ffff7f72296:      push   rbp
               0x7ffff7f72297:      push   rbx
               0x7ffff7f72298:      sub    rsp,0x10
               0x7ffff7f7229c:      mov    rax,QWORD PTR fs:0x28
               0x7ffff7f722a5:      mov    QWORD PTR [rsp+0x8],rax
               0x7ffff7f722aa:      xor    eax,eax
               0x7ffff7f722ac:      mov    eax,DWORD PTR [rip+0x89816]  # 0x7ffff7ffbac8
               0x7ffff7f722b2:      test   eax,eax

            [pattern 3]
               0xf7f8b439:  push   ebp
               0xf7f8b43a:  push   edi
               0xf7f8b43b:  push   esi
               0xf7f8b43c:  push   ebx
               0xf7f8b43d:  call   0xf7f7cf84
               0xf7f8b442:  add    ebx,0x6fbbe       # libc_bss_base
               0xf7f8b448:  sub    esp,0x1c
               0xf7f8b44b:  cmp    DWORD PTR [ebx+0x708],0x0
            """
            for cand in __malloc_alloc_meta_candidate:
                self.info("alloc_meta (candidate): {:#x}".format(cand))
                res = gdb.execute("x/10i {:#x}".format(cand), to_string=True)
                for line in res.splitlines():
                    if is_x86_64():
                        m = re.search(r"DWORD PTR \[rip\+0x\w+\].*#\s*(0x\w+)", line)
                        if not m:
                            continue
                        __malloc_context_init_done = int(m.group(1), 16)
                    else:
                        m = re.search(r"DWORD PTR \[e[abcd]x\+(0x\w+)\]", line)
                        if not m:
                            continue
                        __malloc_context_init_done_offset = int(m.group(1), 16)
                        maps = ProcessMap.get_process_maps()
                        rw_maps = [p for p in maps if p.permission.value == Permission.READ | Permission.WRITE]
                        rw_maps = [p for p in rw_maps if "libc.so" in p.path]
                        libc_bss_base = rw_maps[0].page_start
                        __malloc_context_init_done = libc_bss_base + __malloc_context_init_done_offset
                    # check
                    value = u32(read_memory(__malloc_context_init_done, 4))
                    if value not in [0, 1]: # init_done is 1 or 0
                        continue
                    # found
                    self.info("__malloc_context.init_done: {:#x}".format(__malloc_context_init_done))
                    __malloc_context = __malloc_context_init_done - current_arch.ptrsize
                    x = read_int_from_memory(__malloc_context)
                    if x == gef_getpagesize():
                        __malloc_context -= current_arch.ptrsize
                    self.info("__malloc_context: {:#x}".format(__malloc_context))
                    return __malloc_context
            return None
        except Exception:
            err("Not found &__malloc_context")
            return None

    def get_malloc_context(self):
        try:
            return AddressUtil.parse_address("&__malloc_context")
        except gdb.error:
            self.info("Symbol is not found. It will use heuristic search")
            return self.get_malloc_context_heuristic()

    def class_to_size(self, cl):
        class_to_size_list = [
            1, 2, 3, 4, 5, 6, 7, 8,
            9, 10, 12, 15,
            18, 20, 25, 31,
            36, 42, 50, 63,
            72, 84, 102, 127,
            146, 170, 204, 255,
            292, 340, 409, 511,
            584, 682, 818, 1023,
            1169, 1364, 1637, 2047,
            2340, 2730, 3276, 4095,
            4680, 5460, 6552, 8191,
        ]
        assert cl < len(class_to_size_list)
        return class_to_size_list[cl] * 0x10

    def read_ctx(self):
        ptrsize = current_arch.ptrsize
        _ctx = {}
        _ctx["addr"] = current = self.get_malloc_context()
        if current is None:
            return None
        """
        struct malloc_context {
            uint64_t secret;
        #ifndef PAGESIZE
            size_t pagesize;
        #endif
            int init_done;
            unsigned mmap_counter;
            struct meta *free_meta_head;
            struct meta *avail_meta;
            size_t avail_meta_count;
            size_t avail_meta_area_count;
            size_t meta_alloc_shift;
            struct meta_area *meta_area_head;
            struct meta_area *meta_area_tail;
            unsigned char *avail_meta_areas;
            struct meta *active[48];
            size_t usage_by_class[48];
            uint8_t unmap_seq[32];
            uint8_t bounces[32];
            uint8_t seq;
            uintptr_t brk;
        };
        """
        _ctx["secret"] = u64(read_memory(current, 8))
        current += 8
        x = read_int_from_memory(current)
        if x == gef_getpagesize():
            _ctx["pagesize"] = x
            current += ptrsize
        else:
            _ctx["pagesize"] = None

        _ctx["init_done"] = u32(read_memory(current, 4))
        current += 4
        _ctx["mmap_counter"] = u32(read_memory(current, 4))
        current += 4
        _ctx["free_meta_head"] = read_int_from_memory(current)
        current += ptrsize
        _ctx["avail_meta"] = read_int_from_memory(current)
        current += ptrsize
        _ctx["avail_meta_count"] = read_int_from_memory(current)
        current += ptrsize
        _ctx["avail_meta_area_count"] = read_int_from_memory(current)
        current += ptrsize
        _ctx["alloc_shift"] = read_int_from_memory(current)
        current += ptrsize
        _ctx["meta_area_head"] = read_int_from_memory(current)
        current += ptrsize
        _ctx["meta_area_tail"] = read_int_from_memory(current)
        current += ptrsize
        _ctx["avail_meta_areas"] = read_int_from_memory(current)
        current += ptrsize
        _ctx["active"] = []
        for _ in range(48):
            _ctx["active"].append(read_int_from_memory(current))
            current += ptrsize
        _ctx["usage_by_class"] = []
        for _ in range(48):
            _ctx["usage_by_class"].append(read_int_from_memory(current))
            current += ptrsize
        _ctx["unmap_seq"] = read_memory(current, 32)
        current += 32
        _ctx["bounces"] = read_memory(current, 32)
        current += 32
        _ctx["seq"] = ord(read_memory(current, 1))
        current += ptrsize # with padding
        _ctx["brk"] = read_int_from_memory(current)
        current += ptrsize

        Ctx = collections.namedtuple("Ctx", _ctx.keys())
        return Ctx(*_ctx.values())

    def dump_ctx(self, ctx):
        self.out.append(titlify("__malloc_context: {:#x}".format(ctx.addr)))
        self.out.append("  uint64_t secret:                    {:#x}".format(ctx.secret))
        if ctx.pagesize:
            self.out.append("  size_t pagesize:                    {:#x}".format(ctx.pagesize))
        self.out.append("  int init_done:                      {:#x}".format(ctx.init_done))
        self.out.append("  unsigned int mmap_counter:          {:#x}".format(ctx.mmap_counter))
        self.out.append("  struct meta* free_meta_head:        {!s}".format(ProcessMap.lookup_address(ctx.free_meta_head)))
        self.out.append("  struct meta* avail_meta:            {!s}".format(ProcessMap.lookup_address(ctx.avail_meta)))
        self.out.append("  size_t avail_meta_count:            {:#x}".format(ctx.avail_meta_count))
        self.out.append("  size_t avail_meta_area_count:       {:#x}".format(ctx.avail_meta_area_count))
        self.out.append("  size_t alloc_shift:                 {:#x}".format(ctx.alloc_shift))
        self.out.append("  struct meta_area* meta_area_head:   {!s}".format(ProcessMap.lookup_address(ctx.meta_area_head)))
        self.out.append("  struct meta_area* meta_area_tail:   {!s}".format(ProcessMap.lookup_address(ctx.meta_area_tail)))
        self.out.append("  unsigned char* avail_meta_areas:    {!s}".format(ProcessMap.lookup_address(ctx.avail_meta_areas)))
        self.out.append("  struct meta* active[48]:")
        for i in range(48):
            self.out.append("     active[{:2d}] (for chunk_size={:#7x}):     {:#x}".format(i, self.class_to_size(i), ctx.active[i]))
        self.out.append("  size_t usage_by_class[48]:")
        for i in range(48):
            self.out.append("     usage_by_class[{:2d}]:                     {:#x}".format(i, ctx.usage_by_class[i]))
        self.out.append("  uint8_t unmap_seq[32]:              {}".format(" ".join(["{:02x}".format(x) for x in ctx.unmap_seq])))
        self.out.append("  uint8_t bounces[32]:                {}".format(" ".join(["{:02x}".format(x) for x in ctx.bounces])))
        self.out.append("  uint8_t seq:                        {:#x}".format(ctx.seq))
        self.out.append("  uintptr_t brk:                      {!s}".format(ProcessMap.lookup_address(ctx.brk)))
        return

    def read_meta(self, addr):
        ptrsize = current_arch.ptrsize
        _meta = {}
        _meta["addr"] = current = addr
        """
        struct meta {
            struct meta *prev;
            struct meta *next;
            struct group *mem;
            volatile int avail_mask;
            volatile int freed_mask;
            uintptr_t last_idx:5;
            uintptr_t freeable:1;
            uintptr_t sizeclass:6;
            uintptr_t maplen:8*sizeof(uintptr_t)-12;
        };
        """
        _meta["prev"] = read_int_from_memory(current)
        current += ptrsize
        _meta["next"] = read_int_from_memory(current)
        current += ptrsize
        _meta["mem"] = read_int_from_memory(current)
        current += ptrsize
        _meta["avail_mask"] = u32(read_memory(current, 4))
        current += 4
        _meta["freed_mask"] = u32(read_memory(current, 4))
        current += 4
        x = read_int_from_memory(current)
        _meta["last_idx"] = x & 0b11111
        _meta["freeable"] = (x >> 5) & 0b1
        _meta["sizeclass"] = (x >> 6) & 0b111111
        _meta["maplen"] = (x >> 12)
        current += ptrsize

        Meta = collections.namedtuple("Meta", _meta.keys())
        return Meta(*_meta.values())

    def make_state(self, meta):
        avail_mask = meta.avail_mask
        freed_mask = meta.freed_mask

        text = ""
        for _ in range(meta.last_idx + 1):
            if avail_mask & 1:
                text = "A" + text
            elif freed_mask & 1:
                text = "F" + text
            else:
                text = "U" + text
            avail_mask >>= 1
            freed_mask >>= 1
        return text

    def read_group(self, meta, offset):
        ptrsize = current_arch.ptrsize
        _group = {}
        _group["addr"] = current = meta.mem + offset
        _group["data"] = read_memory(_group["addr"], self.class_to_size(meta.sizeclass))
        """
        from source code:
        struct group {
            struct meta *meta;
            unsigned char active_idx:5;
            char pad[UNIT - sizeof(struct meta *) - 1]; // UNIT = 16
            unsigned char storage[];
        };

        however, the actual usage is as follows. (x64)
        struct group {
            struct meta *meta;
            unsigned int slot_offset32;
            unsigned char is_slot_offset32;
            unsigned char slot_index:5;
            unsigned char reserved:3;
            unsigned short slot_offset16;
        };
        """
        _group["meta"] = read_int_from_memory(current)
        current += ptrsize
        x = u32(read_memory(current, 4))
        current += 4 if is_x86_64() else 8
        y = u32(read_memory(current, 4))
        _group["reserved"] = (x >> 13) & 0b111
        _group["slot_idx"] = (y >> 8) & 0b11111
        if y & 0xff:
            _group["slot_offset"] = x
        else:
            _group["slot_offset"] = (y >> 16) & 0xffff
        current += ptrsize

        Group = collections.namedtuple("Group", _group.keys())
        return Group(*_group.values())

    def dump_chunk(self, group, state):
        chunk_used_color = Config.get_gef_setting("theme.heap_chunk_used")
        chunk_freed_color = Config.get_gef_setting("theme.heap_chunk_freed")

        subinfo = "state:{:5s} meta:{:<#14x} reserved:{:#x}".format(state, group.meta, group.reserved)
        if state == "Used":
            subinfo += " slot_idx:{:<#3x} slot_offset:{:#x}".format(group.slot_idx, group.slot_offset)

        data = slicer(group.data, current_arch.ptrsize * 2)
        addr = group.addr
        group_line_threshold = 8

        # create dump text
        unpack = u32 if current_arch.ptrsize == 4 else u64
        width = current_arch.ptrsize * 2 + 2
        done = False
        for blk, blks in itertools.groupby(data):
            repeat_count = len(list(blks))
            d1, d2 = unpack(blk[:current_arch.ptrsize]), unpack(blk[current_arch.ptrsize:])
            dascii = "".join([chr(x) if 0x20 <= x < 0x7f else "." for x in blk])
            fmt = "{:#x}: {:#0{:d}x} {:#0{:d}x} | {:s} | {:s}"
            if repeat_count < group_line_threshold:
                for _ in range(repeat_count):
                    dump = fmt.format(addr, d1, width, d2, width, dascii, subinfo)
                    if state == "Used":
                        self.out.append(Color.colorify(dump, chunk_used_color))
                    else:
                        self.out.append(Color.colorify(dump, chunk_freed_color))
                    addr += current_arch.ptrsize * 2
                    if subinfo:
                        subinfo = ""
            else:
                dump = fmt.format(addr, d1, width, d2, width, dascii, subinfo)
                dump += "* {:#d} lines, {:#x} bytes".format(repeat_count - 1, (repeat_count - 1) * current_arch.ptrsize * 2)
                if state == "Used":
                    self.out.append(Color.colorify(dump, chunk_used_color))
                else:
                    self.out.append(Color.colorify(dump, chunk_freed_color))
                addr += current_arch.ptrsize * 2 * repeat_count
                if subinfo:
                    subinfo = ""
            if done:
                break

        # print
        dump = dump.rstrip()
        return

    def dump_meta(self, ctx):
        self.out.append("Legend for `Unused chunks list`: A:Avail F:Freed U:Used")
        self.out.append("  1. Search most right 'A' and return it")
        self.out.append("  2. Search most right 'F' and return it")
        self.out.append("  3. If nothing is found, create new meta")

        # iterate __malloc_context.active
        for idx in range(48):
            if self.active_idx is not None and idx != self.active_idx:
                continue
            current = ctx.active[idx]
            if current == 0:
                continue

            self.out.append(titlify("active[{:2d}] (chunk_size={:#x})".format(idx, self.class_to_size(idx))))
            management_color = Config.get_gef_setting("theme.heap_management_address")

            # iterate list of meta
            seen = []
            while current not in seen:
                meta = self.read_meta(current)
                self.out.append("meta @ {:s}".format(Color.colorify_hex(meta.addr, management_color)))
                text = "  "
                colored_prev = Color.colorify_hex(meta.prev, management_color)
                colored_next = Color.colorify_hex(meta.next, management_color)
                text += "prev:{:s} next:{:s} ".format(colored_prev, colored_next)
                colored_mem = Color.colorify_hex(meta.mem, management_color)
                text += "meta:{:s} ".format(colored_mem)
                text += "avail_mask:{:#x} freed_mask:{:#x} ".format(meta.avail_mask, meta.freed_mask)
                text += "last_idx:{:#x} freeable:{:#x} ".format(meta.last_idx, meta.freeable)
                text += "sizeclass:{:#x} maplen:{:#x}".format(meta.sizeclass, meta.maplen)
                self.out.append(text)

                state = self.make_state(meta)
                self.out.append("  Unused chunks list: {}".format(repr(state)))

                # dump chunks
                if state != "F" or self.verbose:
                    dic = {"A": "Avail", "F": "Freed", "U": "Used"}
                    for i in range(meta.last_idx + 1):
                        offset = self.class_to_size(idx) * i
                        group = self.read_group(meta, offset)
                        self.dump_chunk(group, dic[state[-i - 1]])
                    self.out.append("")

                seen.append(current)
                current = meta.next
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        self.verbose = args.verbose
        self.active_idx = args.idx
        self.out = []

        ctx = self.read_ctx()
        if ctx is None:
            return
        if args.command == "ctx":
            self.dump_ctx(ctx)
        elif args.command == "unused":
            self.dump_meta(ctx)

        self.print_output(args)
        return


class uClibcNgHeap:
    class uClibcChunk:
        """uClibc chunk class."""
        def __init__(self, addr, from_base=False):
            self.ptrsize = current_arch.ptrsize
            if from_base:
                self.chunk_base_address = addr
                self.address = addr + 2 * self.ptrsize
            else:
                self.chunk_base_address = AddressUtil.align_address(addr - 2 * self.ptrsize)
                self.address = addr

            self.size_addr = AddressUtil.align_address(self.address - self.ptrsize)
            return

        def get_chunk_size(self):
            return read_int_from_memory(self.size_addr) & (~0x03)

        @property
        def size(self):
            return self.get_chunk_size()

        # if freed functions
        def get_fwd_ptr(self, sll):
            try:
                # Not a single-linked-list (sll) or no Safe-Linking support yet
                if not sll:
                    return read_int_from_memory(self.address)
                # Unmask ("reveal") the Safe-Linking pointer
                else:
                    return read_int_from_memory(self.address) ^ (self.address >> 12)
            except gdb.MemoryError:
                return None

        @property
        def fwd(self):
            return self.get_fwd_ptr(False)

        fd = fwd # for compat

        def get_bkw_ptr(self):
            return read_int_from_memory(self.address + self.ptrsize)

        @property
        def bck(self):
            return self.get_bkw_ptr()

        bk = bck # for compat
        # endif freed functions

        def has_p_bit(self):
            return read_int_from_memory(self.size_addr) & 0x01

        def has_m_bit(self):
            return read_int_from_memory(self.size_addr) & 0x02

        def flags_as_string(self):
            flags = []
            if self.has_p_bit():
                flags.append(Color.colorify("PREV_INUSE", Config.get_gef_setting("theme.heap_chunk_flag_prev_inuse")))
            if self.has_m_bit():
                flags.append(Color.colorify("IS_MMAPPED", Config.get_gef_setting("theme.heap_chunk_flag_is_mmapped")))
            return "|".join(flags)

        def to_str(self, is_fastbin=False):
            chunk_c = Color.colorify("Chunk", Config.get_gef_setting("theme.heap_chunk_label"))
            size_c = Color.colorify_hex(self.get_chunk_size(), Config.get_gef_setting("theme.heap_chunk_size"))
            base_c = Color.colorify_hex(self.chunk_base_address, Config.get_gef_setting("theme.heap_chunk_address_freed"))
            addr_c = Color.colorify_hex(self.address, Config.get_gef_setting("theme.heap_chunk_address_freed"))
            flags = self.flags_as_string()

            if is_fastbin:
                decoded_fd = ProcessMap.lookup_address(self.get_fwd_ptr(sll=True))
                fd = self.get_fwd_ptr(sll=False)
                fmt = "{:s}(base={:s}, addr={:s}, size={:s}, flags={:s}, fd={:#x}(={!s})"
                msg = fmt.format(chunk_c, base_c, addr_c, size_c, flags, fd, decoded_fd)
            else:
                fd = ProcessMap.lookup_address(self.fd)
                bk = ProcessMap.lookup_address(self.bk)
                fmt = "{:s}(base={:s}, addr={:s}, size={:s}, flags={:s}, fd={!s}, bk={!s})"
                msg = fmt.format(chunk_c, base_c, addr_c, size_c, flags, fd, bk)
            return msg


@register_command
class UclibcNgHeapDumpCommand(GenericCommand):
    """uclibc-ng v1.0.42 (libc/stdlib/malloc-standard) heap reusable chunks viewer (only x64/x86)."""
    _cmdline_ = "uclibc-ng-heap-dump"
    _category_ = "06-b. Heap - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--malloc_state", type=AddressUtil.parse_address,
                        help="use specific address for malloc_context.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="also dump an empty active index.")
    _syntax_ = parser.format_help()

    _note_ = "The main structural differences between uclibc-ng (malloc-standard) and glibc are:\n"
    _note_ += "- No tcache. There are fastbins, unsorted bin, small bins and larege bins.\n"
    _note_ += "- No thread arena. So the chunk has no NON_MAIN_ARENA flag."

    fast_size_table = [
        # 64bit  32bit
        ["none", 0x10],
        ["none", 0x18],
        [0x20,   0x20],
        ["none", 0x28],
        [0x30,   0x30],
        ["none", 0x38],
        [0x40,   0x40],
        ["none", 0x48],
        [0x50,   "none"],
        ["none", "none"],
        ["none", None],
    ]

    size_table = [
        # 64bit                32bit
        ["none",               "none"],
        ["any",                "any"],
        ["none",               (0x10, 0x18)],
        ["none",               (0x18, 0x20)],
        [(0x20, 0x30),         (0x20, 0x28)],
        ["none",               (0x28, 0x30)],
        [(0x30, 0x40),         (0x30, 0x38)],
        ["none",               (0x38, 0x40)],
        [(0x40, 0x50),         (0x40, 0x48)],
        ["none",               (0x48, 0x50)],
        [(0x50, 0x60),         (0x50, 0x58)],
        ["none",               (0x58, 0x60)],
        [(0x60, 0x70),         (0x60, 0x68)],
        ["none",               (0x68, 0x70)],
        [(0x70, 0x80),         (0x70, 0x78)],
        ["none",               (0x78, 0x80)],
        [(0x80, 0x90),         (0x80, 0x88)],
        ["none",               (0x88, 0x90)],
        [(0x90, 0xa0),         (0x90, 0x98)],
        ["none",               (0x98, 0xa0)],
        [(0xa0, 0xb0),         (0xa0, 0xa8)],
        ["none",               (0xa8, 0xb0)],
        [(0xb0, 0xc0),         (0xb0, 0xb8)],
        ["none",               (0xb8, 0xc0)],
        [(0xc0, 0xd0),         (0xc0, 0xc8)],
        ["none",               (0xc8, 0xd0)],
        [(0xd0, 0xe0),         (0xd0, 0xd8)],
        ["none",               (0xd8, 0xe0)],
        [(0xe0, 0xf0),         (0xe0, 0xe8)],
        ["none",               (0xe8, 0xf0)],
        [(0xf0, 0x100),        (0xf0, 0xf8)],
        ["none",               (0xf8, 0x100)],
        [(0x100, 0x140),       (0x100, 0x140)],
        [(0x140, 0x180),       (0x140, 0x180)],
        [(0x180, 0x1c0),       (0x180, 0x1c0)],
        [(0x1c0, 0x200),       (0x1c0, 0x200)],
        [(0x200, 0x280),       (0x200, 0x280)],
        [(0x280, 0x300),       (0x280, 0x300)],
        [(0x300, 0x380),       (0x300, 0x380)],
        [(0x380, 0x400),       (0x380, 0x400)],
        [(0x400, 0x500),       (0x400, 0x500)],
        [(0x500, 0x600),       (0x500, 0x600)],
        [(0x600, 0x700),       (0x600, 0x700)],
        [(0x700, 0x800),       (0x700, 0x800)],
        [(0x800, 0xa00),       (0x800, 0xa00)],
        [(0xa00, 0xc00),       (0xa00, 0xc00)],
        [(0xc00, 0xe00),       (0xc00, 0xe00)],
        [(0xe00, 0x1000),      (0xe00, 0x1000)],
        [(0x1000, 0x1400),     (0x1000, 0x1400)],
        [(0x1400, 0x1800),     (0x1400, 0x1800)],
        [(0x1800, 0x1c00),     (0x1800, 0x1c00)],
        [(0x1c00, 0x2000),     (0x1c00, 0x2000)],
        [(0x2000, 0x2800),     (0x2000, 0x2800)],
        [(0x2800, 0x3000),     (0x2800, 0x3000)],
        [(0x3000, 0x3800),     (0x3000, 0x3800)],
        [(0x3800, 0x4000),     (0x3800, 0x4000)],
        [(0x4000, 0x5000),     (0x4000, 0x5000)],
        [(0x5000, 0x6000),     (0x5000, 0x6000)],
        [(0x6000, 0x7000),     (0x6000, 0x7000)],
        [(0x7000, 0x8000),     (0x7000, 0x8000)],
        [(0x8000, 0xa000),     (0x8000, 0xa000)],
        [(0xa000, 0xc000),     (0xa000, 0xc000)],
        [(0xc000, 0xe000),     (0xc000, 0xe000)],
        [(0xe000, 0x10000),    (0xe000, 0x10000)],
        [(0x10000, 0x14000),   (0x10000, 0x14000)],
        [(0x14000, 0x18000),   (0x14000, 0x18000)],
        [(0x18000, 0x1c000),   (0x18000, 0x1c000)],
        [(0x1c000, 0x20000),   (0x1c000, 0x20000)],
        [(0x20000, 0x28000),   (0x20000, 0x28000)],
        [(0x28000, 0x30000),   (0x28000, 0x30000)],
        [(0x30000, 0x38000),   (0x30000, 0x38000)],
        [(0x38000, 0x40000),   (0x38000, 0x40000)],
        [(0x40000, 0x50000),   (0x40000, 0x50000)],
        [(0x50000, 0x60000),   (0x50000, 0x60000)],
        [(0x60000, 0x70000),   (0x60000, 0x70000)],
        [(0x70000, 0x80000),   (0x70000, 0x80000)],
        [(0x80000, 0xa0000),   (0x80000, 0xa0000)],
        [(0xa0000, 0xc0000),   (0xa0000, 0xc0000)],
        [(0xc0000, 0xe0000),   (0xc0000, 0xe0000)],
        [(0xe0000, 0x100000),  (0xe0000, 0x100000)],
        [(0x100000, 0x140000), (0x100000, 0x140000)],
        [(0x140000, 0x180000), (0x140000, 0x180000)],
        [(0x180000, 0x1c0000), (0x180000, 0x1c0000)],
        [(0x1c0000, 0x200000), (0x1c0000, 0x200000)],
        [(0x200000, 0x280000), (0x200000, 0x280000)],
        [(0x280000, 0x300000), (0x280000, 0x300000)],
        [(0x300000, 0x380000), (0x300000, 0x380000)],
        [(0x380000, 0x400000), (0x380000, 0x400000)],
        [(0x400000, 0x500000), (0x400000, 0x500000)],
        [(0x500000, 0x600000), (0x500000, 0x600000)],
        [(0x600000, 0x700000), (0x600000, 0x700000)],
        [(0x700000, 0x800000), (0x700000, 0x800000)],
        [(0x800000, 0xa00000), (0x800000, 0xa00000)],
        [(0xa00000, 0xc00000), (0xa00000, 0xc00000)],
        [(0xc00000, 0xe00000), (0xc00000, 0xe00000)],
        [(0xe00000, 0x0),      (0xe00000, 0x0)],
    ]

    def verbose_print(self, msg):
        if self.verbose:
            self.out.append(msg)
        return

    def get_malloc_state(self):
        # fast path
        try:
            return AddressUtil.parse_address("&__malloc_state")
        except gdb.error:
            pass

        # slow path
        # Do not use AddressUtil.parse_address("malloc").
        # For libc without symbols, the malloc@plt of the main binary will be resolved.
        # You can definitely get the address of malloc by finding the libc path and looking for the GOT of libc itself.
        libc = ProcessMap.process_lookup_path("libuClibc-")
        if libc is None:
            return None
        ret = gdb.execute("got --no-pager --quiet --file '{:s}' <malloc>".format(libc.path), to_string=True)
        if not ret:
            return None
        elem = Color.remove_color(ret).splitlines()[0].split()
        if elem[-1].endswith(">"):
            malloc = int(elem[-2], 16)
        else:
            malloc = int(elem[-1], 16)

        # heuristic search from assembly
        lines = gdb.execute("x/40i {:#x}".format(malloc), to_string=True)
        if is_x86_64():
            for line in lines.splitlines():
                m = re.search(r"\[rip\+0x\w+\].*#\s*(0x\w+)", line)
                if m:
                    malloc_state = int(m.group(1), 16)
                    if is_valid_addr(malloc_state):
                        max_fast = read_int_from_memory(malloc_state)
                        if max_fast != 0 and (max_fast & ~0x3) <= 0xb0:
                            return malloc_state
        elif is_x86_32():
            base = None
            regname = None
            for line in lines.splitlines():
                if base is None:
                    m = re.search(r"^\s*(0x\w+).+:\s+add\s+(\S+),\s*(0x\w+)", line)
                    if m:
                        base = int(m.group(1), 16) + int(m.group(3), 16)
                        regname = m.group(2)
                        continue
                else:
                    m = re.search(r"DWORD PTR \[(\S+)\+(0x\S+)\]", line)
                    if m and m.group(1) == regname:
                        malloc_state = base + int(m.group(2), 16)
                        if is_valid_addr(malloc_state):
                            max_fast = read_int_from_memory(malloc_state)
                            if max_fast != 0 and (max_fast & ~0x3) <= 0xb0:
                                return malloc_state

        # TODO
        # - Other architecture
        # - static build + stripped
        return None

    def read_malloc_state(self, specified_malloc_state_ptr):
        """
        struct malloc_state {
          /* The maximum chunk size to be eligible for fastbin */
          size_t  max_fast;   /* low 2 bits used as flags */

          /* Fastbins */
          mfastbinptr      fastbins[NFASTBINS];

          /* Base of the topmost chunk -- not otherwise kept in a bin */
          mchunkptr        top;

          /* The remainder from the most recent split of a small request */
          mchunkptr        last_remainder;

          /* Normal bins packed as described above */
          mchunkptr        bins[NBINS * 2];

          /* Bitmap of bins. Trailing zero map handles cases of largest binned size */
          unsigned int     binmap[BINMAPSIZE+1];

          /* Tunable parameters */
          unsigned long     trim_threshold;
          size_t  top_pad;
          size_t  mmap_threshold;

          /* Memory map support */
          int              n_mmaps;
          int              n_mmaps_max;
          int              max_n_mmaps;

          /* Cache malloc_getpagesize */
          unsigned int     pagesize;

          /* Track properties of MORECORE */
          unsigned int     morecore_properties;

          /* Statistics */
          size_t  mmapped_mem;
          size_t  sbrked_mem;
          size_t  max_sbrked_mem;
          size_t  max_mmapped_mem;
          size_t  max_total_mem;
        };
        """

        _malloc_state = {}
        if specified_malloc_state_ptr is None:
            _malloc_state["address"] = current = self.get_malloc_state()
            if current is None:
                return None
        else:
            _malloc_state["address"] = current = specified_malloc_state_ptr

        _malloc_state["max_fast"] = max_fast = read_int_from_memory(current)
        current += current_arch.ptrsize

        _malloc_state["max_fast_flags"] = []
        if max_fast & 1:
            _malloc_state["max_fast_flags"] += ["ANYCHUNKS_BIT"]
        if max_fast & 2:
            _malloc_state["max_fast_flags"] += ["FASTCHUNKS_BIT"]

        if is_64bit():
            self.NFASTBINS = 11
        else:
            self.NFASTBINS = 10
        _malloc_state["fastbins"] = []
        for i in range(self.NFASTBINS):
            n = read_int_from_memory(current)
            size = self.fast_size_table[i][is_32bit()]
            _malloc_state["fastbins"].append((current, n, size))
            current += current_arch.ptrsize

        _malloc_state["top"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        _malloc_state["last_remainder"] = read_int_from_memory(current)
        current += current_arch.ptrsize

        self.NBINS = 96
        self.NSMALLBINS = 32
        self.NLARGEBINS = self.NBINS - self.NSMALLBINS

        _malloc_state["smallbins"] = []
        for i in range(self.NSMALLBINS):
            n = read_int_from_memory(current)
            p = read_int_from_memory(current + current_arch.ptrsize)
            size = self.size_table[i][is_32bit()]
            _malloc_state["smallbins"].append((current, n, p, size))
            current += current_arch.ptrsize * 2

        _malloc_state["largebins"] = []
        for i in range(self.NLARGEBINS):
            n = read_int_from_memory(current)
            p = read_int_from_memory(current + current_arch.ptrsize)
            size = self.size_table[i + self.NSMALLBINS][is_32bit()]
            _malloc_state["largebins"].append((current, n, p, size))
            current += current_arch.ptrsize * 2

        self.BINMAPSIZE = 3
        _malloc_state["binmap"] = []
        for _ in range(self.BINMAPSIZE + 1):
            x = u32(read_memory(current, 4))
            _malloc_state["binmap"].append(x)
            current += 4

        _malloc_state["trim_threshold"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        _malloc_state["top_pad"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        _malloc_state["mmap_threshold"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        _malloc_state["n_mmaps"] = u32(read_memory(current, 4))
        current += 4
        _malloc_state["n_mmaps_max"] = u32(read_memory(current, 4))
        current += 4
        _malloc_state["max_n_mmaps"] = u32(read_memory(current, 4))
        current += 4
        _malloc_state["pagesize"] = u32(read_memory(current, 4))
        current += 4
        _malloc_state["morecore_properties"] = morecore_properties = u32(read_memory(current, 4))
        current += 4
        _malloc_state["morecore_properties_flags"] = []
        if morecore_properties & 1:
            _malloc_state["morecore_properties_flags"] += ["MORECORE_CONTIGUOUS_BIT"]
        if is_64bit():
            current += 4 # pad
        _malloc_state["mmaped_mem"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        _malloc_state["sbrked_mem"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        _malloc_state["max_sbrked_mem"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        _malloc_state["max_mmaped_mem"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        _malloc_state["max_total_mem"] = read_int_from_memory(current)
        current += current_arch.ptrsize

        try:
            top_sz = read_int_from_memory(_malloc_state["top"] + current_arch.ptrsize) & ~0b11
            heap_end = _malloc_state["top"] + top_sz
            _malloc_state["heap_base"] = heap_end - _malloc_state["sbrked_mem"]
        except gdb.MemoryError:
            _malloc_state["heap_base"] = 0

        MallocState = collections.namedtuple("MallocState", _malloc_state.keys())
        return MallocState(*_malloc_state.values())

    def dump_malloc_state(self, malloc_state):
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")

        self.verbose_print("malloc_state: {!s}".format(ProcessMap.lookup_address(malloc_state.address)))
        max_fast_flags = "|".join(malloc_state.max_fast_flags)
        self.verbose_print("max_fast:            {:#x} ({:s})".format(malloc_state.max_fast, max_fast_flags))

        self.out.append(titlify("Fast Bins"))
        for i in range(self.NFASTBINS):
            addr, n, size = malloc_state.fastbins[i]
            if n != 0 or self.verbose:
                if isinstance(size, int):
                    colored_size = Color.colorify("{:#4x}".format(size), chunk_size_color)
                else:
                    colored_size = Color.colorify(size, chunk_size_color)
                self.out.append("fastbins[idx={:d}, size={:s}, @{!s}]: fd={!s}".format(
                    i, colored_size,
                    ProcessMap.lookup_address(addr),
                    ProcessMap.lookup_address(n),
                ))

            if n != 0:
                seen = []
                while is_valid_addr(n) and n not in seen:
                    seen.append(n)
                    chunk = uClibcNgHeap.uClibcChunk(n, from_base=True)
                    self.out.append(" -> {}".format(chunk.to_str(is_fastbin=True)))
                    n = chunk.get_fwd_ptr(True)

        self.verbose_print("top:                 {!s}".format(ProcessMap.lookup_address(malloc_state.top)))
        self.verbose_print("last_remainder:      {!s}".format(ProcessMap.lookup_address(malloc_state.last_remainder)))

        self.out.append(titlify("Unsorted Bin / Small Bins"))
        for i in range(len(malloc_state.smallbins)):
            addr, n, p, size = malloc_state.smallbins[i]
            if (n and addr - current_arch.ptrsize * 2 != n) or self.verbose:
                if isinstance(size, tuple):
                    colored_size = Color.colorify("{:#x}-{:#x}".format(*size), chunk_size_color)
                else:
                    colored_size = Color.colorify(size, chunk_size_color)
                self.out.append("{:s}[idx={:d}, size={:s}, @{!s}]: fd={!s}, bk={!s}".format(
                    ["small_bins", "unsorted_bin"][i == 1],
                    i, colored_size,
                    ProcessMap.lookup_address(addr),
                    ProcessMap.lookup_address(n),
                    ProcessMap.lookup_address(p),
                ))

            if n and addr - current_arch.ptrsize * 2 != n:
                seen = [addr - current_arch.ptrsize * 2]
                while is_valid_addr(n) and n not in seen:
                    seen.append(n)
                    chunk = uClibcNgHeap.uClibcChunk(n, from_base=True)
                    self.out.append(" -> {}".format(chunk.to_str()))
                    n = chunk.fwd

        self.out.append(titlify("Large Bins"))
        for i in range(len(malloc_state.largebins)):
            addr, n, p, size = malloc_state.largebins[i]
            if addr - current_arch.ptrsize * 2 != n or self.verbose:
                if isinstance(size, tuple):
                    colored_size = Color.colorify("{:#x}-{:#x}".format(*size), chunk_size_color)
                else:
                    colored_size = Color.colorify(size, chunk_size_color)
                self.out.append("large_bins[idx={:d}, size={:s}, @{!s}]: fd={!s}, bk={!s}".format(
                    self.NSMALLBINS + i, colored_size,
                    ProcessMap.lookup_address(addr),
                    ProcessMap.lookup_address(n),
                    ProcessMap.lookup_address(p),
                ))

            if addr - current_arch.ptrsize * 2 != n:
                seen = [addr - current_arch.ptrsize * 2]
                while is_valid_addr(n) and n not in seen:
                    seen.append(n)
                    chunk = uClibcNgHeap.uClibcChunk(n, from_base=True)
                    self.out.append(" -> {}".format(chunk.to_str()))
                    n = chunk.fwd

        for i in range(self.BINMAPSIZE + 1):
            self.verbose_print("binmap[{:d}]:           {:#x}".format(i, malloc_state.binmap[i]))
        self.verbose_print("trim_threshold:      {:#x}".format(malloc_state.trim_threshold))
        self.verbose_print("top_pad:             {:#x}".format(malloc_state.top_pad))
        self.verbose_print("mmap_threshold:      {:#x}".format(malloc_state.mmap_threshold))
        self.verbose_print("n_mmaps:             {:#x}".format(malloc_state.n_mmaps))
        self.verbose_print("n_mmaps_max:         {:#x}".format(malloc_state.n_mmaps_max))
        self.verbose_print("max_n_mmaps:         {:#x}".format(malloc_state.max_n_mmaps))
        self.verbose_print("pagesize:            {:#x}".format(malloc_state.pagesize))
        mp_flags = "|".join(malloc_state.morecore_properties_flags)
        self.verbose_print("morecore_properties: {:#x} ({:s})".format(malloc_state.morecore_properties, mp_flags))
        self.verbose_print("mmaped_mem:          {:#x}".format(malloc_state.mmaped_mem))
        self.verbose_print("sbrked_mem:          {:#x}".format(malloc_state.sbrked_mem))
        self.verbose_print("max_sbrked_mem:      {:#x}".format(malloc_state.max_sbrked_mem))
        self.verbose_print("max_mmaped_mem:      {:#x}".format(malloc_state.max_mmaped_mem))
        self.verbose_print("max_total_mem:       {:#x}".format(malloc_state.max_total_mem))
        self.verbose_print("(heap_base):         {:#x}".format(malloc_state.heap_base))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        self.verbose = args.verbose
        self.out = []

        malloc_state = self.read_malloc_state(args.malloc_state)
        if malloc_state is None:
            err("malloc_state is not found")
            return
        self.dump_malloc_state(malloc_state)
        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class UclibcNgVisualHeapCommand(UclibcNgHeapDumpCommand):
    """Visualize chunks on a heap for uClibc-ng."""
    _cmdline_ = "uclibc-ng-visual-heap"
    _category_ = "06-b. Heap - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="LOCATION", nargs="?", type=AddressUtil.parse_address,
                        help="the address interpreted as the beginning of a contiguous chunk. (default: [heap] of vmmap)")
    parser.add_argument("--malloc_state", type=AddressUtil.parse_address,
                        help="use specific address for malloc_context.")
    parser.add_argument("-c", dest="max_count", type=AddressUtil.parse_address,
                        help="Maximum count to parse. It is used when there is a very large amount of chunks.")
    parser.add_argument("-f", "--full", action="store_true",
                        help="display the same line without omitting.")
    parser.add_argument("-d", "--dark-color", action="store_true",
                        help="use the dark color if chunk is allocated.")
    parser.add_argument("-s", "--safe-linking-decode", action="store_true",
                        help="decode safe-linking encoded pointer if tcache or fastbins.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    color = [
        Color.redify,
        Color.greenify,
        Color.blueify,
        Color.yellowify
    ]
    dark_color = [
        lambda x: Color.colorify(x, "bright_black"),
        lambda x: Color.colorify(x, "graphite"),
    ]

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def init_bins_info(self, malloc_state):
        self.bins_info = {
            "fastbins": {},
            "small_bins": {},
            "large_bins": {},
        }
        # fastbins
        for i in range(self.NFASTBINS):
            addr, n, size = malloc_state.fastbins[i]
            seen = []
            while n and n not in seen:
                seen.append(n)
                try:
                    chunk = uClibcNgHeap.uClibcChunk(n, from_base=True)
                    n = chunk.get_fwd_ptr(True)
                except gdb.MemoryError:
                    break
            self.bins_info["fastbins"][i] = seen
        # smallbins / unsortedbin
        for i in range(len(malloc_state.smallbins)):
            addr, n, p, size = malloc_state.smallbins[i]
            seen = []
            while n and addr - current_arch.ptrsize * 2 != n and n not in seen:
                seen.append(n)
                try:
                    chunk = uClibcNgHeap.uClibcChunk(n, from_base=True)
                    n = chunk.fwd
                except gdb.MemoryError:
                    break
            self.bins_info["small_bins"][i] = seen
        # largebins
        for i in range(len(malloc_state.largebins)):
            addr, n, p, size = malloc_state.largebins[i]
            seen = []
            while n and addr - current_arch.ptrsize * 2 != n and n not in seen:
                seen.append(n)
                try:
                    chunk = uClibcNgHeap.uClibcChunk(n, from_base=True)
                    n = chunk.fwd
                except gdb.MemoryError:
                    break
            self.bins_info["large_bins"][i] = seen

        # make table
        self.bins_dict_for_address = {}
        for fastbin_idx, fastbin_list in self.bins_info["fastbins"].items():
            for address in set(fastbin_list):
                pos = ",".join([str(i + 1) for i, x in enumerate(fastbin_list) if x == address])
                sz = self.fast_size_table[fastbin_idx][is_32bit()]
                m = "fastbins[idx={:d},sz={:#x}][{:s}/{:d}]".format(fastbin_idx, sz, pos, len(fastbin_list))
                self.bins_dict_for_address[address] = self.bins_dict_for_address.get(address, []) + [m]
        for smallbin_idx, smallbin_list in self.bins_info["small_bins"].items():
            for address in set(smallbin_list):
                pos = ",".join([str(i + 1) for i, x in enumerate(smallbin_list) if x == address])
                if smallbin_idx == 0:
                    m = "unsortedbins[{:s}/{:d}]".format(pos, len(smallbin_list))
                else:
                    size = self.size_table[smallbin_idx][is_32bit()]
                    if isinstance(size, tuple):
                        sz = "{:#x}-{:#x}".format(size[0], size[1])
                    else:
                        sz = size
                    m = "smallbins[idx={:d},sz={:s}][{:s}/{:d}]".format(smallbin_idx, sz, pos, len(smallbin_list))
                self.bins_dict_for_address[address] = self.bins_dict_for_address.get(address, []) + [m]
        for largebin_idx, largebin_list in self.bins_info["large_bins"].items():
            for address in set(largebin_list):
                pos = ",".join([str(i + 1) for i, x in enumerate(largebin_list) if x == address])
                size = self.size_table[self.NSMALLBINS + largebin_idx][is_32bit()]
                if isinstance(size, tuple):
                    sz = "{:#x}-{:#x}".format(size[0], size[1])
                else:
                    sz = size
                m = "largebins[idx={:d},sz={:s}][{:s}/{:d}]".format(self.NSMALLBINS + largebin_idx, sz, pos, len(largebin_list))
                self.bins_dict_for_address[address] = self.bins_dict_for_address.get(address, []) + [m]
        return

    def make_bins_info(self, malloc_state, address):
        info = self.bins_dict_for_address.get(address, [])
        if address == malloc_state.top:
            info.append("top")
        return info

    def generate_visual_chunk(self, malloc_state, chunk, idx):
        unpack = u32 if current_arch.ptrsize == 4 else u64
        data = slicer(chunk.data, current_arch.ptrsize * 2)
        group_line_threshold = 8

        addr = chunk.chunk_base_address
        width = current_arch.ptrsize * 2 + 2
        exceed_top = False
        has_subinfo = False

        out_tmp = []
        # Group rows to display rows with the same value together.
        prev_sub_info = ""
        for blk, blks in itertools.groupby(data):
            repeat_count = len(list(blks))
            d1, d2 = unpack(blk[:current_arch.ptrsize]), unpack(blk[current_arch.ptrsize:])
            dascii = "".join([chr(x) if 0x20 <= x < 0x7f else "." for x in blk])

            fmt = "{:#x}|{:+#08x}|{:+#08x}: {:#0{:d}x} {:#0{:d}x} | {:s} | {:s}"
            if self.full or repeat_count < group_line_threshold:
                # non-collapsed line
                for _ in range(repeat_count):
                    sub_info = self.make_bins_info(malloc_state, addr)
                    if sub_info:
                        sub_info = "{:s} {:s}".format(LEFT_ARROW, ", ".join(sub_info))
                        has_subinfo = True
                    else:
                        sub_info = ""

                    if self.safe_linking_decode:
                        if chunk.address == addr and "fastbins" in prev_sub_info:
                            d1 = chunk.get_fwd_ptr(True)

                    offset1 = addr - chunk.chunk_base_address
                    offset2 = addr - malloc_state.heap_base
                    out_tmp.append(fmt.format(addr, offset1, offset2, d1, width, d2, width, dascii, sub_info))
                    addr += current_arch.ptrsize * 2
                    prev_sub_info = sub_info

                    if addr > malloc_state.top + current_arch.ptrsize * 4:
                        exceed_top = True
                        break
            else:
                # collapsed line
                sub_info = self.make_bins_info(malloc_state, addr)
                if sub_info:
                    sub_info = "{:s} {:s}".format(LEFT_ARROW, ", ".join(sub_info))
                    has_subinfo = True
                else:
                    sub_info = ""

                offset1 = addr - chunk.chunk_base_address
                offset2 = addr - malloc_state.heap_base
                out_tmp.append(fmt.format(addr, offset1, offset2, d1, width, d2, width, dascii, sub_info))
                addr += current_arch.ptrsize * 2 * repeat_count
                out_tmp.append("* {:#d} lines, {:#x} bytes".format(repeat_count - 1, (repeat_count - 1) * current_arch.ptrsize * 2))

            prev_sub_info = sub_info

            if exceed_top:
                break

        # coloring
        if self.use_dark_color and not has_subinfo:
            color_func = self.dark_color[idx % len(self.dark_color)]
        else:
            color_func = self.color[idx % len(self.color)]
        self.out.append("\n".join(map(color_func, out_tmp)))

        # corrupted case
        if exceed_top:
            self.out.append(Color.boldify("..."))
        return

    def generate_visual_heap(self, malloc_state, dump_start, max_count):
        sect = ProcessMap.process_lookup_address(dump_start)
        if sect:
            end = sect.page_end
        else:
            # If qemu-user 8.1 or higher, the process_lookup_address to obtain the section list uses info proc mappings internally.
            # This is fast, but does not return an accurate list in some cases.
            # For example, sparc64 may not include the heap area.
            # So it detects the end of the page from malloc_state.top.
            end = malloc_state.top + uClibcNgHeap.uClibcChunk(malloc_state.top, from_base=True).size

        try:
            from tqdm import tqdm
        except ImportError:
            tqdm = None
        if tqdm:
            pbar = tqdm(total=end - dump_start, leave=False)

        addr = dump_start
        i = 0

        while addr < end:
            chunk = GlibcHeap.GlibcChunk(addr + current_arch.ptrsize * 2)
            # corrupt check
            if chunk.size == 0:
                msg = "{} Corrupted (chunk.size == 0)".format(Color.colorify("[!]", "bold red"))
                self.out.append(msg)
                chunk.data = read_memory(addr, malloc_state.top - addr + 0x10)
                self.generate_visual_chunk(malloc_state, chunk, i)
                break
            elif addr != malloc_state.top and addr + chunk.size > malloc_state.top:
                msg = "{} Corrupted (addr + chunk.size > malloc_state.top)".format(Color.colorify("[!]", "bold red"))
                self.out.append(msg)
                chunk.data = read_memory(addr, malloc_state.top - addr + 0x10)
                self.generate_visual_chunk(malloc_state, chunk, i)
                break
            elif addr + chunk.size > end:
                msg = "{} Corrupted (addr + chunk.size > sect.page_end)".format(Color.colorify("[!]", "bold red"))
                self.out.append(msg)
                chunk.data = read_memory(addr, malloc_state.top - addr + 0x10)
                self.generate_visual_chunk(malloc_state, chunk, i)
                break
            # maybe not corrupted
            try:
                chunk.data = read_memory(addr, chunk.size)
            except gdb.MemoryError:
                break
            self.generate_visual_chunk(malloc_state, chunk, i)
            addr += chunk.size
            i += 1

            if tqdm:
                pbar.update(chunk.size)

            if max_count and max_count <= i:
                break

        if tqdm:
            pbar.close()
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        self.full = args.full
        self.use_dark_color = args.dark_color
        self.safe_linking_decode = args.safe_linking_decode

        malloc_state = self.read_malloc_state(args.malloc_state)
        if malloc_state is None:
           err("malloc_state is not found")
           return

        if malloc_state.heap_base is None or not is_valid_addr(malloc_state.heap_base):
            err("Not found heap base")
            return

        self.init_bins_info(malloc_state)

        if args.location is None:
            dump_start = malloc_state.heap_base
        else:
            dump_start = args.location

        self.out = []
        Cache.reset_gef_caches(all=True)
        self.generate_visual_heap(malloc_state, dump_start, args.max_count)
        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class XStringCommand(GenericCommand):
    """Dump string like x/s command, but with hex-string style."""
    _cmdline_ = "xs"
    _category_ = "03-b. Memory - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("count", metavar="COUNT", nargs="?", help="repeat count for displaying.")
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address, help="dump target address.")
    parser.add_argument("-l", "--max-length", type=AddressUtil.parse_address,
                        help="maximum number of characters to display. 0 means unlimited.")
    parser.add_argument("-H", "--hex", action="store_true", help="show in hex style.")
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet mode.")
    _syntax_ = parser.format_help()

    def dump_string(self, address, count, max_length, tohex, quiet):
        for _ in range(count):
            if not is_valid_addr(address):
                err("Memory access error at {:#x}".format(address))
                break

            # read string
            current = address
            size = gef_getpagesize() - (address & gef_getpagesize_mask_low())
            s = b""
            while True:
                # check accessibility
                if not is_valid_addr(current):
                    break

                # read string
                s += read_memory(current, size)
                pos = s.find(b"\0")
                if pos != -1:
                    s = s[:pos]
                    break

                # not found 0x0, read more
                current += size
                size = gef_getpagesize()

            # cut off
            if max_length and len(s) >= max_length:
                cs = s[:max_length] + b"..."
            else:
                cs = s

            if quiet:
                if tohex:
                    gef_print("{:s}".format(cs.hex()))
                else:
                    gef_print("{:s}".format(repr(cs)))
            else:
                if tohex:
                    gef_print("{!s}: {:s} ({:#x} bytes)".format(ProcessMap.lookup_address(address), cs.hex(), len(s)))
                else:
                    gef_print("{!s}: {:s} ({:#x} bytes)".format(ProcessMap.lookup_address(address), repr(cs), len(s)))

            # go to next address
            if pos == -1:
                address += 1
            else:
                address += pos + 1
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.count is None:
            count = 1
        else:
            count = args.count
            if args.count.startswith("/"):
                count = count[1:]
            if args.count.endswith("s"):
                count = count[:-1]
            try:
                count = int(count)
            except ValueError:
                err("parse failed: {}".format(args.count))
                return

        if args.max_length is not None:
            max_length = args.max_length
        else:
            max_length = Config.get_gef_setting("context.nb_max_string_length")

        self.dump_string(args.address, count, max_length, args.hex, args.quiet)
        return


@register_command
class XColoredCommand(GenericCommand):
    """Dump address like x/x command, but with coloring at some intervals."""
    _cmdline_ = "xc"
    _category_ = "03-b. Memory - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("format", metavar="FMT", nargs="?", default="", help="dump format.")
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="dump address.")
    parser.add_argument("-i", "--interval", type=lambda x: int(x, 16),
                        help="the line of interval for coloring.")
    parser.add_argument("-c", "--color-num", type=lambda x: int(x, 16), default=4,
                        help="the number of colors used (1-5).")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet mode.")
    _syntax_ = parser.format_help()

    color = [
        Color.greenify,
        Color.redify,
        Color.blueify,
        Color.yellowify,
        Color.cyanify,
    ]

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.color_num < 1 or len(self.color) < args.color_num:
            err("Invalid --color-num")
            return

        try:
            ret = gdb.execute("x{:s} {:#x}".format(args.format, args.address), to_string=True)
            ret = ret.strip()
        except gdb.error as e:
            err(e)
            return

        out = []
        for i, line in enumerate(ret.splitlines()):
            if args.interval and args.interval > 0:
                color_func = self.color[:args.color_num][(i // args.interval) % args.color_num]
            else:
                color_func = self.color[:args.color_num][0]
            out.append(color_func(line))

        if len(out) > GefUtil.get_terminal_size()[0]:
            gef_print("\n".join(out), less=not args.no_pager)
        else:
            gef_print("\n".join(out), less=False)
        return


@register_command
class XphysAddrCommand(GenericCommand):
    """Dump physical memory taking into account ROM mapping."""
    _cmdline_ = "xp"
    _category_ = "08-a. Qemu-system Cooperation - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("format", metavar="/FMT", help="specified output format.")
    parser.add_argument("location", metavar="ADDRESS", type=AddressUtil.parse_address, help="dump target address.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} /16xg 0x11223344".format(_cmdline_)

    @staticmethod
    def print_fmt_i(target, data, count):
        kwargs = {}
        kwargs["code"] = data.hex()
        if is_x86_32():
            kwargs["arch"] = "X86"
            kwargs["mode"] = "32"
        elif is_x86_64():
            kwargs["arch"] = "X86"
            kwargs["mode"] = "64"
        elif is_arm32():
            kwargs["arch"] = "ARM"
            if target & 1:
                kwargs["mode"] = "THUMB"
            else:
                kwargs["mode"] = "ARM"
        elif is_arm64():
            kwargs["arch"] = "ARM64"
            kwargs["mode"] = "ARM"

        out = []
        try:
            for insn in Disasm.capstone_disassemble(target, count, **kwargs):
                text_insn = "{:12o}".format(insn)
                msg = "{} {}".format(" " * 5, text_insn)
                out.append(msg)
        except gdb.error:
            pass
        out = "\n".join(out)
        return out

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware", "kgdb"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    def do_invoke(self, args):
        # arg parse
        m = re.search(r"/(\d*)([xibhwg]*)", args.format)
        if not m:
            self.usage()
            return

        dump_type = "x"
        dump_unit = current_arch.ptrsize
        dump_count = 1
        if m.group(1):
            dump_count = int(m.group(1))
        for c in m.group(2):
            if c in ["x", "i"]:
                dump_type = c
            elif c in ["b", "h", "w", "g"]:
                dump_unit = {"b": 1, "h": 2, "w": 4, "g": 8}[c]
            else:
                err("Unsupported format: {}".format(c))
                return

        target = args.location
        if dump_type == "x":
            dump_size = dump_count * dump_unit
        elif dump_type == "i":
            if is_x86():
                # I don't know the length, but I'll read it 10 bytes at a time.
                dump_size = dump_count * 10
            else:
                if target & 1: # fix thumb2
                    if is_arm32():
                        target -= 1
                    else:
                        err("Unsupported odd address: {}".format(target))
                        return
                # ARM opcode is at most 4byte
                dump_size = dump_count * 4

        # read
        data = read_physmem(target, dump_size)
        if data is None:
            err("read memory error")
            return

        # print
        if dump_type == "x":
            out = hexdump(data, show_symbol=False, base=args.location, unit=dump_unit)
        elif dump_type == "i":
            out = XphysAddrCommand.print_fmt_i(args.location, data, dump_count)
        gef_print(out)
        return


@register_command
class XSecureMemAddrCommand(GenericCommand):
    """Dump secure memory via qemu-system memory map."""
    _cmdline_ = "xsm"
    _category_ = "08-g. Qemu-system Cooperation - TrustZone"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("--phys", action="store_true", help="treat ADDRESS as physical address.")
    group.add_argument("--off", action="store_true", help="treat ADDRESS as offset of secure memory top.")
    group.add_argument("--virt", action="store_true", help="treat ADDRESS as virtual address.")
    parser.add_argument("format", metavar="/FMT", help="specified output format.")
    parser.add_argument("location", metavar="ADDRESS", type=AddressUtil.parse_address, help="dump target address.")
    parser.add_argument("-v", "--verbose", action="store_true", help="verbose output.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} /16xw --phys 0xe11e3d0  # absolute (physical/non-ASLR) address of secure memory\n".format(_cmdline_)
    _example_ += "{:s} /16xw --off 0x11e3d0    # the offset from secure memory area\n".format(_cmdline_)
    _example_ += "{:s} /16xw --virt 0x783ae3d0 # secure memory ASLR is supported".format(_cmdline_)

    @staticmethod
    def v2p_secure(vaddr, verbose=False): # vaddr -> addr1 or None
        maps = PageMap.get_page_maps(FORCE_PREFIX_S=True, verbose=verbose)
        if maps is None:
            return None
        for vstart, vend, pstart, _pend in maps:
            if vstart <= vaddr < vend:
                offset = vaddr - vstart
                paddr = pstart + offset
                if verbose:
                    info("v2p: {:#x} -> {:#x}".format(vaddr, paddr))
                return paddr
        return None

    @staticmethod
    def p2v_secure(paddr, verbose=False): # paddr -> [addr1, addr2, ...] or []
        maps = PageMap.get_page_maps(FORCE_PREFIX_S=True, verbose=verbose)
        if maps is None:
            return []
        result = []
        for vstart, _vend, pstart, pend in maps:
            if pstart <= paddr < pend:
                offset = paddr - pstart
                vaddr = vstart + offset
                if verbose:
                    info("p2v: {:#x} -> {:#x}".format(paddr, vaddr))
                result.append(vaddr)
        return result

    @staticmethod
    def read_secure_memory(sm, offset, dump_size, verbose=False):
        qemu_system_pid = Pid.get_pid()
        if qemu_system_pid is None:
            err("Not found qemu-system pid")
            return None

        if dump_size > sm.size:
            dump_size = sm.size

        if verbose:
            info("target offset: {:#x}".format(offset))
            info("read address: {:#x}, size:{:#x}".format(sm.page_start + offset, dump_size))

        with open("/proc/{:d}/mem".format(qemu_system_pid), "rb") as fd:
            try:
                fd.seek(sm.page_start + offset, 0)
                data = fd.read(dump_size)
            except Exception:
                return None
        if verbose:
            info("read size result: {:#x}".format(len(data)))
        return data

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM32", "ARM64"))
    def do_invoke(self, args):
        # arg parse
        m = re.search(r"/(\d*)([xibhwg]*)", args.format)
        if not m:
            self.usage()
            return

        dump_type = "x"
        dump_unit = current_arch.ptrsize
        dump_count = 1
        if m.group(1):
            dump_count = int(m.group(1))
        for c in m.group(2):
            if c in ["x", "i"]:
                dump_type = c
            elif c in ["b", "h", "w", "g"]:
                dump_unit = {"b": 1, "h": 2, "w": 4, "g": 8}[c]
            else:
                err("Unsupported format: {}".format(c))
                return

        # initialize
        sm = QemuMonitor.get_secure_memory_map(args.verbose)
        if sm is None:
            err("Not found secure memory maps")
            return

        if args.phys:
            if sm.page_start <= args.location < sm.page_end:
                target_offset = args.location - sm.page_start
            else:
                err("Phys {:#x} is not default secure memory (unsupported)".format(args.location))
                return
        elif args.off:
            if 0 <= args.location < sm.size:
                target_offset = args.location
            else:
                err("Offset {:#x} is not default secure memory (unsupported)".format(args.location))
                return
        elif args.virt:
            target_phys = XSecureMemAddrCommand.v2p_secure(args.location, args.verbose)
            if target_phys is None:
                err("Not found physical address")
                return
            if sm.page_start <= target_phys < sm.page_end:
                target_offset = target_phys - sm.page_start
            else:
                err("Virt {:#x} is not default secure memory (unsupported)".format(args.location))
                return

        # fix for size, offset (when thumb2)
        if dump_type == "x":
            dump_size = dump_count * dump_unit
        elif dump_type == "i":
            if target_offset & 1: # fix thumb2
                if is_arm32():
                    target_offset -= 1
                else:
                    err("Unsupported odd address: {}".format(target_offset))
                    return
            # ARM opcode is at most 4byte
            dump_size = dump_count * 4

        # read
        data = self.read_secure_memory(sm, target_offset, dump_size, args.verbose)
        if data is None:
            err("read memory error")
            return

        # print
        if dump_type == "x":
            out = hexdump(data, show_symbol=False, base=args.location, unit=dump_unit)
        elif dump_type == "i":
            out = XphysAddrCommand.print_fmt_i(args.location, data, dump_count)
        gef_print(out)
        return


# The wsm command directly modifies /proc/<PID>/mem of qemu-system.
# However, even though the memory change was successful, it may not be reflected in the behavior of the code.
# I don't know the cause, but I'm guessing it's because qemu has an internal cache.
# Apparently setting a breakpoint ignores this cache, so setting a temporary breakpoint avoids this problem.
class TemporaryDummyBreakpoint(gdb.Breakpoint):
    """Create a breakpoint to avoid gdb cache problem"""
    def __init__(self):
        super().__init__("*{:#x}".format(0x0), type=gdb.BP_BREAKPOINT, internal=True, temporary=True)
        return

    def stop(self):
        EventHandler.__gef_check_disabled_bp__ = True
        self.enabled = False
        return False


@register_command
class WSecureMemAddrCommand(GenericCommand):
    """Write secure memory via qemu-system memory map."""
    _cmdline_ = "wsm"
    _category_ = "08-g. Qemu-system Cooperation - TrustZone"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("mode", choices=["byte", "short", "dword", "qword", "string", "hex"],
                        help="the mode that represents the value of the argument. You have to choose one or the other.")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("--phys", action="store_true", help="treat ADDRESS as physical address.")
    group.add_argument("--off", action="store_true", help="treat ADDRESS as offset of secure memory top.")
    group.add_argument("--virt", action="store_true", help="treat ADDRESS as virtual address.")
    parser.add_argument("value", metavar="VALUE", help="write value.")
    parser.add_argument("location", metavar="ADDRESS", type=AddressUtil.parse_address, help="write target address.")
    parser.add_argument("-v", "--verbose", action="store_true", help="verbose output.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} dword 0x41414141 --phys 0xe11e3d0            # absolute (physical/non-ASLR) address of secure memory\n".format(_cmdline_)
    _example_ += '{:s} string "\\\\x41\\\\x41\\\\x41\\\\x41" --off 0x11e3d0 # the offset of secure memory\n'.format(_cmdline_)
    _example_ += '{:s} hex "4141 4141" --off 0x11e3d0               # hex string is supported (invalid character is ignored)\n'.format(_cmdline_)
    _example_ += "{:s} byte 0x41 --virt 0x783ae3d0                  # secure memory ASLR is supported".format(_cmdline_)

    @staticmethod
    def write_secure_memory(sm, offset, data, verbose=False):
        qemu_system_pid = Pid.get_pid()
        if qemu_system_pid is None:
            return None

        write_size = len(data)
        if write_size > sm.size:
            write_size = sm.size
            data = data[:write_size]

        if verbose:
            info("target offset: {:#x}".format(offset))
            info("write address: {:#x}, size:{:#x}".format(sm.page_start + offset, write_size))

        with open("/proc/{:d}/mem".format(qemu_system_pid), "r+b") as fd:
            try:
                fd.seek(sm.page_start + offset, 0)
                ret = fd.write(data)
            except Exception:
                return None
        if verbose:
            info("written size result: {:#x}".format(ret))

        # avoid qemu-system caches
        TemporaryDummyBreakpoint()

        # By default, "context code" uses Disasm.gdb_disassemble.
        # However, due to gdb's internal cache, changes to secure memory may not be reflected in the disassembled results.
        # Therefore, if capstone is available, change it to disassemble by capstone.
        if Config.get_gef_setting("context.use_capstone") is False:
            Config.set_gef_setting("context.use_capstone", True)
        return ret

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM32", "ARM64"))
    def do_invoke(self, args):
        try:
            if args.mode == "byte":
                data = p8(int(args.value, 0))
            elif args.mode == "short":
                data = p16(int(args.value, 0))
            elif args.mode == "dword":
                data = p32(int(args.value, 0))
            elif args.mode == "qword":
                data = p64(int(args.value, 0))
            elif args.mode == "string":
                try:
                    data = codecs.escape_decode(args.value)[0]
                except binascii.Error:
                    err("Could not decode '\\xXX' encoded string")
                    return
            elif args.mode == "hex":
                data = ""
                for c in args.value.lower():
                    if c in "0123456789abcdef":
                        data += c
                data = bytes.fromhex(data)
        except Exception:
            self.usage()
            return

        # initialize
        sm = QemuMonitor.get_secure_memory_map(args.verbose)
        if sm is None:
            err("Not found secure memory maps")
            return

        if args.phys:
            if sm.page_start <= args.location < sm.page_end:
                target_offset = args.location - sm.page_start
            else:
                err("Phys {:#x} is not default secure memory (unsupported)".format(args.location))
                return
        elif args.off:
            if 0 <= args.location < sm.size:
                target_offset = args.location
            else:
                err("Offset {:#x} is not default secure memory (unsupported)".format(args.location))
                return
        elif args.virt:
            target_phys = XSecureMemAddrCommand.v2p_secure(args.location, args.verbose)
            if target_phys is None:
                err("Not found physical address")
                return
            if sm.page_start <= target_phys < sm.page_end:
                target_offset = target_phys - sm.page_start
            else:
                err("Virt {:#x} is not default secure memory (unsupported)".format(args.location))
                return

        # write
        ret = self.write_secure_memory(sm, target_offset, data, args.verbose)
        if ret is None:
            err("memory write error")
        return


@register_command
class BreakSecureMemAddrCommand(GenericCommand):
    """Set a breakpoint in virtual memory by specifying the physical memory of the secure world."""
    _cmdline_ = "bsm"
    _category_ = "08-g. Qemu-system Cooperation - TrustZone"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("location", metavar="PHYS_ADDRESS", type=AddressUtil.parse_address,
                        help="the target physical address to set a breakpoint.")
    parser.add_argument("-v", "--verbose", action="store_true", help="verbose output.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0xe1008d8".format(_cmdline_)

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM32", "ARM64"))
    def do_invoke(self, args):
        if args.verbose:
            info("phys address: {:#x}".format(args.location))
        virt_addrs = XSecureMemAddrCommand.p2v_secure(args.location, args.verbose)
        for virt_addr in virt_addrs:
            gdb.execute("break *{:#x}".format(virt_addr))
        return


class OpteeThreadEnterUserModeBreakpoint(gdb.Breakpoint):
    """Create a breakpoint to thread_enter_user_mode"""
    def __init__(self, vaddr, ta_offset):
        super().__init__("*{:#x}".format(vaddr), type=gdb.BP_BREAKPOINT, internal=True)
        self.count = 0
        self.ta_offset = ta_offset
        return

    @staticmethod
    def get_ta_loaded_address():
        if is_arm32():
            res = PageMap.get_page_maps_by_pagewalk("pagewalk -S --quiet --no-pager")
            res = sorted(set(res.splitlines()))
            res = list(filter(lambda line: "PL0/R-X" in line, res))
        elif is_arm64():
            res = PageMap.get_page_maps_by_pagewalk("pagewalk 1 --quiet --no-pager")
            res = sorted(set(res.splitlines()))
            res = list(filter(lambda line: "EL0/R-X" in line, res))
        maps = []
        for line in res:
            vrange, prange, *_ = line.split()
            vstart, vend = [int(x, 16) for x in vrange.split("-")]
            pstart, pend = [int(x, 16) for x in prange.split("-")]
            maps.append((vstart, vend, pstart, pend))
        if len(maps) == 2:
            return maps[1]
        else:
            return None

    def stop(self):
        if self.count != 1:
            self.count += 1
            return False

        ta_address = self.get_ta_loaded_address()
        if ta_address is None:
            err("TA address is not found")
            self.enabled = False
            return False

        ta_vstart, ta_vend, _, _ = ta_address
        info("TA address: {:#x}".format(ta_vstart))

        ta_vsize = ta_vend - ta_vstart
        if self.ta_offset >= ta_vsize:
            err("TA offset {:#x} is greater than the size of TA R-X area ({:#x})".format(self.ta_offset, ta_vsize))
            self.enabled = False
            return False

        gdb.execute("break *{:#x}".format(ta_vstart + self.ta_offset))
        self.enabled = False
        return False


@register_command
class OpteeBreakTaAddrCommand(GenericCommand):
    """Set a breakpoint to OPTEE-TA."""
    _cmdline_ = "optee-break-ta"
    _category_ = "08-g. Qemu-system Cooperation - TrustZone"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("thread_enter_user_mode", metavar="PHYS_ADDR_thread_enter_user_mode", type=AddressUtil.parse_address,
                        help="The physical address of `thread_enter_user_mode` in OPTEE-OS.")
    parser.add_argument("ta_offset", metavar="TA_OFFSET", type=AddressUtil.parse_address,
                        help="The breakpoint target offset of OPTEE-TA.")
    parser.add_argument("-v", "--verbose", action="store_true", help="verbose output.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0xe137c78 0x2784".format(_cmdline_)

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM32", "ARM64"))
    def do_invoke(self, args):
        if args.verbose:
            info("thread_enter_user_mode @ OPTEE-OS: {:#x}".format(args.thread_enter_user_mode))
            info("breakpoint target offset of TA: {:#x}".format(args.ta_offset))

        thread_enter_user_mode_virt = XSecureMemAddrCommand.p2v_secure(args.thread_enter_user_mode, args.verbose)

        for vaddr in thread_enter_user_mode_virt:
            OpteeThreadEnterUserModeBreakpoint(vaddr, args.ta_offset)
            info("Temporarily breakpoint at {:#x}".format(vaddr))
        return


@register_command
class OpteeBgetDumpCommand(GenericCommand):
    """Dump bget allocator of OPTEE-Trusted-App."""
    _cmdline_ = "optee-bget-dump"
    _category_ = "08-g. Qemu-system Cooperation - TrustZone"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-m", "--malloc_ctx", metavar="OFFSET_malloc_ctx", type=AddressUtil.parse_address,
                        help="The offset of `malloc_ctx` at OPTEE-TA.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="verbose output.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0x2a408".format(_cmdline_)

    _note_ = "Simplified heap structure:\n"
    _note_ += "\n"
    _note_ += "+-malloc_ctx-------------------+         +-freed chunk------------+\n"
    _note_ += "| bufsize prevfree             |<--+ +-->| bufsize prevfree       |= 0 (if upper chunk is used)  +--> ...\n"
    _note_ += "| bufsize bsize                |   | |   | bufsize bsize          |= the size of this chunk      |\n"
    _note_ += "| struct bfhead *flink         |-----+   | struct bfhead *flink   |------------------------------+\n"
    _note_ += "| struct bfhead *blink         |   +-----| struct bfhead *blink   |\n"
    _note_ += "| (bufsize totalloc)           |         |                        |\n"
    _note_ += "| (long numget)                |         |                        |\n"
    _note_ += "| (long numrel)                |         |                        |\n"
    _note_ += "| (long numpblk)               |         +-used chunk-------------+\n"
    _note_ += "| (long numpget)               |         | bufsize prevfree       |= the size of upper chunk (if upper chunk is freed)\n"
    _note_ += "| (long numprel)               |         | bufsize bsize          |= the size of this chunk (negative number)\n"
    _note_ += "| (long numdget)               |         | uchar user_data[bsize] |\n"
    _note_ += "| (long numdrel)               |         |                        |\n"
    _note_ += "| (func_ptr compfcn)           |         |                        |\n"
    _note_ += "| (func_ptr acqfcn)            |         +------------------------+\n"
    _note_ += "| (func_ptr relfcn)            |\n"
    _note_ += "| (bufsize exp_incr)           |\n"
    _note_ += "| (bufsize pool_len)           |\n"
    _note_ += "| struct malloc_pool* pool     |\n"
    _note_ += "| size_t pool_len              |\n"
    _note_ += "| (struct malloc_stats mstats) |\n"
    _note_ += "+------------------------------+"

    def is_readable_virt_memory(self, addr):
        if is_arm32():
            res = PageMap.get_page_maps_by_pagewalk("pagewalk -S --quiet --no-pager")
            res = sorted(set(res.splitlines()))
            res = list(filter(lambda line: "PL0/RW-" in line, res))
        elif is_arm64():
            res = PageMap.get_page_maps_by_pagewalk("pagewalk 1 --quiet --no-pager")
            res = sorted(set(res.splitlines()))
            res = list(filter(lambda line: "EL0/RW-" in line, res))
        for line in res:
            vrange, prange, *_ = line.split()
            vstart, vend = [int(x, 16) for x in vrange.split("-")]
            pstart, pend = [int(x, 16) for x in prange.split("-")]
            if vstart <= addr < vend:
                return True
        return False

    def get_ta_rw_address(self, ta_loaded_rx_end):
        if is_arm32():
            res = PageMap.get_page_maps_by_pagewalk("pagewalk -S --quiet --no-pager")
            res = sorted(set(res.splitlines()))
        elif is_arm64():
            res = PageMap.get_page_maps_by_pagewalk("pagewalk 1 --quiet --no-pager")
            res = sorted(set(res.splitlines()))
        for line in res:
            if not re.search("[PE]L1/RW", line):
                continue
            vrange, prange, *_ = line.split()
            vstart, vend = [int(x, 16) for x in vrange.split("-")]
            pstart, pend = [int(x, 16) for x in prange.split("-")]
            if vstart == ta_loaded_rx_end:
                return (vstart, vend, pstart, pend)
        return None

    def get_malloc_ctx(self, ta_rw_address_map):
        vstart = ta_rw_address_map[0]
        vend = ta_rw_address_map[1]
        data = read_memory(vstart, vend - vstart)
        data = slice_unpack(data, current_arch.ptrsize)

        candidate = []
        for i in range(len(data) - 3):
            if data[i] != 0 or data[i + 1] != 0: # should be 0
                continue
            if not is_valid_addr(data[i + 2]) or not is_valid_addr(data[i + 3]): # should be flink, blink
                continue

            addr = vstart + current_arch.ptrsize * i

            flink_blink = read_int_from_memory(data[i + 2] + current_arch.ptrsize * 3)
            blink_flink = read_int_from_memory(data[i + 3] + current_arch.ptrsize * 2)
            if flink_blink != addr or blink_flink != addr:
                continue

            link_list_count = 1
            flink_cur = data[i + 2]
            blink_cur = data[i + 3]
            flink_seen = []
            blink_seen = []
            while True:
                if flink_cur in flink_seen:
                    break
                if blink_cur in blink_seen:
                    break
                flink_seen.append(flink_cur)
                blink_seen.append(blink_cur)
                try:
                    flink_cur = read_int_from_memory(flink_cur + current_arch.ptrsize * 2)
                    blink_cur = read_int_from_memory(blink_cur + current_arch.ptrsize * 3)
                except gdb.MemoryError:
                    link_list_count = -1
                    break
                link_list_count += 1

            candidate.append((link_list_count, addr))

        if len(candidate) == 0:
            return None
        return sorted(candidate, reverse=True)[0][1] # maybe the longest flink is malloc_ctx

    def parse_flink(self, head):
        current = head
        flinks = []
        seen = [current]
        while True:
            try:
                prevfree = read_int_from_memory(current + current_arch.ptrsize * 0)
                bsize = read_int_from_memory(current + current_arch.ptrsize * 1)
                flink = read_int_from_memory(current + current_arch.ptrsize * 2)
                blink = read_int_from_memory(current + current_arch.ptrsize * 3)
                next_prevfree = read_int_from_memory(current + bsize)
                next_bsize = read_int_from_memory(current + bsize + current_arch.ptrsize)
            except gdb.MemoryError:
                flinks.append("memory corrupted")
                break
            if flink % 8 or blink % 8 or bsize % 8 or next_prevfree % 8 or next_bsize % 8:
                flinks.append("unaligned corrupted")
                break
            _chunk = {
                "addr": current, "prevfree": prevfree, "bsize": bsize, "flink": flink, "blink": blink,
                "next_prevfree": next_prevfree, "next_bsize": next_bsize,
            }
            Chunk = collections.namedtuple("Chunk", _chunk.keys())
            flinks.append(Chunk(*_chunk.values()))
            if flink == head:
                break
            if flink in seen[1:]:
                flinks.append("loop detected")
                break
            seen.append(current)
            current = flink
        return flinks

    def parse_blink(self, head):
        current = head
        blinks = []
        seen = [current]
        while True:
            try:
                prevfree = read_int_from_memory(current + current_arch.ptrsize * 0)
                bsize = read_int_from_memory(current + current_arch.ptrsize * 1)
                flink = read_int_from_memory(current + current_arch.ptrsize * 2)
                blink = read_int_from_memory(current + current_arch.ptrsize * 3)
                next_prevfree = read_int_from_memory(current + bsize)
                next_bsize = read_int_from_memory(current + bsize + current_arch.ptrsize)
            except gdb.MemoryError:
                blinks.append("memory corrupted")
                break
            if flink % 8 or blink % 8 or bsize % 8 or next_prevfree % 8 or next_bsize % 8:
                blinks.append("unaligned corrupted")
                break
            _chunk = {
                "addr": current, "prevfree": prevfree, "bsize": bsize, "flink": flink, "blink": blink,
                "next_prevfree": next_prevfree, "next_bsize": next_bsize,
            }
            Chunk = collections.namedtuple("Chunk", _chunk.keys())
            blinks.append(Chunk(*_chunk.values()))
            if blink == head:
                break
            if blink in seen[1:]:
                blinks.append("loop detected")
                break
            seen.append(current)
            current = blink
        return blinks

    def parse_malloc_ctx(self, malloc_ctx_addr):
        _malloc_ctx = {}
        _malloc_ctx["addr"] = current = malloc_ctx_addr

        _malloc_ctx["prevfree"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        _malloc_ctx["bsize"] = read_int_from_memory(current)
        current += current_arch.ptrsize
        _malloc_ctx["flink"] = read_int_from_memory(current)
        _malloc_ctx["flink_list"] = self.parse_flink(_malloc_ctx["flink"])
        current += current_arch.ptrsize
        _malloc_ctx["blink"] = read_int_from_memory(current)
        _malloc_ctx["blink_list"] = self.parse_blink(_malloc_ctx["blink"])
        current += current_arch.ptrsize

        # search pool
        for _ in range(14):
            pool_candidate = read_int_from_memory(current)
            current += current_arch.ptrsize
            if self.is_readable_virt_memory(pool_candidate):
                _malloc_ctx["pool"] = pool_candidate
                break
        else:
            err("Not found malloc_ctx->pool")
            return None

        _malloc_ctx["pool_len"] = read_int_from_memory(current)
        current += current_arch.ptrsize

        _malloc_ctx["pool_list"] = []
        for i in range(_malloc_ctx["pool_len"]):
            buf = read_int_from_memory(_malloc_ctx["pool"] + (i * 2) * current_arch.ptrsize)
            size = read_int_from_memory(_malloc_ctx["pool"] + (i * 2 + 1) * current_arch.ptrsize)
            _pool = {"buf": buf, "len": size}
            Pool = collections.namedtuple("Pool", _pool.keys())
            _malloc_ctx["pool_list"].append(Pool(*_pool.values()))

        MallocCtx = collections.namedtuple("MallocCtx", _malloc_ctx.keys())
        return MallocCtx(*_malloc_ctx.values())

    def dump_malloc_ctx(self, malloc_ctx):
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")

        self.out.append(titlify("malloc_ctx @ {:#x}".format(malloc_ctx.addr)))
        self.out.append("prevfree: {:#x}".format(malloc_ctx.prevfree))
        self.out.append("bsize:    {:#x}".format(malloc_ctx.bsize))
        self.out.append("flink:    {:#x}".format(malloc_ctx.flink))
        for chunk in malloc_ctx.flink_list:
            if isinstance(chunk, str):
                self.out.append(" -> {:s}".format(Color.colorify(chunk, corrupted_msg_color)))
            else:
                chunk_addr = Color.colorify("{:#010x}".format(chunk.addr), freed_address_color)
                colored_chunk_bsize = Color.colorify("{:#010x}".format(chunk.bsize), chunk_size_color)
                fmt = " -> {:s}: prevfree:{:#x} bsize:{:s} flink:{:#010x} blink:{:#010x}"
                fmt += " next_prevfree:{:#010x} next_bsize:{:#010x} (={:#010x})"
                self.out.append(fmt.format(chunk_addr, chunk.prevfree, colored_chunk_bsize, chunk.flink, chunk.blink,
                                     chunk.next_prevfree, chunk.next_bsize, (-chunk.next_bsize) & 0xffffffff))
        self.out.append("blink:    {:#x}".format(malloc_ctx.blink))
        for chunk in malloc_ctx.blink_list:
            if isinstance(chunk, str):
                self.out.append(" -> {:s}".format(Color.colorify(chunk, corrupted_msg_color)))
            else:
                chunk_addr = Color.colorify("{:#010x}".format(chunk.addr), freed_address_color)
                colored_chunk_bsize = Color.colorify("{:#010x}".format(chunk.bsize), chunk_size_color)
                fmt = " -> {:s}: prevfree:{:#x} bsize:{:s} flink:{:#010x} blink:{:#010x}"
                fmt += " next_prevfree:{:#010x} next_bsize:{:#010x} (={:#010x})"
                self.out.append(fmt.format(chunk_addr, chunk.prevfree, colored_chunk_bsize, chunk.flink, chunk.blink,
                                     chunk.next_prevfree, chunk.next_bsize, (-chunk.next_bsize) & 0xffffffff))
        self.out.append("pool:     {:#x}".format(malloc_ctx.pool))
        self.out.append("pool_len: {:#x}".format(malloc_ctx.pool_len))

        for i in range(malloc_ctx.pool_len):
            pool = malloc_ctx.pool_list[i]
            self.out.append("  pool[{:d}]  buf:{:#x}  size:{:#x}".format(i, pool.buf, pool.len))
        return

    def dump_chunk_list(self, malloc_ctx):
        freed_address_color = Config.get_gef_setting("theme.heap_chunk_address_freed")
        used_address_color = Config.get_gef_setting("theme.heap_chunk_address_used")
        corrupted_msg_color = Config.get_gef_setting("theme.heap_corrupted_msg")
        chunk_size_color = Config.get_gef_setting("theme.heap_chunk_size")
        chunk_used_color = Config.get_gef_setting("theme.heap_chunk_used")
        chunk_freed_color = Config.get_gef_setting("theme.heap_chunk_freed")

        for i in range(malloc_ctx.pool_len):
            pool = malloc_ctx.pool_list[i]
            pool_start = pool.buf
            pool_end = pool.buf + pool.len
            self.out.append(titlify("pool[{:d}] @ {:#x} - {:#x}".format(i, pool_start, pool_end)))

            chunk = pool_start
            seen = []
            while chunk < pool_end:
                if chunk in seen:
                    self.out.append(Color.colorify("loop detected", corrupted_msg_color))
                    break
                seen.append(chunk)
                try:
                    prevfree = read_int_from_memory(chunk + current_arch.ptrsize * 0)
                    bsize = read_int_from_memory(chunk + current_arch.ptrsize * 1)
                    flink = read_int_from_memory(chunk + current_arch.ptrsize * 2)
                    blink = read_int_from_memory(chunk + current_arch.ptrsize * 3)
                except gdb.MemoryError:
                    self.out.append(Color.colorify("unaligned orrupted", corrupted_msg_color))
                    break
                bsize_inv = (-bsize) & 0xffffffff
                if bsize_inv < 0x80000000: # used
                    fmt = "{:s} {:s}: prevfree:{:#010x} bsize:{:#010x} ({:s})"
                    used = Color.colorify("used", chunk_used_color)
                    colored_chunk_addr = Color.colorify("{:#010x}".format(chunk), used_address_color)
                    colored_bsize_inv = Color.colorify("{:#010x}".format(bsize_inv), chunk_size_color)
                    self.out.append(fmt.format(used, colored_chunk_addr, prevfree, bsize, colored_bsize_inv))
                    chunk += bsize_inv
                else: # freed
                    fmt = "{:s} {:s}: prevfree:{:#010x} bsize:{:s}              flink:{:#010x} blink:{:#010x}"
                    freed = Color.colorify("free", chunk_freed_color)
                    colored_chunk_addr = Color.colorify("{:#010x}".format(chunk), freed_address_color)
                    colored_bsize = Color.colorify("{:#010x}".format(bsize), chunk_size_color)
                    self.out.append(fmt.format(freed, colored_chunk_addr, prevfree, colored_bsize, flink, blink))
                    chunk += bsize
                if chunk % 8:
                    self.out.append(Color.colorify("unaligned orrupted", corrupted_msg_color))
                    break
            return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM32", "ARM64"))
    def do_invoke(self, args):
        self.out = []

        ta_address_map = OpteeThreadEnterUserModeBreakpoint.get_ta_loaded_address()
        if ta_address_map is None:
            err("TA address is not found")
            return

        ta_address = ta_address_map[0]
        if args.verbose:
            info("TA loaded address (RX): {:#x} - {:#x}".format(ta_address_map[0], ta_address_map[1]))

        if args.malloc_ctx is None:
            ta_rw_address_map = self.get_ta_rw_address(ta_address_map[1])
            if ta_rw_address_map is None:
                err("TA rw address is not found")
                return
            if args.verbose:
                info("TA loaded address (RW): {:#x} - {:#x}".format(ta_rw_address_map[0], ta_rw_address_map[1]))
            malloc_ctx_addr = self.get_malloc_ctx(ta_rw_address_map)
            if malloc_ctx_addr is None:
                err("malloc_ctx is not found")
                return
        else:
            if args.verbose:
                info("offset of malloc_ctx: {:#x}".format(args.malloc_ctx))
            malloc_ctx_addr = ta_address + args.malloc_ctx

        if args.verbose:
            info("malloc_ctx: {:#x}".format(malloc_ctx_addr))

        malloc_ctx = self.parse_malloc_ctx(malloc_ctx_addr)
        if malloc_ctx is None:
            err("parse failed")
            return

        self.dump_malloc_ctx(malloc_ctx)
        self.dump_chunk_list(malloc_ctx)

        if self.out:
            gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class CpuidCommand(GenericCommand):
    """Get cpuid result."""
    _cmdline_ = "cpuid"
    _category_ = "04-a. Register - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}".format(_cmdline_)

    _note_ = "Disable `-enable-kvm` option for qemu-system."

    def execute_cpuid(self, num, subnum=0):
        codes = [b"\x0f\xa2"] # cpuid
        if is_x86_64():
            regs = {"$rax": num, "$rcx": subnum}
        else:
            regs = {"$eax": num, "$ecx": subnum}
        ret = ExecAsm(codes, regs=regs).exec_code()

        if is_x86_64():
            eax = ret["reg"]["$rax"] & 0xffffffff
            ebx = ret["reg"]["$rbx"] & 0xffffffff
            ecx = ret["reg"]["$rcx"] & 0xffffffff
            edx = ret["reg"]["$rdx"] & 0xffffffff
        else:
            eax = ret["reg"]["$eax"]
            ebx = ret["reg"]["$ebx"]
            ecx = ret["reg"]["$ecx"]
            edx = ret["reg"]["$edx"]
        return eax, ebx, ecx, edx

    def show_result(self, id, subid, eax, ebx, ecx, edx):
        if eax == ebx == ecx == edx == 0:
            return

        if subid is None:
            self.out.append(titlify("cpuid (eax={:#x})".format(id)))
        else:
            self.out.append(titlify("cpuid (eax={:#x}, ecx={:#x})".format(id, subid)))
        self.out.append(Color.colorify("eax={:#x}, ebx={:#x}, ecx={:#x}, edx={:#x}".format(eax, ebx, ecx, edx), "bold yellow"))

        def c(reg, shift, mask, msg):
            val = (reg >> shift) & mask
            msg = msg + " (={:#x})".format(val)
            if val:
                return Color.boldify(msg)
            else:
                return msg

        if id == 0:
            vid = String.bytes2str(p32(ebx) + p32(edx) + p32(ecx))
            self.out.append("eax: Maximum Input Value for Basic CPUID Information")
            self.out.append("ebx+edx+ecx: Vendor ID (={:s})".format(repr(vid)))
        elif id == 1:
            self.out.append("eax: Version Information")
            self.out.append(c(eax,  0, 0xf,        "        EAX  3- 0: Stepping ID"))
            self.out.append(c(eax,  4, 0xf,        "        EAX  7- 4: Model Number"))
            self.out.append(c(eax,  8, 0xf,        "        EAX 11- 8: Family Code"))
            self.out.append(c(eax, 12, 0b11,       "        EAX 13-12: Processor Type"))
            self.out.append(c(eax, 14, 0b11,       "        EAX 15-14: Reserved"))
            self.out.append(c(eax, 16, 0xf,        "        EAX 19-16: Extended Model"))
            self.out.append(c(eax, 20, 0xff,       "        EAX 27-20: Extended Family"))
            self.out.append(c(eax, 28, 0xf,        "        EAX 31-28: Reserved"))
            self.out.append("ebx: Additional Information")
            self.out.append(c(ebx,  0, 0xff,       "        EBX  7- 0: Brand Index"))
            self.out.append(c(ebx,  8, 0xff,       "        EBX 15- 8: CLFLUSH line size"))
            self.out.append(c(ebx, 16, 0xff,       "        EBX 23-16: The number of logical processors"))
            self.out.append(c(ebx, 24, 0xff,       "        EBX 31-24: Initial APIC ID"))
            self.out.append("edx,ecx: Feature Information")
            self.out.append(c(edx,  0, 1,          "        EDX     0: FPU (Floating Point Unit on-chip)"))
            self.out.append(c(edx,  1, 1,          "        EDX     1: VME (Virtual 8086 Mode Enhancements)"))
            self.out.append(c(edx,  2, 1,          "        EDX     2: DE (Debugging Extensions)"))
            self.out.append(c(edx,  3, 1,          "        EDX     3: PSE (Page Size Extension)"))
            self.out.append(c(edx,  4, 1,          "        EDX     4: TSC (Time Stamp Counter)"))
            self.out.append(c(edx,  5, 1,          "        EDX     5: MSR (Model Specific Registers RDMSR and WRMSR instructions)"))
            self.out.append(c(edx,  6, 1,          "        EDX     6: PAE (Physical Address Extension)"))
            self.out.append(c(edx,  7, 1,          "        EDX     7: MCE (Machine Check Exception)"))
            self.out.append(c(edx,  8, 1,          "        EDX     8: CX8 (CMPXCHG8B instruction)"))
            self.out.append(c(edx,  9, 1,          "        EDX     9: APIC (APIC on-chip)"))
            self.out.append(c(edx, 10, 1,          "        EDX    10: Reserved"))
            self.out.append(c(edx, 11, 1,          "        EDX    11: SEP (SYSENTER and SYSEXIT instructions)"))
            self.out.append(c(edx, 12, 1,          "        EDX    12: MTRR (Memory Type Range Registers)"))
            self.out.append(c(edx, 13, 1,          "        EDX    13: PGE (Page Global Bit)"))
            self.out.append(c(edx, 14, 1,          "        EDX    14: MCA (Machine Check Architecture)"))
            self.out.append(c(edx, 15, 1,          "        EDX    15: CMOV (Conditional Move instructions)"))
            self.out.append(c(edx, 16, 1,          "        EDX    16: PAT (Page Attribute Table)"))
            self.out.append(c(edx, 17, 1,          "        EDX    17: PSE-36 (36-Bit Page Size Extension)"))
            self.out.append(c(edx, 18, 1,          "        EDX    18: PSN (Processor Serial Number)"))
            self.out.append(c(edx, 19, 1,          "        EDX    19: CLFSH (CLFLUSH instruction)"))
            self.out.append(c(edx, 20, 1,          "        EDX    20: Reserved"))
            self.out.append(c(edx, 21, 1,          "        EDX    21: DS (Debug Store)"))
            self.out.append(c(edx, 22, 1,          "        EDX    22: ACPI (Thermal Monitor and Software Controlled Clock Facilities)"))
            self.out.append(c(edx, 23, 1,          "        EDX    23: MMX (Intel MMX technology)"))
            self.out.append(c(edx, 24, 1,          "        EDX    24: FXSR (FXSAVE and FXRSTOR instructions)"))
            self.out.append(c(edx, 25, 1,          "        EDX    25: SSE (Streaming SIMD Extension)"))
            self.out.append(c(edx, 26, 1,          "        EDX    26: SSE2 (STreaming SIMD Extension 2)"))
            self.out.append(c(edx, 27, 1,          "        EDX    27: SS (Self Snoop)"))
            self.out.append(c(edx, 28, 1,          "        EDX    28: HTT (Max APIC IDs reserved field is Valid)"))
            self.out.append(c(edx, 29, 1,          "        EDX    29: TM (Thermal Monitor)"))
            self.out.append(c(edx, 30, 1,          "        EDX    30: Reserved"))
            self.out.append(c(edx, 31, 1,          "        EDX    31: PBE (Pending Break Enable)"))
            self.out.append(c(ecx,  0, 1,          "        ECX     0: SSE3 (Streaming SIMD Extensions 3)"))
            self.out.append(c(ecx,  1, 1,          "        ECX     1: PCLMULQDQ (PCLMULQDQ instruction)"))
            self.out.append(c(ecx,  2, 1,          "        ECX     2: DTES64 (64-bit DS Area)"))
            self.out.append(c(ecx,  3, 1,          "        ECX     3: MONITOR (MONITOR/MWAIT instruction)"))
            self.out.append(c(ecx,  4, 1,          "        ECX     4: DS-CPL (CPL Qualified Debug Store)"))
            self.out.append(c(ecx,  5, 1,          "        ECX     5: VMX (Intel VT (Virtual Machine eXtensions))"))
            self.out.append(c(ecx,  6, 1,          "        ECX     6: SMX (Safer Mode eXtensions)"))
            self.out.append(c(ecx,  7, 1,          "        ECX     7: EIST (Enhanced Intel SpeedStep Technology)"))
            self.out.append(c(ecx,  8, 1,          "        ECX     8: TM2 (Thermal Monitor 2)"))
            self.out.append(c(ecx,  9, 1,          "        ECX     9: SSSE3 (Supplemental Streaming SIMD Extensions 3)"))
            self.out.append(c(ecx, 10, 1,          "        ECX    10: CNXT-ID (L1 Context ID)"))
            self.out.append(c(ecx, 11, 1,          "        ECX    11: SDBG (IA32_DEBUG_INTERFACE MSR for silicon debug)"))
            self.out.append(c(ecx, 12, 1,          "        ECX    12: FMA (FMA extensions using YMM state)"))
            self.out.append(c(ecx, 13, 1,          "        ECX    13: CMPXCHG16B (CMPXCHG16B instruction)"))
            self.out.append(c(ecx, 14, 1,          "        ECX    14: xTPR (xTPR update control)"))
            self.out.append(c(ecx, 15, 1,          "        ECX    15: PDCM (Perfmon and Debug Capability MSR)"))
            self.out.append(c(ecx, 16, 1,          "        ECX    16: Reserved"))
            self.out.append(c(ecx, 17, 1,          "        ECX    17: PCID (Process-Context IDentifiers)"))
            self.out.append(c(ecx, 18, 1,          "        ECX    18: DCA (Direct Cache Access)"))
            self.out.append(c(ecx, 19, 1,          "        ECX    19: SSE4_1 (Streaming SIMD Extensions 4.1)"))
            self.out.append(c(ecx, 20, 1,          "        ECX    20: SSE4_2 (Streaming SIMD Extensions 4.2)"))
            self.out.append(c(ecx, 21, 1,          "        ECX    21: x2APIC"))
            self.out.append(c(ecx, 22, 1,          "        ECX    22: MOVBE (MOVBE instruction)"))
            self.out.append(c(ecx, 23, 1,          "        ECX    23: POPCNT (POPulation CouNt instruction)"))
            self.out.append(c(ecx, 24, 1,          "        ECX    24: TSC-Deadline"))
            self.out.append(c(ecx, 25, 1,          "        ECX    25: AESNI (AESNI Instruction)"))
            self.out.append(c(ecx, 26, 1,          "        ECX    26: XSAVE (XSAVE instruction)"))
            self.out.append(c(ecx, 27, 1,          "        ECX    27: OSXSAVE (OSXSAVE instruction)"))
            self.out.append(c(ecx, 28, 1,          "        ECX    28: AVX (Intel Advanced Vector eXtensions)"))
            self.out.append(c(ecx, 29, 1,          "        ECX    29: F16C (16-bit Floating-point Conversion instructions)"))
            self.out.append(c(ecx, 30, 1,          "        ECX    30: RDRAND (RDRAND instruction)"))
            self.out.append(c(ecx, 31, 1,          "        ECX    31: RAZ (Reserved for use by hypervisor to indicate guest status)"))
        elif id == 2:
            self.out.append("Cache and TLB Information")
        elif id == 3:
            self.out.append("eax,ebx: Reserved")
            self.out.append("edx+ecx: Processor Serial Number")
        elif id == 4:
            self.out.append("Information of cache configuration descriptor")
        elif id == 5:
            self.out.append("Information of MONITOR/MWAIT")
        elif id == 6:
            self.out.append("Information of power management")
            self.out.append(c(eax,  0, 1,          "        EAX     0: Digital temperature sensor"))
            self.out.append(c(eax,  1, 1,          "        EAX     1: Intel Turbo Boost Technology"))
            self.out.append(c(eax,  2, 1,          "        EAX     2: ARAT (Always Running APIC Timer)"))
            self.out.append(c(eax,  3, 1,          "        EAX     3: Reserved"))
            self.out.append(c(eax,  4, 1,          "        EAX     4: Power limit notification controls"))
            self.out.append(c(eax,  5, 1,          "        EAX     5: Clock modulation duty cycle extensions"))
            self.out.append(c(eax,  6, 1,          "        EAX     6: Package thermal management"))
            self.out.append(c(eax,  7, 1,          "        EAX     7: Hardware-managed P-state base support (HWP)"))
            self.out.append(c(eax,  8, 1,          "        EAX     8: HWP notification interrupt enable MSR"))
            self.out.append(c(eax,  9, 1,          "        EAX     9: HWP activity window MSR"))
            self.out.append(c(eax, 10, 1,          "        EAX    10: HWP energy/performance preference MSR"))
            self.out.append(c(eax, 11, 1,          "        EAX    11: HWP package level request MSR"))
            self.out.append(c(eax, 12, 1,          "        EAX    12: Reserved"))
            self.out.append(c(eax, 13, 1,          "        EAX    13: HDC (Hardware Duty Cycle programming)"))
            self.out.append(c(eax, 14, 1,          "        EAX    14: Intel Turbo Boost Max Technology 3.0"))
            self.out.append(c(eax, 15, 1,          "        EAX    15: HWP Capabilities, Highest Performance change"))
            self.out.append(c(eax, 16, 1,          "        EAX    16: HWP PECI override"))
            self.out.append(c(eax, 17, 1,          "        EAX    17: Flexible HWP"))
            self.out.append(c(eax, 18, 1,          "        EAX    18: Fast access mode for IA32_HWP_REQUEST MSR"))
            self.out.append(c(eax, 19, 1,          "        EAX    19: Hardware feedback MSRs"))
            self.out.append(c(eax, 20, 1,          "        EAX    20: Ignoring Idle Logical Processor HWP request"))
            self.out.append(c(eax, 21, 1,          "        EAX    21: Reserved"))
            self.out.append(c(eax, 22, 1,          "        EAX    22: Reserved"))
            self.out.append(c(eax, 23, 1,          "        EAX    23: Enhanced hardware feedback MSRs"))
            self.out.append(c(eax, 24, 0x7f,       "        EAX 30-24: Reserved"))
            self.out.append(c(eax, 31, 1,          "        EAX    31: IP payloads are LIP"))
            self.out.append(c(ebx,  0, 0xf,        "        EBX  3- 0: Number of interrupted thresholds of digital temperature sensor"))
            self.out.append(c(ebx,  4, 0xfffffff,  "        EBX 31- 4: Reserved"))
            self.out.append(c(ecx,  0, 1,          "        ECX     0: Hardware Coordination Feedback Capability (APERF and MPERF)"))
            self.out.append(c(ecx,  1, 1,          "        ECX     1: Reserved"))
            self.out.append(c(ecx,  2, 1,          "        ECX     2: Reserved"))
            self.out.append(c(ecx,  3, 1,          "        ECX     3: Performance-energy bias preference"))
            self.out.append(c(ecx,  4, 0xfffffff,  "        ECX 31- 4: Reserved"))
            self.out.append(c(edx,  0, 1,          "        EDX     0: Performance feature report"))
            self.out.append(c(edx,  1, 1,          "        EDX     1: Energy efficiency capacity report"))
            self.out.append(c(edx,  2, 0x3f,       "        EDX  7- 2: Reserved"))
            self.out.append(c(edx,  8, 0xf,        "        EDX 11- 8: The size of the hardware feedback interface structure"))
            self.out.append(c(edx, 12, 0xf,        "        EDX 15-12: Reserved"))
            self.out.append(c(edx, 16, 0xffff,     "        EDX 31-16: Index of rows for the hardware feedback interface structure"))
        elif id == 7 and subid == 0:
            self.out.append("eax: Maximum Input Value for Extended CPUID Information")
            self.out.append("ebx,edx,edx: Extended Feature Information")
            self.out.append(c(ebx,  0, 1,          "        EBX     0: FSGSBASE (FSGSBASE instructions)"))
            self.out.append(c(ebx,  1, 1,          "        EBX     1: TSC_ADJUST (IA32_TSC_ADJUST MSR supported)"))
            self.out.append(c(ebx,  2, 1,          "        EBX     2: SGX (Software Guard Extensions)"))
            self.out.append(c(ebx,  3, 1,          "        EBX     3: BMI1 (Bit Manipulation Instructions)"))
            self.out.append(c(ebx,  4, 1,          "        EBX     4: HLE (Hardware Lock Elision)"))
            self.out.append(c(ebx,  5, 1,          "        EBX     5: AVX2 (Advanced Vector Extensions 2.0)"))
            self.out.append(c(ebx,  6, 1,          "        EBX     6: FDP_EXCPTN_ONLY (x87 FPU Data Pointer updated only on x87 Exceptions)"))
            self.out.append(c(ebx,  7, 1,          "        EBX     7: SMEP (Supervisor Mode Execution Protection)"))
            self.out.append(c(ebx,  8, 1,          "        EBX     8: BMI2 (Bit Manipulation Instructions 2)"))
            self.out.append(c(ebx,  9, 1,          "        EBX     9: ERMS (Enhanced REP MOVSB/STOSB)"))
            self.out.append(c(ebx, 10, 1,          "        EBX    10: INVPCID (INVPCID instruction)"))
            self.out.append(c(ebx, 11, 1,          "        EBX    11: RTM (Restricted Transactional Memory)"))
            self.out.append(c(ebx, 12, 1,          "        EBX    12: PQM (Platform QoS Monitoring)"))
            self.out.append(c(ebx, 13, 1,          "        EBX    13: x87 FPU CS and DS deprecated"))
            self.out.append(c(ebx, 14, 1,          "        EBX    14: MPX (Memory Protection eXtensions)"))
            self.out.append(c(ebx, 15, 1,          "        EBX    15: PQE (Platform QoS Enforcement)"))
            self.out.append(c(ebx, 16, 1,          "        EBX    16: AVX512F (AVX512 Foundation)"))
            self.out.append(c(ebx, 17, 1,          "        EBX    17: AVX512DQ (AVX512 Double/Quadword instructions)"))
            self.out.append(c(ebx, 18, 1,          "        EBX    18: RDSEED (RDSEED instruction)"))
            self.out.append(c(ebx, 19, 1,          "        EBX    19: ADX (Multi-Precision Add-Carry instruction eXtensions)"))
            self.out.append(c(ebx, 20, 1,          "        EBX    20: SMAP (Supervisor Mode Access Prevention)"))
            self.out.append(c(ebx, 21, 1,          "        EBX    21: AVX512IFMA (AVX512 Integer FMA instructions)"))
            self.out.append(c(ebx, 22, 1,          "        EBX    22: (Intel) PCOMMIT (Persistent Commit instruction)"))
            self.out.append(c(ebx, 22, 1,          "        EBX    22: (AMD) RDPID (RDPID instruction and TSC_AUX MSR iupport)"))
            self.out.append(c(ebx, 23, 1,          "        EBX    23: CLFLUSHOPT (CLFLUSHOPT instruction)"))
            self.out.append(c(ebx, 24, 1,          "        EBX    24: CLWB (Cache Line Write-Back instruction)"))
            self.out.append(c(ebx, 25, 1,          "        EBX    25: PT (Intel Processor Trace)"))
            self.out.append(c(ebx, 26, 1,          "        EBX    26: AVX512PF (AVX512 Prefetch instructions)"))
            self.out.append(c(ebx, 27, 1,          "        EBX    27: AVX512ER (AVX512 Exponent/Reciprocal instructions)"))
            self.out.append(c(ebx, 28, 1,          "        EBX    28: AVX512CD (AVX512 Conflict Detection instructions)"))
            self.out.append(c(ebx, 29, 1,          "        EBX    29: SHA (SHA-1/SHA-256 instructions)"))
            self.out.append(c(ebx, 30, 1,          "        EBX    30: AVX512BW (AVX512 Byte/Word instructions)"))
            self.out.append(c(ebx, 31, 1,          "        EBX    31: AVX512VL (AVX512 Vector Length Extensions)"))
            self.out.append(c(ecx,  0, 1,          "        ECX     0: PREFETCHWT1 (PREFETCHWT1 instruction)"))
            self.out.append(c(ecx,  1, 1,          "        ECX     1: AVX512VBMI (AVX512 Vector Byte Manipulation Instructions)"))
            self.out.append(c(ecx,  2, 1,          "        ECX     2: UMIP (User Mode Instruction Prevention)"))
            self.out.append(c(ecx,  3, 1,          "        ECX     3: PKU (Protection Keys for User-mode pages)"))
            self.out.append(c(ecx,  4, 1,          "        ECX     4: OSPKE (OS has Enabled Protection Keys)"))
            self.out.append(c(ecx,  5, 1,          "        ECX     5: WAITPKG (Wait and Pause Enhancements)"))
            self.out.append(c(ecx,  6, 1,          "        ECX     6: AVX512VBMI2 (AVX512 Vector Byte Manipulation Instructions 2)"))
            self.out.append(c(ecx,  7, 1,          "        ECX     7: CET_SS (CET shadow stack)"))
            self.out.append(c(ecx,  8, 1,          "        ECX     8: GFNI (Galois Field NI / Galois Field Affine Transformation)"))
            self.out.append(c(ecx,  9, 1,          "        ECX     9: VAES (VEX-encoded AES-NI)"))
            self.out.append(c(ecx, 10, 1,          "        ECX    10: VPCL (VEX-encoded PCLMUL)"))
            self.out.append(c(ecx, 11, 1,          "        ECX    11: AVX512VNNI (AVX512 Vector Neural Network Instructions)"))
            self.out.append(c(ecx, 12, 1,          "        ECX    12: AVX512BITALG (AVX512 Bitwise Algorithms)"))
            self.out.append(c(ecx, 13, 1,          "        ECX    13: TME_EN (Total Memory Encryption)"))
            self.out.append(c(ecx, 14, 1,          "        ECX    14: AVX512 VPOPCNTDQ"))
            self.out.append(c(ecx, 15, 1,          "        ECX    15: Reserved"))
            self.out.append(c(ecx, 16, 1,          "        ECX    16: LA57 (5-Level paging)"))
            self.out.append(c(ecx, 17, 0x1f,       "        ECX 21-17: MAWAU (MPX Address-Width Adjust for CPL=3)"))
            self.out.append(c(ecx, 22, 1,          "        ECX    22: RDPID (Read Processor ID)"))
            self.out.append(c(ecx, 23, 1,          "        ECX    23: KL (Key Locker)"))
            self.out.append(c(ecx, 24, 1,          "        ECX    24: Reserved"))
            self.out.append(c(ecx, 25, 1,          "        ECX    25: CLDEMOTE (Cache Line Demote)"))
            self.out.append(c(ecx, 26, 1,          "        ECX    26: Reserved"))
            self.out.append(c(ecx, 27, 1,          "        ECX    27: MOVDIRI (32-bit Direct Stores)"))
            self.out.append(c(ecx, 28, 1,          "        ECX    28: MOVDIRI64B (64-bit Direct Stores)"))
            self.out.append(c(ecx, 29, 1,          "        ECX    29: ENQCMD (ENQueue Stores)"))
            self.out.append(c(ecx, 30, 1,          "        ECX    30: SGX_LC (SGX Launch Configuration)"))
            self.out.append(c(ecx, 31, 1,          "        ECX    31: PKS (Protection Keys for Supervisor-mode pages)"))
            self.out.append(c(edx,  0, 1,          "        EDX     0: Reserved"))
            self.out.append(c(edx,  1, 1,          "        EDX     1: Reserved"))
            self.out.append(c(edx,  2, 1,          "        EDX     2: AVX512_4VNNIW"))
            self.out.append(c(edx,  3, 1,          "        EDX     3: AVX512_4FMAPS"))
            self.out.append(c(edx,  4, 1,          "        EDX     4: Fast Short REP MOV"))
            self.out.append(c(edx,  5, 1,          "        EDX     5: UINTR (User Interrupts)"))
            self.out.append(c(edx,  6, 1,          "        EDX     6: Reserved"))
            self.out.append(c(edx,  7, 1,          "        EDX     7: Reserved"))
            self.out.append(c(edx,  8, 1,          "        EDX     8: AVX512_VP2INTERSECT"))
            self.out.append(c(edx,  9, 1,          "        EDX     9: Reserved"))
            self.out.append(c(edx, 10, 1,          "        EDX    10: MD_CLEAR"))
            self.out.append(c(edx, 11, 1,          "        EDX    11: Reserved"))
            self.out.append(c(edx, 12, 1,          "        EDX    12: Reserved"))
            self.out.append(c(edx, 13, 1,          "        EDX    13: TSX force abort MSR"))
            self.out.append(c(edx, 14, 1,          "        EDX    14: SERIALIZE"))
            self.out.append(c(edx, 15, 1,          "        EDX    15: Hybrid"))
            self.out.append(c(edx, 16, 1,          "        EDX    16: TSX suspend load address tracking"))
            self.out.append(c(edx, 17, 1,          "        EDX    17: Reserved"))
            self.out.append(c(edx, 18, 1,          "        EDX    18: PCONFIG"))
            self.out.append(c(edx, 19, 1,          "        EDX    19: Reserved"))
            self.out.append(c(edx, 20, 1,          "        EDX    20: CET_IBT (CET Indirect Branch Tracking)"))
            self.out.append(c(edx, 21, 1,          "        EDX    21: Reserved"))
            self.out.append(c(edx, 22, 1,          "        EDX    22: AMX-BF16 (Tile computation on bfloat16)"))
            self.out.append(c(edx, 23, 1,          "        EDX    23: AVX512FP16"))
            self.out.append(c(edx, 24, 1,          "        EDX    24: AMX-TILE (Tile architecture)"))
            self.out.append(c(edx, 25, 1,          "        EDX    25: AMX-INT8 (Tile computation on 8-bit integers)"))
            self.out.append(c(edx, 26, 1,          "        EDX    26: IBRS/IBPB (Indirect Branch Restricted Speculation/Predictor Barrier)"))
            self.out.append(c(edx, 27, 1,          "        EDX    27: STIBP (Single Thread Indirect Branch Predictors)"))
            self.out.append(c(edx, 28, 1,          "        EDX    28: L1D_FLUSH (L1 Data Cache Flush)"))
            self.out.append(c(edx, 29, 1,          "        EDX    29: IA32_ARCH_CAPABILITIES MSR"))
            self.out.append(c(edx, 30, 1,          "        EDX    30: IA32_CORE_CAPABILITIES MSR"))
            self.out.append(c(edx, 31, 1,          "        EDX    31: SSBD (Speculative Store Bypass Disable)"))
        elif id == 7 and subid != 0:
            self.out.append("ebx,edx,edx: Extended Feature Information")
        elif id == 8:
            self.out.append("Reserved")
        elif id == 9:
            self.out.append("eax: PLATFORM_DCA_CAP MSR")
            self.out.append("ebx,ecx,edx: Reserved")
        elif id == 10:
            self.out.append("DCA parameters")
            self.out.append(c(eax,  0, 0xff,       "        EAX  7- 0: Revision"))
            self.out.append(c(eax,  8, 0xff,       "        EAX 15- 8: Number of PeMo counters per logical processor"))
            self.out.append(c(eax, 16, 0xff,       "        EAX 23-16: Bit width of PeMo counter"))
            self.out.append(c(eax, 24, 0xff,       "        EAX 31-24: EBX bit vector length"))
            self.out.append(c(ebx,  0, 1,          "        EBX     0: Core cycles event unavailable"))
            self.out.append(c(ebx,  1, 1,          "        EBX     1: Instructions retired event unavailable"))
            self.out.append(c(ebx,  2, 1,          "        EBX     2: Reference cycles event unavailable"))
            self.out.append(c(ebx,  3, 1,          "        EBX     3: Last level cache references event unavailable"))
            self.out.append(c(ebx,  4, 1,          "        EBX     4: Last level cache misses event unavailable"))
            self.out.append(c(ebx,  5, 1,          "        EBX     5: Branch instructions retired event unavailable"))
            self.out.append(c(ebx,  6, 1,          "        EBX     6: Branch mispredicts retired event unavailable"))
            self.out.append(c(ebx,  7, 0x1ffffff,  "        EBX 31- 7: Reserved"))
            self.out.append(c(ecx,  0, 0xffffffff, "        ECX 31- 0: Reserved"))
            self.out.append(c(edx,  0, 0x1f,       "        EDX  4- 0: Number of fixed function PeMo counters"))
            self.out.append(c(edx,  5, 0xff,       "        EDX 12- 5: Bit width of fixed function PeMo counter"))
            self.out.append(c(edx, 13, 1,          "        EDX    13: Reserved"))
            self.out.append(c(edx, 14, 1,          "        EDX    14: Reserved"))
            self.out.append(c(edx, 15, 1,          "        EDX    15: AnyThread deprecation"))
            self.out.append(c(edx, 16, 0xffff,     "        EDX 31-16: Reserved"))
        elif id == 11:
            self.out.append("Information of topology enumeration")
        elif id == 12:
            self.out.append("Reserved")
        elif id == 13:
            if subid == 0:
                m = "main"
            elif subid == 1:
                m = "sub"
            else:
                m = "XCR0.{:d}".format(subid)
            self.out.append("Information of extended state enumeration ({:s})".format(m))
        elif id in [15, 16]:
            self.out.append("Intel Resource Director Technology (Intel RDT), Cache, Memory Bandwidth Allocation Enumeration")
        elif id == 18:
            self.out.append("Information of Intel SGX")
        elif id == 20:
            self.out.append("Information of Intel Processor Trace Enumeration")
            self.out.append(c(ebx,  0, 1,          "        EBX     0: CR3 filtering"))
            self.out.append(c(ebx,  1, 1,          "        EBX     1: Configurable PSB, Cycle-Accurate Mode"))
            self.out.append(c(ebx,  2, 1,          "        EBX     2: Filtering preserved across warm reset"))
            self.out.append(c(ebx,  3, 1,          "        EBX     3: MTC timing packet, suppression of COFI-based packets"))
            self.out.append(c(ebx,  4, 1,          "        EBX     4: PTWRITE"))
            self.out.append(c(ebx,  5, 1,          "        EBX     5: Power Event Trace"))
            self.out.append(c(ebx,  6, 1,          "        EBX     6: PSB and PMI preservation MSRs"))
            self.out.append(c(ebx,  7, 0x1ffffff,  "        EBX 31- 7: Reserved"))
            self.out.append(c(ecx,  0, 1,          "        ECX     0: ToPA output scheme"))
            self.out.append(c(ecx,  1, 1,          "        ECX     1: ToPA tables hold multiple output entries"))
            self.out.append(c(ecx,  2, 1,          "        ECX     2: Single-range output scheme"))
            self.out.append(c(ecx,  3, 1,          "        ECX     3: Trace Transport output support"))
            self.out.append(c(ecx,  4, 0x7ffffff,  "        ECX 30- 4: Reserved"))
            self.out.append(c(ecx, 31, 1,          "        ECX    31: IP payloads are LIP"))
        elif id == 21:
            self.out.append("TSC and Nominal Core Crystal Clock")
        elif id == 22:
            self.out.append("Information of CPU frequency")
            self.out.append(c(eax,  0, 0xffff,     "        EAX 15- 0: Processor Base Frequency (MHz)"))
            self.out.append(c(eax, 16, 0xffff,     "        EAX 31-16: Reserved"))
            self.out.append(c(ebx,  0, 0xffff,     "        EBX 15- 0: Maximum Frequency (MHz)"))
            self.out.append(c(ebx, 16, 0xffff,     "        EBX 31-16: Reserved"))
            self.out.append(c(ecx,  0, 0xffff,     "        ECX 15- 0: Bus (Reference) Frequency (MHz)"))
            self.out.append(c(ecx, 16, 0xffff,     "        ECX 31-16: Reserved"))
            self.out.append(c(edx,  0, 0xffffffff, "        EDX 31- 0: Reserved"))
        elif id == 23:
            self.out.append("Information of System-On-Chip Vendor Attribute Enumeration")
        elif id == 24:
            self.out.append("Information of Deterministic Address Translation Parameters")
        elif id == 26:
            self.out.append("Information of Hybrid Information Enumeration")
        elif id == 31:
            self.out.append("Information of V2 Extended Topology Enumeration")
        elif id == 0x40000000:
            vid = String.bytes2str(p32(ebx) + p32(ecx) + p32(edx))
            self.out.append("eax: Maximum Input Value for Hypervisor Function CPUID Information")
            self.out.append("ebx+ecx+edx: Hypervisor Brand String (={:s})".format(repr(vid)))
        elif id == 0x40000001:
            self.out.append("Hypervisor")
            self.out.append(c(eax,  0, 1,          "        EAX     0: Clocksource"))
            self.out.append(c(eax,  1, 1,          "        EAX     1: NOP IO Delay"))
            self.out.append(c(eax,  2, 1,          "        EAX     2: MMU Op"))
            self.out.append(c(eax,  3, 1,          "        EAX     3: Clocksource 2"))
            self.out.append(c(eax,  4, 1,          "        EAX     4: Async PF"))
            self.out.append(c(eax,  5, 1,          "        EAX     5: Steal Time"))
            self.out.append(c(eax,  6, 1,          "        EAX     6: PV EOI"))
            self.out.append(c(eax,  7, 1,          "        EAX     7: PV UNHALT"))
            self.out.append(c(eax,  8, 1,          "        EAX     8: Reserved"))
            self.out.append(c(eax,  9, 1,          "        EAX     9: PV TLB flush"))
            self.out.append(c(eax, 10, 1,          "        EAX    10: PV async PF VMEXIT"))
            self.out.append(c(eax, 11, 1,          "        EAX    11: PV send IPI"))
            self.out.append(c(eax, 12, 1,          "        EAX    12: PV poll control"))
            self.out.append(c(eax, 13, 1,          "        EAX    13: PV sched yield"))
            self.out.append(c(eax, 14, 1,          "        EAX    14: Async PF INT"))
            self.out.append(c(eax, 15, 1,          "        EAX    15: MSI extended destination ID"))
            self.out.append(c(eax, 16, 1,          "        EAX    16: Hypercall map GPA range"))
            self.out.append(c(eax, 17, 1,          "        EAX    17: Hypercall map GPA range"))
            self.out.append(c(eax, 18, 1,          "        EAX    18: Migration control"))
            self.out.append(c(eax, 19, 0x3f,       "        EAX 24-19: Reserved"))
            self.out.append(c(eax, 25, 1,          "        EAX    25: Clocksource Stable"))
            self.out.append(c(eax, 26, 0x3f,       "        EAX 31-26: Reserved"))
            self.out.append(c(edx,  0, 1,          "        EDX     0: vCPUs realtime, never preempted"))
            self.out.append(c(edx,  1, 0x7fffffff, "        EDX 31- 1: Reserved"))
        elif id == 0x40000003:
            self.out.append("Hypervisor")
            self.out.append(c(eax,  0, 1,          "        EAX     0: VP_RUNTIME"))
            self.out.append(c(eax,  1, 1,          "        EAX     1: TIME_REF_COUNT"))
            self.out.append(c(eax,  2, 1,          "        EAX     2: Basic SynIC MSRs"))
            self.out.append(c(eax,  3, 1,          "        EAX     3: Synthetic Timer"))
            self.out.append(c(eax,  4, 1,          "        EAX     4: APIC access"))
            self.out.append(c(eax,  5, 1,          "        EAX     5: Hypercall MSRs"))
            self.out.append(c(eax,  6, 1,          "        EAX     6: VP Index MSR"))
            self.out.append(c(eax,  7, 1,          "        EAX     7: System Reset MSR"))
            self.out.append(c(eax,  8, 1,          "        EAX     8: Access stats MSRs"))
            self.out.append(c(eax,  9, 1,          "        EAX     9: Reference TSC"))
            self.out.append(c(eax, 10, 1,          "        EAX    10: Guest Idle MSR"))
            self.out.append(c(eax, 11, 1,          "        EAX    11: Timer Frequency MSRs"))
            self.out.append(c(eax, 12, 1,          "        EAX    12: Debug MSRs"))
            self.out.append(c(eax, 13, 1,          "        EAX    13: Reenlightenment controls"))
            self.out.append(c(eax, 14, 0x3ffff,    "        EAX 31-14: Reserved"))
            self.out.append(c(ebx,  0, 1,          "        EBX     0: CreatePartitions"))
            self.out.append(c(ebx,  1, 1,          "        EBX     1: AccessPartitionId"))
            self.out.append(c(ebx,  2, 1,          "        EBX     2: AccessMemoryPool"))
            self.out.append(c(ebx,  3, 1,          "        EBX     3: AdjustMemoryBuffers"))
            self.out.append(c(ebx,  4, 1,          "        EBX     4: PostMessages"))
            self.out.append(c(ebx,  5, 1,          "        EBX     5: SignalEvents"))
            self.out.append(c(ebx,  6, 1,          "        EBX     6: CreatePort"))
            self.out.append(c(ebx,  7, 1,          "        EBX     7: ConnectPort"))
            self.out.append(c(ebx,  8, 1,          "        EBX     8: AccessStats"))
            self.out.append(c(ebx,  9, 1,          "        EBX     9: Reserved"))
            self.out.append(c(ebx, 10, 1,          "        EBX    10: Reserved"))
            self.out.append(c(ebx, 11, 1,          "        EBX    11: Debugging"))
            self.out.append(c(ebx, 12, 1,          "        EBX    12: CpuManagement"))
            self.out.append(c(ebx, 13, 1,          "        EBX    13: ConfigureProfiler"))
            self.out.append(c(ebx, 14, 1,          "        EBX    14: EnableExpandedStackwalking"))
            self.out.append(c(ebx, 15, 1,          "        EBX    15: Reserved"))
            self.out.append(c(ebx, 16, 1,          "        EBX    16: AccessVSM"))
            self.out.append(c(ebx, 17, 1,          "        EBX    17: AccessVpRegisters"))
            self.out.append(c(ebx, 18, 1,          "        EBX    18: Reserved"))
            self.out.append(c(ebx, 19, 1,          "        EBX    19: Reserved"))
            self.out.append(c(ebx, 20, 1,          "        EBX    20: EnableExtendedHypercalls"))
            self.out.append(c(ebx, 21, 1,          "        EBX    21: StartVirtualProcessor"))
            self.out.append(c(ebx, 22, 0x3ff,      "        EBX 31-22: Reserved"))
            self.out.append(c(edx,  0, 1,          "        EDX     0: MWAIT instruction support (deprecated)"))
            self.out.append(c(edx,  1, 1,          "        EDX     1: Guest debugging support"))
            self.out.append(c(edx,  2, 1,          "        EDX     2: Performance Monitor support"))
            self.out.append(c(edx,  3, 1,          "        EDX     3: Physical CPU dynamic partitioning event support"))
            self.out.append(c(edx,  4, 1,          "        EDX     4: Hypercall input params via XMM registers"))
            self.out.append(c(edx,  5, 1,          "        EDX     5: Virtual guest idle state support"))
            self.out.append(c(edx,  6, 1,          "        EDX     6: Hypervisor sleep state support"))
            self.out.append(c(edx,  7, 1,          "        EDX     7: NUMA distance query support"))
            self.out.append(c(edx,  8, 1,          "        EDX     8: Timer frequency details available"))
            self.out.append(c(edx,  9, 1,          "        EDX     9: Synthetic machine check injection support"))
            self.out.append(c(edx, 10, 1,          "        EDX    10: Guest crash MSR support"))
            self.out.append(c(edx, 11, 1,          "        EDX    11: Debug MSR support"))
            self.out.append(c(edx, 12, 1,          "        EDX    12: NPIEP support"))
            self.out.append(c(edx, 13, 1,          "        EDX    13: Hypervisor disable support"))
            self.out.append(c(edx, 14, 1,          "        EDX    14: Extended GVA ranges for flush virtual address list available"))
            self.out.append(c(edx, 15, 1,          "        EDX    15: Hypercall output via XMM registers"))
            self.out.append(c(edx, 16, 1,          "        EDX    16: Virtual guest idle state"))
            self.out.append(c(edx, 17, 1,          "        EDX    17: Soft interrupt polling mode available"))
            self.out.append(c(edx, 18, 1,          "        EDX    18: Hypercall MSR lock available"))
            self.out.append(c(edx, 19, 1,          "        EDX    19: Direct synthetic timers support"))
            self.out.append(c(edx, 20, 1,          "        EDX    20: PAT register available for VSM"))
            self.out.append(c(edx, 21, 1,          "        EDX    21: BNDCFGS register available for VSM"))
            self.out.append(c(edx, 22, 1,          "        EDX    22: Reserved"))
            self.out.append(c(edx, 23, 1,          "        EDX    23: Synthetic time unhalted timer"))
            self.out.append(c(edx, 24, 1,          "        EDX    24: Reserved"))
            self.out.append(c(edx, 25, 1,          "        EDX    25: Reserved"))
            self.out.append(c(edx, 26, 1,          "        EDX    26: Intel Last Branch Record (LBR) feature"))
            self.out.append(c(edx, 27, 1,          "        EDX 31-27: Reserved"))
        elif id == 0x40000004:
            self.out.append("Hypervisor implementation recommendations")
            self.out.append(c(eax,  0, 1,          "        EAX     0: Hypercall for address space switches"))
            self.out.append(c(eax,  1, 1,          "        EAX     1: Hypercall for local TLB flushes"))
            self.out.append(c(eax,  2, 1,          "        EAX     2: Hypercall for remote TLB flushes"))
            self.out.append(c(eax,  3, 1,          "        EAX     3: MSRs for accessing APIC registers"))
            self.out.append(c(eax,  4, 1,          "        EAX     4: Hypervisor MSR for system RESET"))
            self.out.append(c(eax,  5, 1,          "        EAX     5: Relaxed timing"))
            self.out.append(c(eax,  6, 1,          "        EAX     6: DMA remapping"))
            self.out.append(c(eax,  7, 1,          "        EAX     7: Interrupt remapping"))
            self.out.append(c(eax,  8, 1,          "        EAX     8: x2APIC MSRs"))
            self.out.append(c(eax,  9, 1,          "        EAX     9: Deprecating AutoEOI"))
            self.out.append(c(eax, 10, 1,          "        EAX    10: Hypercall for SyntheticClusterIpi"))
            self.out.append(c(eax, 11, 1,          "        EAX    11: Interface ExProcessorMasks"))
            self.out.append(c(eax, 12, 1,          "        EAX    12: Nested Hyper-V partition"))
            self.out.append(c(eax, 13, 1,          "        EAX    13: INT for MBEC system calls"))
            self.out.append(c(eax, 14, 1,          "        EAX    14: Enlightenment VMCS interface"))
            self.out.append(c(eax, 15, 1,          "        EAX    15: Synced timeline"))
            self.out.append(c(eax, 16, 1,          "        EAX    16: Reserved"))
            self.out.append(c(eax, 17, 1,          "        EAX    17: Direct local flush entire"))
            self.out.append(c(eax, 18, 1,          "        EAX    18: No architectural core sharing"))
            self.out.append(c(eax, 19, 0x1fff,     "        EAX 31-19: Reserved"))
        elif id == 0x40000006:
            self.out.append("Hypervisor hardware features enable")
            self.out.append(c(eax,  0, 1,          "        EAX     0: APIC overlay assist"))
            self.out.append(c(eax,  1, 1,          "        EAX     1: MSR bitmaps"))
            self.out.append(c(eax,  2, 1,          "        EAX     2: Architectural performance counters"))
            self.out.append(c(eax,  3, 1,          "        EAX     3: Second-level address translation"))
            self.out.append(c(eax,  4, 1,          "        EAX     4: DMA remapping"))
            self.out.append(c(eax,  5, 1,          "        EAX     5: Interrupt remapping"))
            self.out.append(c(eax,  6, 1,          "        EAX     6: Memory patrol scrubber"))
            self.out.append(c(eax,  7, 1,          "        EAX     7: DMA protection"))
            self.out.append(c(eax,  8, 1,          "        EAX     8: HPET"))
            self.out.append(c(eax,  9, 1,          "        EAX     9: Volatile synthetic timers"))
            self.out.append(c(eax, 10, 0x3fffff,   "        EAX 31-10: Reserved"))
        elif id == 0x40000007:
            self.out.append("Hypervisor CPU management features")
            self.out.append(c(eax,  0, 1,          "        EAX     0: Start logical processor"))
            self.out.append(c(eax,  1, 1,          "        EAX     1: Create root virtual processor"))
            self.out.append(c(eax,  2, 1,          "        EAX     2: Performance counter sync"))
            self.out.append(c(eax,  3, 0x1fffffff, "        EAX 31- 3: Reserved"))
            self.out.append(c(ebx,  0, 1,          "        EBX     0: Processor power management"))
            self.out.append(c(ebx,  1, 1,          "        EBX     1: MWAIT idle states"))
            self.out.append(c(ebx,  2, 1,          "        EBX     2: Logical processor idling"))
            self.out.append(c(ebx,  3, 0x1fffffff, "        EBX 31- 3: Reserved"))
            self.out.append(c(ecx,  0, 1,          "        ECX     0: Remap guest uncached"))
            self.out.append(c(ecx,  1, 0x7fffffff, "        ECX 31- 1: Reserved"))
        elif id == 0x40000008:
            self.out.append("Hypervisor shared virtual memory (SVM) features")
            self.out.append(c(eax,  0, 1,          "        EAX     0: SVM (Shared Virtual Memory)"))
            self.out.append(c(eax,  1, 0x7fffffff, "        EAX 31- 1: Reserved"))
        elif id == 0x40000009:
            self.out.append("Nested hypervisor feature identification")
            self.out.append(c(eax,  0, 1,          "        EAX     0: Reserved"))
            self.out.append(c(eax,  1, 1,          "        EAX     1: Reserved"))
            self.out.append(c(eax,  2, 1,          "        EAX     2: Synthetic Timer"))
            self.out.append(c(eax,  3, 1,          "        EAX     3: Reserved"))
            self.out.append(c(eax,  4, 1,          "        EAX     4: Interrupt control registers"))
            self.out.append(c(eax,  5, 1,          "        EAX     5: Hypercall MSRs"))
            self.out.append(c(eax,  6, 1,          "        EAX     6: VP index MSR"))
            self.out.append(c(eax,  7, 0x1f,       "        EAX 11- 7: Reserved"))
            self.out.append(c(eax, 12, 1,          "        EAX    12: Reenlightenment controls"))
            self.out.append(c(eax, 13, 0x7ffff,    "        EAX 31-13: Reserved"))
            self.out.append(c(edx,  0, 0xf,        "        EDX  3- 0: Reserved"))
            self.out.append(c(eax,  4, 1,          "        EDX     4: Hypercall input params via XMM registers"))
            self.out.append(c(edx,  5, 0x3ff,      "        EDX 14- 5: Reserved"))
            self.out.append(c(edx, 15, 1,          "        EDX    15: Hypercall output via XMM registers"))
            self.out.append(c(edx, 16, 1,          "        EDX    16: Reserved"))
            self.out.append(c(edx, 17, 1,          "        EDX    17: Soft interrupt polling mode available"))
            self.out.append(c(edx, 18, 0x3fff,     "        EDX 31-18: Reserved"))
        elif id == 0x4000000a:
            self.out.append("Nested hypervisor feature identification")
            self.out.append(c(eax,  0, 0x1ffff,    "        EAX 16- 0: Reserved"))
            self.out.append(c(eax, 17, 1,          "        EAX    17: Direct virtual flush hypercalls"))
            self.out.append(c(eax, 18, 1,          "        EAX    18: Flush GPA space and list hypercalls"))
            self.out.append(c(eax, 19, 1,          "        EAX    19: Enlightened MSR bitmaps"))
            self.out.append(c(eax, 20, 1,          "        EAX    20: Combining virtualization exceptions in page fault exception class"))
            self.out.append(c(eax, 21, 0x7ff,      "        EAX 31-21: Reserved"))
        elif id == 0x40000010:
            self.out.append("Hypervisor timing information")
            self.out.append("eax: (Virtual) TSC frequency in kHz")
            self.out.append("ebx: (Virtual) Bus (local apic timer) frequency in kHz")
            self.out.append("ecx,edx: Reserved")
        elif id == 0x80000000:
            self.out.append("eax: Maximum Input Value for Extended Function CPUID Information")
            self.out.append("ebx,ecx,edx: Reserved")
        elif id == 0x80000001:
            self.out.append("eax,ebx: Extended Processor Signature")
            self.out.append("edx,ecx: Extended Processor Feature")
            self.out.append(c(edx,  0, 1,          "        EDX     0: FPU (Floating Point Unit on-chip)"))
            self.out.append(c(edx,  1, 1,          "        EDX     1: VME (Virtual 8086 Mode Enhancements)"))
            self.out.append(c(edx,  2, 1,          "        EDX     2: DE (Debugging Extensions)"))
            self.out.append(c(edx,  3, 1,          "        EDX     3: PSE (Page Size Extension)"))
            self.out.append(c(edx,  4, 1,          "        EDX     4: TSC (Time Stamp Counter)"))
            self.out.append(c(edx,  5, 1,          "        EDX     5: MSR (Model Specific Registers RDMSR and WRMSR instructions)"))
            self.out.append(c(edx,  6, 1,          "        EDX     6: PAE (Physical Address Extension)"))
            self.out.append(c(edx,  7, 1,          "        EDX     7: MCE (Machine Check Exception)"))
            self.out.append(c(edx,  8, 1,          "        EDX     8: CX8 (CMPXCHG8B instruction)"))
            self.out.append(c(edx,  9, 1,          "        EDX     9: APIC (APIC on-chip)"))
            self.out.append(c(edx, 10, 1,          "        EDX    10: Reserved"))
            self.out.append(c(edx, 11, 1,          "        EDX    11: (Intel) SEP (SYSENTER and SYSEXIT instructions)"))
            self.out.append(c(edx, 11, 1,          "        EDX    11: (AMD) SYSCALL (SYSCALL and SYSRET instructions)"))
            self.out.append(c(edx, 12, 1,          "        EDX    12: MTRR (Memory Type Range Registers)"))
            self.out.append(c(edx, 13, 1,          "        EDX    13: PGE (Page Global Bit)"))
            self.out.append(c(edx, 14, 1,          "        EDX    14: MCA (Machine Check Architecture)"))
            self.out.append(c(edx, 15, 1,          "        EDX    15: CMOV (Conditional MOVe instructions)"))
            self.out.append(c(edx, 16, 1,          "        EDX    16: PAT (Page Attribute Table)"))
            self.out.append(c(edx, 17, 1,          "        EDX    17: PSE-36 (36-Bit Page Size Extension)"))
            self.out.append(c(edx, 18, 1,          "        EDX    18: Reserved"))
            self.out.append(c(edx, 19, 1,          "        EDX    19: MP (MultiProcessing capable)"))
            self.out.append(c(edx, 20, 1,          "        EDX    20: (Intel) XD (No-execute page protection)"))
            self.out.append(c(edx, 20, 1,          "        EDX    20: (AMD) NX (No-execute page protection)"))
            self.out.append(c(edx, 21, 1,          "        EDX    21: Reserved"))
            self.out.append(c(edx, 22, 1,          "        EDX    22: MMX+ (MMX instruction extensions)"))
            self.out.append(c(edx, 23, 1,          "        EDX    23: MMX (Intel MMX technology)"))
            self.out.append(c(edx, 24, 1,          "        EDX    24: FXSR (FXSAVE and FXRSTOR instructions)"))
            self.out.append(c(edx, 25, 1,          "        EDX    25: FFXSR (Fast FXSAVE/FXRSTOR)"))
            self.out.append(c(edx, 26, 1,          "        EDX    26: P1GB (1GB Page support)"))
            self.out.append(c(edx, 27, 1,          "        EDX    27: RDTSCP (RDTSCP instruction)"))
            self.out.append(c(edx, 28, 1,          "        EDX    28: Reserved"))
            self.out.append(c(edx, 29, 1,          "        EDX    29: LM (Long Mode (EM64T))"))
            self.out.append(c(edx, 30, 1,          "        EDX    30: 3DNow!+ (3DNow! extended)"))
            self.out.append(c(edx, 31, 1,          "        EDX    31: 3DNow! (3DNow! instructions)"))
            self.out.append(c(ecx,  0, 1,          "        ECX     0: LAHF (LAHF/SAHF supported in 64-bit mode)"))
            self.out.append(c(ecx,  1, 1,          "        ECX     1: CMPL (Core Multi-Processing Legacy mode)"))
            self.out.append(c(ecx,  2, 1,          "        ECX     2: SVM (Secure Virtual Machine)"))
            self.out.append(c(ecx,  3, 1,          "        ECX     3: EAS (Extended APIC Space)"))
            self.out.append(c(ecx,  4, 1,          "        ECX     4: AMC8 (AltMovCr8; LOCK MOV CR0 means MOV CR8)"))
            self.out.append(c(ecx,  5, 1,          "        ECX     5: ABM (Advanced Bit Manipulation; LZCNT instruction)"))
            self.out.append(c(ecx,  6, 1,          "        ECX     6: SSE4A (SSE4A instructions)"))
            self.out.append(c(ecx,  7, 1,          "        ECX     7: MASSE (Mis-Aligned SSE Support)"))
            self.out.append(c(ecx,  8, 1,          "        ECX     8: PREFETCH (3DNow! PREFETCH/PREFETCHHW instructions)"))
            self.out.append(c(ecx,  9, 1,          "        ECX     9: OSVW (OS-Visible Workaround)"))
            self.out.append(c(ecx, 10, 1,          "        ECX    10: IBS (Instruction-Based Sampling)"))
            self.out.append(c(ecx, 11, 1,          "        ECX    11: XOP (eXtended OPeration)"))
            self.out.append(c(ecx, 12, 1,          "        ECX    12: SKINIT (SKINIT/STGI instructions)"))
            self.out.append(c(ecx, 13, 1,          "        ECX    13: WDT (WatchDog Timer)"))
            self.out.append(c(ecx, 14, 1,          "        ECX    14: Reserved"))
            self.out.append(c(ecx, 15, 1,          "        ECX    15: LWP (Light Weight Profiling)"))
            self.out.append(c(ecx, 16, 1,          "        ECX    16: FMA4 (4-operands FMA instructions)"))
            self.out.append(c(ecx, 17, 1,          "        ECX    17: TCE (Translation Cache Extension)"))
            self.out.append(c(ecx, 18, 1,          "        ECX    18: Reserved"))
            self.out.append(c(ecx, 19, 1,          "        ECX    19: MSR (Node ID MSR"))
            self.out.append(c(ecx, 20, 1,          "        ECX    20: Reserved"))
            self.out.append(c(ecx, 21, 1,          "        ECX    21: TBM (Trailing Bit Manipulation instructions)"))
            self.out.append(c(ecx, 22, 1,          "        ECX    22: TOPOEXT (TOPology EXTensions)"))
            self.out.append(c(ecx, 23, 1,          "        ECX    23: PERFCTR_CORE (CORE PERFormance CounTeR extensions)"))
            self.out.append(c(ecx, 24, 1,          "        ECX    24: PERFCTR_NB (NB PERFormance CounTeR extensions"))
            self.out.append(c(ecx, 25, 1,          "        ECX    25: Streaming performance monitor architecture"))
            self.out.append(c(ecx, 26, 1,          "        ECX    26: DBX (Data breakpoint eXtensions)"))
            self.out.append(c(ecx, 27, 1,          "        ECX    27: PERFTSC (PERFormance Time Stamp Counter)"))
            self.out.append(c(ecx, 28, 1,          "        ECX    28: PERFCTR_L2 (L2 PERFormance CounTeR extensions)"))
            self.out.append(c(ecx, 29, 1,          "        ECX    29: MONITORX/MWAITX instructions"))
            self.out.append(c(ecx, 30, 1,          "        ECX    30: Address mask extension for instruction breakpoint"))
            self.out.append(c(ecx, 31, 1,          "        ECX    31: Reserved"))
        elif id in [0x80000002, 0x80000003, 0x80000004]:
            vid = String.bytes2str(p32(eax) + p32(ebx) + p32(ecx) + p32(edx))
            self.out.append("eax+ebx+ecx+edx: Processor Brand String (={:s})".format(repr(vid)))
        elif id == 0x80000005:
            self.out.append("L1 Cache Information")
            self.out.append("eax: 4/2 MB L1 TLB configuration descriptor")
            self.out.append("ebx: 4 KB L1 TLB configuration descriptor")
            self.out.append("ecx: data L1 cache configuration descriptor")
            self.out.append("edx: code L1 cache configuration descriptor")
        elif id == 0x80000006:
            self.out.append("L2/L3 Cache Information")
            self.out.append("eax: 4/2 MB L2 TLB configuration descriptor")
            self.out.append("ebx: 4 KB L2 TLB configuration descriptor")
            self.out.append("ecx: unified L2 cache configuration descriptor")
            self.out.append("edx: unified L3 cache configuration descriptor")
        elif id == 0x80000007:
            self.out.append("ebx: RAS Capabilities")
            self.out.append(c(ebx,  0, 1,          "        EBX     0: MCA overflow recovery"))
            self.out.append(c(ebx,  1, 1,          "        EBX     1: Software uncorrectable error containment and recovery"))
            self.out.append(c(ebx,  2, 1,          "        EBX     2: HWA (HardWare Assert)"))
            self.out.append(c(ebx,  3, 1,          "        EBX     3: Scalable MCA"))
            self.out.append(c(ebx,  4, 1,          "        EBX     4: PFEH (Platform First Error Handling)"))
            self.out.append(c(ebx,  5, 0x7ffffff,  "        EBX 31- 5: Reserved"))
            self.out.append("edx: Advanced Power Management information")
            self.out.append(c(edx,  0, 1,          "        EDX     0: TS (Temperature Sensor)"))
            self.out.append(c(edx,  1, 1,          "        EDX     1: FID (Frequency ID control)"))
            self.out.append(c(edx,  2, 1,          "        EDX     2: VID (Voltage ID control)"))
            self.out.append(c(edx,  3, 1,          "        EDX     3: TTP (Thermal Trip)"))
            self.out.append(c(edx,  4, 1,          "        EDX     4: TM (Thermal Monitoring)"))
            self.out.append(c(edx,  5, 1,          "        EDX     5: STC (Software Thermal Control)"))
            self.out.append(c(edx,  6, 1,          "        EDX     6: MUL (100MHz Multiplier steps)"))
            self.out.append(c(edx,  7, 1,          "        EDX     7: HWPS (HardWare P-State control)"))
            self.out.append(c(edx,  8, 1,          "        EDX     8: ITSC (Invariant TSC)"))
            self.out.append(c(edx,  9, 1,          "        EDX     9: Core performance boost"))
            self.out.append(c(edx, 10, 1,          "        EDX    10: Read-only effective frequency interface"))
            self.out.append(c(edx, 11, 1,          "        EDX    11: Processor feedback interface"))
            self.out.append(c(edx, 12, 1,          "        EDX    12: Core power reporting"))
            self.out.append(c(edx, 13, 1,          "        EDX    13: Connected standby"))
            self.out.append(c(edx, 14, 1,          "        EDX    14: RAPL (Running Average Power Limit)"))
            self.out.append(c(edx, 15, 0x1ffff,    "        EAX 31-15: Reserved"))
        elif id == 0x80000008:
            self.out.append("eax: Extended Address Length Information")
            self.out.append(c(eax,  0, 0xff,       "        EAX  7- 0: Physical address length"))
            self.out.append(c(eax,  8, 0xff,       "        EAX 15- 8: Linear address length"))
            self.out.append(c(eax, 16, 0xff,       "        EAX 23-16: Guest physical address length"))
            self.out.append(c(eax, 24, 0xff,       "        EAX 31-24: Reserved"))
            self.out.append("ebx: Extended Feature Extensions ID")
            self.out.append(c(ebx,  0, 1,          "        EBX     0: CLZERO (CLZERO instruction)"))
            self.out.append(c(ebx,  1, 1,          "        EBX     1: IRPerf (Instructions Retired count support)"))
            self.out.append(c(ebx,  2, 1,          "        EBX     2: XSAVE always saves/restores error pointers"))
            self.out.append(c(ebx,  3, 1,          "        EBX     3: INVLPGB and TLBSYNC instruction"))
            self.out.append(c(ebx,  4, 1,          "        EBX     4: RDPRU (RDPRU instruction)"))
            self.out.append(c(ebx,  5, 1,          "        EBX     5: Reserved"))
            self.out.append(c(ebx,  6, 1,          "        EBX     6: MBE (Memory Bandwidth Enforcement)"))
            self.out.append(c(ebx,  7, 1,          "        EBX     7: Reserved"))
            self.out.append(c(ebx,  8, 1,          "        EBX     8: MCOMMIT (MCOMMIT instruction)"))
            self.out.append(c(ebx,  9, 1,          "        EBX     9: WBNOINVD (Write Back and do NOt INValiDate cache)"))
            self.out.append(c(ebx, 10, 1,          "        EBX    10: LBR extensions"))
            self.out.append(c(ebx, 11, 1,          "        EBX    11: Reserved"))
            self.out.append(c(ebx, 12, 1,          "        EBX    12: IBPB (Indirect Branch Prediction Barrier)"))
            self.out.append(c(ebx, 13, 1,          "        EBX    13: WBINVD (Write Back and INValiDate cache)"))
            self.out.append(c(ebx, 14, 1,          "        EBX    14: IBRS (Indirect Branch Restricted Speculation)"))
            self.out.append(c(ebx, 15, 1,          "        EBX    15: STIBP (Single Thread Indirect Branch Predictor)"))
            self.out.append(c(ebx, 16, 1,          "        EBX    16: Reserved"))
            self.out.append(c(ebx, 17, 1,          "        EBX    17: STIBP always on"))
            self.out.append(c(ebx, 18, 1,          "        EBX    18: IBRS preferred over software solution"))
            self.out.append(c(ebx, 19, 1,          "        EBX    19: IBRS provides Same Mode Protection"))
            self.out.append(c(ebx, 20, 1,          "        EBX    20: EFER.LMLSE is unsupported"))
            self.out.append(c(ebx, 21, 1,          "        EBX    21: INVLPGB for guest nested translations"))
            self.out.append(c(ebx, 22, 1,          "        EBX    22: Reserved"))
            self.out.append(c(ebx, 23, 1,          "        EBX    23: PPIN (Protected Processor Inventory Number)"))
            self.out.append(c(ebx, 24, 1,          "        EBX    24: SSBD (Speculative Store Bypass Disable)"))
            self.out.append(c(ebx, 25, 1,          "        EBX    25: VIRT_SPEC_CTL"))
            self.out.append(c(ebx, 26, 1,          "        EBX    26: SSBD no longer needed"))
            self.out.append(c(ebx, 27, 1,          "        EBX    27: CPPC (Collaborative Processor Performance Control)"))
            self.out.append(c(ebx, 28, 1,          "        EBX    28: PSFD (Predictive Store Forward Disable)"))
            self.out.append(c(ebx, 29, 1,          "        EBX    29: Reserved"))
            self.out.append(c(ebx, 30, 1,          "        EBX    30: Reserved"))
            self.out.append(c(ebx, 31, 1,          "        EBX    31: Reserved"))
            self.out.append("ecx: Extended Core Information")
            self.out.append(c(ecx,  0, 0xff,       "        ECX  7- 0: Number of cores per (number of dies-1)"))
            self.out.append(c(ecx,  8, 0xf,        "        ECX 11- 8: Reserved"))
            self.out.append(c(ecx, 12, 0xf,        "        ECX 15-12: Number of LSBs in APIC ID that indicate core ID"))
            self.out.append(c(ecx, 16, 0xffff,     "        ECX 31-16: Reserved"))
        elif id == 0x8000000a:
            self.out.append("SVM Revision and Feature Identification")
            self.out.append(c(edx,  0, 1,          "        EDX     0: Nested paging"))
            self.out.append(c(edx,  1, 1,          "        EDX     1: LBR virtualization"))
            self.out.append(c(edx,  2, 1,          "        EDX     2: SVM lock"))
            self.out.append(c(edx,  3, 1,          "        EDX     3: NRIP save"))
            self.out.append(c(edx,  4, 1,          "        EDX     4: MSR-based TSC rate control"))
            self.out.append(c(edx,  5, 1,          "        EDX     5: VMCB clean bits"))
            self.out.append(c(edx,  6, 1,          "        EDX     6: Flush by ASID"))
            self.out.append(c(edx,  7, 1,          "        EDX     7: Decode assists"))
            self.out.append(c(edx,  8, 1,          "        EDX     8: Reserved"))
            self.out.append(c(edx,  9, 1,          "        EDX     9: Reserved"))
            self.out.append(c(edx, 10, 1,          "        EDX    10: Pause intercept filter"))
            self.out.append(c(edx, 11, 1,          "        EDX    11: Encrypted micro-code patch"))
            self.out.append(c(edx, 12, 1,          "        EDX    12: PAUSE filter threshold"))
            self.out.append(c(edx, 13, 1,          "        EDX    13: AMD virtual interrupt controller"))
            self.out.append(c(edx, 14, 1,          "        EDX    14: Reserved"))
            self.out.append(c(edx, 15, 1,          "        EDX    15: Virtualized VMLOAD/VMSAVE"))
            self.out.append(c(edx, 16, 1,          "        EDX    16: Virtualized GIF"))
            self.out.append(c(edx, 17, 1,          "        EDX    17: GMET (Guest Mode Execution Trap"))
            self.out.append(c(edx, 18, 1,          "        EDX    18: Reserved"))
            self.out.append(c(edx, 19, 1,          "        EDX    19: SVM supervisor shadow stack restrictions"))
            self.out.append(c(edx, 20, 1,          "        EDX    20: SPEC_CTRL virtualization"))
            self.out.append(c(edx, 21, 1,          "        EDX    21: Reserved"))
            self.out.append(c(edx, 22, 1,          "        EDX    22: Reserved"))
            self.out.append(c(edx, 23, 1,          "        EDX    23: Host MCE override"))
            self.out.append(c(edx, 24, 1,          "        EDX    24: INVLPGB/TLBSYNC hypervisor enable"))
            self.out.append(c(edx, 25, 0x7f,       "        EDX 31-25: Reserved"))
        elif id == 0x80000019:
            self.out.append("TLB Configuration Descriptors")
        elif id == 0x8000001a:
            self.out.append("Performance Optimization Identifiers")
            self.out.append(c(eax,  0, 1,          "        EAX     0: FP128 (128-bit SSE full-width pipelines)"))
            self.out.append(c(eax,  1, 1,          "        EAX     1: MOVU (Efficient MOVU SSE instructions)"))
            self.out.append(c(eax,  2, 1,          "        EAX     2: FP256 (256-bit AVX full-width pipelines)"))
            self.out.append(c(eax,  3, 0x1fffffff, "        EAX 31- 3: Reserved"))
        elif id == 0x8000001b:
            self.out.append("Instruction Based Sampling Identifiers")
            self.out.append(c(eax,  0, 1,          "        EAX     0: IBSFFV (IBS Feature Flags Valid)"))
            self.out.append(c(eax,  1, 1,          "        EAX     1: FetchSam (IBS Fetch Sampling)"))
            self.out.append(c(eax,  2, 1,          "        EAX     2: OpSam (IBS Execution Sampling)"))
            self.out.append(c(eax,  3, 1,          "        EAX     3: RdWrOpCnt (Read/write of Op Counter)"))
            self.out.append(c(eax,  4, 1,          "        EAX     4: OpCnt (Op Counting mode)"))
            self.out.append(c(eax,  5, 1,          "        EAX     5: BrnTrgt (Branch Target address reporting)"))
            self.out.append(c(eax,  6, 1,          "        EAX     6: OpCntExt (IBS op cur/max count extended by 7 bits)"))
            self.out.append(c(eax,  7, 1,          "        EAX     7: RipInvalidChk (IBS RIP invalid indication)"))
            self.out.append(c(eax,  8, 1,          "        EAX     8: OpBrnFuse (IBS fused Branch micro-op indication)"))
            self.out.append(c(eax,  9, 1,          "        EAX     9: IbsFetchCtlExtd (IBS Fetch Control Extended MSR)"))
            self.out.append(c(eax, 10, 1,          "        EAX    10: IbsOpData4 (IBS Op Data 4 MSR)"))
            self.out.append(c(eax, 11, 0x1fffff,   "        EAX 31-11: Reserved"))
        elif id == 0x8fffffff:
            vid = String.bytes2str(p32(eax) + p32(ebx) + p32(ecx) + p32(edx))
            self.out.append("eax+ebx+ecx+edx: Easter egg (={:s})".format(repr(vid)))
        elif id == 0xc0000000:
            self.out.append("eax: Maximum Input Value for Extended Function CPUID Information")
            self.out.append("ebx,ecx,edx: Reserved")
        elif id == 0xc0000001:
            self.out.append("Centaur features")
            self.out.append(c(edx,  0, 1,          "        EDX     0: AIS (Alternate Instruction Set available)"))
            self.out.append(c(edx,  1, 1,          "        EDX     1: AIS_EN (Alternate Instruction Set ENabled)"))
            self.out.append(c(edx,  2, 1,          "        EDX     2: RNG (Random Number Generator available)"))
            self.out.append(c(edx,  3, 1,          "        EDX     3: RNG_EN (Random Number Generator ENabled)"))
            self.out.append(c(edx,  4, 1,          "        EDX     4: LH (LongHaul MSR 0000_110Ah)"))
            self.out.append(c(edx,  5, 1,          "        EDX     5: FEMMS"))
            self.out.append(c(edx,  6, 1,          "        EDX     6: ACE (Advanced Cryptography Engine available)"))
            self.out.append(c(edx,  7, 1,          "        EDX     7: ACE_EN (Advanced Cryptography Engine Enabled)"))
            self.out.append(c(edx,  8, 1,          "        EDX     8: ACE2 (Montgomery Multiplier and Hash Engine available)"))
            self.out.append(c(edx,  9, 1,          "        EDX     9: ACE2_EN (Montgomery Multiplier and Hash Engine Enabled)"))
            self.out.append(c(edx, 10, 1,          "        EDX    10: PHE (Padlock Hash Engine available)"))
            self.out.append(c(edx, 11, 1,          "        EDX    11: PHE_EN (Padlock Hash Engine ENabled)"))
            self.out.append(c(edx, 12, 1,          "        EDX    12: PMM (Padlock Montgomery Multiplier available)"))
            self.out.append(c(edx, 13, 1,          "        EDX    13: PMM_EN (Padlock Montgomery Multiplier ENabled)"))
            self.out.append(c(edx, 14, 0x3ffff,    "        EAX 31-14: Reserved"))
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr", "kgdb"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    @only_if_kvm_disabled
    def do_invoke(self, args):
        self.out = []

        # Basic Information
        eax, _, _, _ = self.execute_cpuid(0)
        valid_max_cpuid = min(eax, 0x20)

        for id in range(valid_max_cpuid + 1):
            if id == 4:
                for subid in range(3):
                    eax, ebx, ecx, edx = self.execute_cpuid(id, subid)
                    self.show_result(id, subid, eax, ebx, ecx, edx)
            elif id == 7:
                eax, _, _, _ = self.execute_cpuid(id, 0)
                for subid in range(eax + 1):
                    eax, ebx, ecx, edx = self.execute_cpuid(id, subid)
                    self.show_result(id, subid, eax, ebx, ecx, edx)
            elif id == 13:
                for subid in range(63):
                    eax, ebx, ecx, edx = self.execute_cpuid(id, subid)
                    self.show_result(id, subid, eax, ebx, ecx, edx)
            elif id in [16, 18, 19, 20, 23, 24, 26, 31]:
                eax, ebx, ecx, edx = self.execute_cpuid(id, 0)
                self.show_result(id, 0, eax, ebx, ecx, edx)
            else:
                eax, ebx, ecx, edx = self.execute_cpuid(id)
                self.show_result(id, None, eax, ebx, ecx, edx)

        # Hypervisor Information
        valid_max_cpuid, _, _, _ = self.execute_cpuid(0x40000000)
        for id in range(0x40000000, valid_max_cpuid + 1):
            eax, ebx, ecx, edx = self.execute_cpuid(id)
            self.show_result(id, None, eax, ebx, ecx, edx)

        # Extended Information
        valid_max_cpuid, _, _, _ = self.execute_cpuid(0x80000000)
        for id in range(0x80000000, valid_max_cpuid + 1):
            eax, ebx, ecx, edx = self.execute_cpuid(id)
            self.show_result(id, None, eax, ebx, ecx, edx)
        for id in [0x8fffffff]:
            eax, ebx, ecx, edx = self.execute_cpuid(id)
            self.show_result(id, None, eax, ebx, ecx, edx)

        # Transmeta Specific Information
        valid_max_cpuid, _, _, _ = self.execute_cpuid(0x80860000)
        for id in range(0x80860000, valid_max_cpuid + 1):
            eax, ebx, ecx, edx = self.execute_cpuid(id)
            self.show_result(id, None, eax, ebx, ecx, edx)

        # Centaur(VIA) Specific Information
        valid_max_cpuid, _, _, _ = self.execute_cpuid(0xc0000000)
        for id in range(0xc0000000, valid_max_cpuid + 1):
            eax, ebx, ecx, edx = self.execute_cpuid(id)
            self.show_result(id, None, eax, ebx, ecx, edx)

        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class MsrCommand(GenericCommand):
    """Read or write MSR value."""
    _cmdline_ = "msr"
    _category_ = "04-a. Register - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("msr_target", metavar="MSR_NAME|MSR_CONST", nargs="?",
                        help="the MSR name or constant to know the value.")
    parser.add_argument("msr_value", metavar="MSR_VALUE", nargs="?", type=AddressUtil.parse_address,
                        help="the MSR value to update.")
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}                   # show frequently used MSRs\n".format(_cmdline_)
    _example_ += "{:s} 0xc0000080        # read msr\n".format(_cmdline_)
    _example_ += "{:s} MSR_EFER          # another valid format\n".format(_cmdline_)
    _example_ += "{:s} 0xc0000080 0xd01  # write msr".format(_cmdline_)

    _note_ = "Disable`-enable-kvm` option for qemu-system."

    msr_table = [
        # frequently used x86-64 MSRs
        ["MSR_EFER",              0xc0000080, "Extended feature register"],
        ["MSR_STAR",              0xc0000081, "Legacy mode SYSCALL target"],
        ["MSR_LSTAR",             0xc0000082, "Long mode SYSCALL target"],
        ["MSR_CSTAR",             0xc0000083, "Compat mode SYSCALL target"],
        ["MSR_SYSCALL_MASK",      0xc0000084, "EFLAGS mask for syscall"],
        ["MSR_FS_BASE",           0xc0000100, "64bit FS base"],
        ["MSR_GS_BASE",           0xc0000101, "64bit GS base"],
        ["MSR_KERNEL_GS_BASE",    0xc0000102, "SwapGS GS shadow"],
        ["MSR_TSC_AUX",           0xc0000103, "Auxiliary TSC"],
        # x86-32 and x86-64
        ["MSR_IA32_SYSENTER_CS",  0x00000174, "Sysenter CS"],
        ["MSR_IA32_SYSENTER_ESP", 0x00000175, "Sysenter ESP"],
        ["MSR_IA32_SYSENTER_EIP", 0x00000176, "Sysenter EIP"],
        ["MSR_IA32_U_CET",        0x000006a0, "User mode CET"],
        ["MSR_IA32_S_CET",        0x000006a2, "Kernel mode CET"],
        ["MSR_IA32_PL0_SSP",      0x000006a4, "Ring-0 shadow stack pointer"],
        ["MSR_IA32_PL1_SSP",      0x000006a5, "Ring-1 shadow stack pointer"],
        ["MSR_IA32_PL2_SSP",      0x000006a6, "Ring-2 shadow stack pointer"],
        ["MSR_IA32_PL3_SSP",      0x000006a7, "Ring-3 shadow stack pointer"],
        ["MSR_IA32_INT_SSP_TAB",  0x000006a8, "Exception shadow stack table"],
    ]

    def lookup_name2const(self, target_name):
        for name, const, _desc in self.msr_table:
            if name == target_name:
                return const
        try:
            return int(target_name, 0)
        except ValueError:
            return None

    def lookup_const2name(self, target_const):
        for name, const, _desc in self.msr_table:
            if const == target_const:
                return name
        return "Unknown"

    def print_const_table(self):
        gef_print(titlify("MSR table (Only frequently used)"))
        fmt = "{:30s}  {:10s}  {:30s}  {:s}"
        legend = ["Name", "Const", "Description", "Value"]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        for name, const, desc in self.msr_table:
            value = self.read_msr(const)
            sym = ""
            if is_valid_addr(value):
                sym = Symbol.get_symbol_string(value)
            gef_print("{:30s}  {:#010x}  {:30s}  {:s}{:s}".format(
                name, const, desc, AddressUtil.format_address(value), sym),
            )

        info("See more info: https://elixir.bootlin.com/linux/latest/source/arch/x86/include/asm/msr-index.h")
        return

    def read_msr(self, const):
        codes = [b"\x0f\x32"] # rdmsr
        if is_x86_64():
            regs = {"$rcx": const}
        else:
            regs = {"$ecx": const}
        ret = ExecAsm(codes, regs=regs).exec_code()

        if ret is None:
            return None

        if is_x86_64():
            edx = ret["reg"]["$rdx"] & 0xffffffff
            eax = ret["reg"]["$rax"] & 0xffffffff
        else:
            edx = ret["reg"]["$edx"]
            eax = ret["reg"]["$eax"]
        return ((edx << 32) | eax) & 0xffffffffffffffff

    def write_msr(self, const, value):
        codes = [b"\x0f\x30"] # wrmsr
        if is_x86_64():
            regs = {"$rcx": const, "$rdx": value >> 32, "$rax": value & 0xffffffff}
        else:
            regs = {"$ecx": const, "$edx": value >> 32, "$eax": value & 0xffffffff}
        ret = ExecAsm(codes, regs=regs).exec_code()
        return bool(ret)

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    @only_if_in_kernel
    @only_if_kvm_disabled
    def do_invoke(self, args):
        # list up
        if args.msr_target is None and args.msr_value is None:
            self.print_const_table()
            return

        # search const table
        const = self.lookup_name2const(args.msr_target)
        if const is None:
            self.usage()
            return

        if args.msr_value is None:
            # exec rdmsr
            value = self.read_msr(const)
            if value is None:
                err("Failed to read")
                return
            name = self.lookup_const2name(const)
            if args.quiet:
                gef_print("{:s}".format(AddressUtil.format_address(value)))
            else:
                gef_print("{:s} ({:#x}): {:s}".format(name, const, AddressUtil.format_address(value)))

        else:
            # exec wrmsr
            ret = self.write_msr(const, args.msr_value)
            if ret:
                info("Success to write")
            else:
                err("Failed to write")
        return


@register_command
class MteTagsCommand(GenericCommand):
    """Display the MTE tag for the specified address (only ARM64)."""
    _cmdline_ = "mte-tags"
    _category_ = "02-f. Process Information - Security"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="the start address to display the MTE tag.")
    parser.add_argument("count", metavar="COUNT", nargs="?", type=AddressUtil.parse_address,
                        help="repeat count for MTE tag displaying (every 16 bytes).")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("rr",))
    @only_if_specific_arch(arch=("ARM64",))
    def do_invoke(self, args):
        auxv = Auxv.get_auxiliary_values()
        HWCAP2_MTE = 1 << 18
        if auxv and "AT_HWCAP2" in auxv and (auxv["AT_HWCAP2"] & HWCAP2_MTE) == 0:
            err("MTE is unsupported")
            return

        codes = [b"\x00\x00\x60\xD9"] # ldg x0, [x0]
        count = args.count or 1
        for i in range(count):
            address = args.address + 16 * i
            if not is_valid_addr(address):
                break
            ret = ExecAsm(codes, regs={"$x0": address}).exec_code()
            tag = (ret["reg"]["$x0"] >> 56) & 0xff
            gef_print("{!s}: {:#04x} ({:#018x})".format(ProcessMap.lookup_address(address), tag, tag << 56))
        return


@register_command
class PacKeysCommand(GenericCommand):
    """Pretty-print PAC keys from qemu registers (only ARM64)."""
    _cmdline_ = "pac-keys"
    _category_ = "04-a. Register - View"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM64",))
    def do_invoke(self, args):
        for keyname in ["APIA", "APIB", "APDA", "APDB", "APGA"]:
            try:
                lo = get_register("{:s}KEYLO_EL1".format(keyname))
                hi = get_register("{:s}KEYHI_EL1".format(keyname))
                bs = " ".join(slicer(p64(lo).hex() + p64(hi).hex(), 2))
                gef_print("{:s}KEY: {:#018x} {:#018x} ({:s})".format(keyname, hi, lo, bs))
            except Exception:
                err("Failed to get the value of PAC keys")
                break
        return


class BitInfo:
    """Printing various bit information of the register"""

    def __init__(self, name, register_bit=None, bit_info=(), desc=None):
        self.name = name
        if register_bit is None:
            self.register_bit = current_arch.ptrsize * 8
        else:
            self.register_bit = register_bit
        self.description = desc

        # bit_info: [[bits, short_name, short_description, long_description], ...]
        self.bit_info = bit_info
        return

    @staticmethod
    def bits_split(x, bits):
        # split by 4bits. e.g.: 0bXXYYYY -> 0b00XX_YYYY
        out = ""
        for i in range(bits):
            if x & (1 << i):
                out = "1" + out
            else:
                out = "0" + out
            if i % 4 == 3:
                out = "_" + out
        return "0b" + out[1:]

    def print_value(self, regval, split=False):
        regname = Color.colorify(self.name, "bold red")
        value_str = Color.colorify_hex(regval, "bold yellow")
        if split:
            bit_split_str = BitInfo.bits_split(regval, self.register_bit)
            value_str += Color.colorify(" (={:s})".format(bit_split_str), "bold yellow")
        self.out.append("{:s} = {:s}".format(regname, value_str))
        return

    def print_description(self):
        if self.description:
            self.out.append(Color.colorify(self.description, "bold"))
        return

    def print_bitinfo(self, regval):
        # preprocess
        max_width_bits = 2 # default
        max_width_sym = 0
        max_width_val = 0
        bit_range_strs = []
        bit_values = []
        for bits, sym, *_ in self.bit_info:
            if isinstance(bits, range):
                bits = list(bits)

            # search max width for bit_ragne_string
            if isinstance(bits, int):
                b = "{:d}".format(bits)
                bit_range_strs.append(b)
            else:
                # e.g.: [11, 12, 0, 1, 2, 10] -> [0, 1, 2, 10, 11, 12]
                bits = sorted(bits)
                # e.g.: [0, 1, 2, 10, 11, 12] -> [[0, 1, 2], [10, 11, 12]]
                gr_bits = [list(g) for _, g in itertools.groupby(bits, key=lambda n, c=itertools.count(): n - next(c))] # noqa: B008

                tmp = []
                for gb in gr_bits:
                    if len(gb) == 1:
                        tmp.append("{:d}".format(gb[0]))
                    else:
                        tmp.append("{:d}-{:d}".format(gb[-1], gb[0]))
                bit_str = ",".join(tmp[::-1])
                bit_range_strs.append(bit_str)
                max_width_bits = max(max_width_bits, len(bit_str))

            # search max width for sym
            if sym:
                max_width_sym = max(max_width_sym, len(sym))

            # search max width for val
            if isinstance(bits, int):
                val = (regval & (1 << bits)) >> bits
                bit_values.append(val)
            else:
                val = 0
                for i, x in enumerate(bits):
                    val |= (regval & (1 << x)) >> (x - i)
                bit_values.append(val)
            max_width_val = max(max_width_val, len("{:#x}".format(val)))

        # here, preprocess is finieshed.
        # - max_width_bits
        # - max_width_sym
        # - max_width_val
        # - bit_range_strs # e.g.: ["0", "4-1", "8-7,5"]
        # - bit_values     # e.g.: [0b1, 0b1111, 0b1101]

        # actual perform
        for i, (_, sym, *desc) in enumerate(self.bit_info):
            b = bit_range_strs[i]
            val = bit_values[i]

            msg = "bit{:>{:d}s}: ".format(b, max_width_bits)

            if val:
                msg += Color.colorify("{:>#{:d}x} ".format(val, max_width_val), "bold")
            else:
                msg += "{:>#{:d}x} ".format(val, max_width_val)

            if sym is not None:
                msg += "{:{:d}s}  ".format(sym, max_width_sym)

            if len(desc) == 1:
                # short description only
                if desc[0]:
                    msg += desc[0]

            elif len(desc) >= 2:
                # short description and long description
                if desc[0]:
                    msg += desc[0] + "; "
                msg += "; ".join(desc[1:])

            self.out.append(msg)
        return

    def make_out(self, regval, split=False):
        self.out = []
        self.print_value(regval, split)
        self.print_description()
        self.print_bitinfo(regval)
        return self.out

    def print(self, regval, split=False):
        self.make_out(regval, split)
        if self.out:
            gef_print("\n".join(self.out))
        return


@register_command
class QemuRegistersCommand(GenericCommand, BufferingOutput):
    """Get registers via qemu-monitor and shows the detail of x64/x86 system registers."""
    _cmdline_ = "qreg"
    _category_ = "08-a. Qemu-system Cooperation - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-v", "--verbose", action="store_true", help="also display detailed bit information.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def qregisters_x86_x64(self):
        red = lambda x: Color.colorify(x, "bold red")
        yellow = lambda x: Color.colorify(x, "bold yellow")

        # CR0
        self.out.append(titlify("CR0 (Control Register 0)"))
        desc = "It contains system control flags that control operating mode and states of the processor"
        bit_info = [
            [31, "PG", "Paging", "If 1, enable paging and use CR3 register, else disable paging"],
            [30, "CD", "Cache disable", "If 1, disable the memory cache globally"],
            [29, "NW", "Not-write through", "If 1, disable write-through caching globally"],
            [18, "AM", "Alignment mask", "If 1, alignment check enabled when EFLAGS.AC==1 and Ring-3"],
            [16, "WP", "Write protect", "If 1, the CPU can't write to read-only pages when Ring-0"],
            [5, "NE", "Numeric error", "If 1, enable internal x87 FPU error reporting, else enable PC style x87 error detection"],
            [4, "ET", "Extension type", "x64: always 1. i386: if 1, x87 DX math coprosessor instructions is supported"],
            [3, "TS", "Task switched", "If 1, allow the saving x87 task context upon a task switch only after x87 instruction used"],
            [2, "EM", "Emulation", "If 1, no x87 FPU present, else x87 FPU present"],
            [1, "MP", "Monitor co-processor", "If 1, WAIT/FWAIT instructions generate #NM exception when CR0.TS"],
            [0, "PE", "Protected mode enable", "If 1, system is in protected mode, else system is in real mode"],
        ]
        cr0 = get_register("cr0", use_monitor=True)
        self.out.extend(BitInfo("CR0", 32, bit_info, desc).make_out(cr0))

        # CR1
        self.out.append(titlify("CR1 (Control Register 1)"))
        self.out.append("Reserved")

        # CR2
        self.out.append(titlify("CR2 (Control Register 2)"))
        desc = "When page fault, the address attempted to access is stored (PFLA: Page Fault Linear Address)"
        cr2 = get_register("cr2", use_monitor=True)
        self.out.extend(BitInfo("CR2", desc=desc).make_out(cr2))

        # CR3
        self.out.append(titlify("CR3 (Control Register 3)"))
        desc = "It contains the physical address of the base of the paging-structure hierarchy and two flags"
        bit_info = [
            [range(12, 32), None, None, "Base of page directory base, typically it points to PML4T if 4-level paging"],
            [range(0, 12), None, None, "Process context identifier when CR4.PCIDE=1"],
            [4, "PCD", "Page-level Cache Disable", "If 1, disable Page-Directory itself caching when CR4.PCIDE=0"],
            [3, "PWT", "Page-level Write-Through", "If 1, enable write through Page-Directory itself caching when CR4.PCIDE=0"],
        ]
        cr3 = get_register("cr3", use_monitor=True)
        self.out.extend(BitInfo("CR3", bit_info=bit_info, desc=desc).make_out(cr3))

        # CR4
        self.out.append(titlify("CR4 (Control Register 4)"))
        desc = "It contains flags that enable some architectural extensions, and indicate OS or executive support for specific processor capabilities"
        bit_info = [
            [25, "UINTR", "Enable user-mode inter-processor interrupts", "If 1, enable User-Interrupt Delivery"],
            [24, "PKS", "Enable protection keys for supervisor-mode pages", "If 1, enable PKS"],
            [23, "CET", "Control-flow Enforcement Technology", "If 1, enable CET"],
            [22, "PKE", "Protection Key Enable", "If 1, enable PKE"],
            [21, "SMAP", "Supervisor Mode Access Protection Enable", "If 1, access of data in a higher ring generates a fault"],
            [20, "SMEP", "Supervisor Mode Execution Protection Enable", "If 1, execution of code in a higher ring generates a fault"],
            [19, "KL", "Key-Locker Enable", "If 1, enable LOADIWKEY"],
            [18, "OSXSAVE", "Enable XSAVE and Processor Extended States", "If 1, enable XSAVE/XSAVEC/XSAVEOPT/XSAVES/XRSTOR/XRSTORS/XSETBV/XGETBV"],
            [17, "PCIDE", "PCID Enable", "If 1, enable process-context identifiers (PCIDs)"],
            [15, "FSGSBASE", "FSGSBASE Enable", "If 1, enable RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE"],
            [14, "SMXE", "Safer Mode Extensions Enable", "If 1, enable Trusted Execution Technology (TXT)"],
            [13, "VMXE", "Virtual Machine Extensions Enable", "If 1, enable Intel VT-x x86 virtualization"],
            [12, "LA57", "57bit linear addresses", "If 1, enable 5-Level Paging"],
            [11, "UMIP", "User-Mode Instruction Prevention", "If 1, SGDT/SIDT/SLDT/SMSW/STR instructions can only be executed in ring0"],
            [10, "OSXMMEXCPT", "OS support for Unmasked SIMD FP Exceptions", "If 1, enable unmasked SSE exceptions"],
            [9, "OSFXSR", "OS support for FXSAVE/FXRSTOR", "If 1, enable SSE instructions and fast FPU save & restore"],
            [8, "PCE", "Performance-Monitoring Counter enable", "If 1, RDPMC instruction can be executed at any privilege level"],
            [7, "PGE", "Page Global Enabled", "If 1, address translations (PDE or PTE records) may be shared between address spaces"],
            [6, "MCE", "Machine Check Exception", "If 1, enable machine check interrupts to occur"],
            [5, "PAE", "Physical Address Extension", "If 1, changes page table layout to translate 32bit virtaddr into 36bit physaddr"],
            [4, "PSE", "Page Size Extension", "If 1, page size is 4MB, else 4KB, this bit is ignored when PAE or x86-64 long mode"],
            [3, "DE", "Debugging Extensions", "If 1, enable debug register based breaks on I/O space access"],
            [2, "TSD", "Time Stamp Disable", "If 1, RDTSC instruction can only be executed in ring0"],
            [1, "PVI", "Protected-mode Virtual Interrupts", "If 1, enable support for the virtual interrupt flag (VIF) in protected mode"],
            [0, "VME", "Virtual 8086 Mode Extensions", "If 1, enable support for the virtual interrupt flag (VIF) in virtual-8086 mode"],
        ]
        cr4 = get_register("cr4", use_monitor=True)
        self.out.extend(BitInfo("CR4", bit_info=bit_info, desc=desc).make_out(cr4))

        # CR8
        self.out.append(titlify("CR8 (Control Register 8)"))
        desc = "Contain task priority level"
        bit_info = [
            [range(0, 4), "TPL", "Task Priority Level"],
        ]
        cr8 = get_register("cr8", use_monitor=True)
        if cr8 is not None: # only access x86 64-bit mode
            self.out.extend(BitInfo("CR8", bit_info=bit_info, desc=desc).make_out(cr8))

        # XCR0
        self.out.append(titlify("XCR0 (Extended Control Register 0)"))
        desc = "Contain task priority level"
        bit_info = [
            [19, "APX", "Extended GPRs (R16 through R31)"],
            [18, "AMX_TILEDATA", "Advanced Matrix Extensions Tile Data"],
            [17, "AMX_TILECFG", "Advanced Matrix Extensions Tile Config"],
            [16, "HWP", "Hardware P-states"],
            [15, "LBR", "Last branch record"],
            [14, "UINTR", "User interrupts"],
            [13, "HDC", "Hardware duty cycling"],
            [12, "CET_S", "Control-flow Enforcement Technology (CET) Supervisor State"],
            [11, "CET_U", "Control-flow Enforcement Technology (CET) User State"],
            [10, "PASID", "Processor Address Space ID (PASID) state"],
            [9, "PKRU", "XSAVE feature set can be used for PKRU register, which is part of the protection keys mechanism"],
            [8, "PT", "Processor Trace"],
            [7, "Hi16_ZMM", "AVX-512 enable, and XSAVE feature set can be used for the upper ZMM regs"],
            [6, "ZMM_Hi256", "AVX-512 enable, and XSAVE feature set can be used for upper-halves of the lower ZMM regs"],
            [5, "opmask", "AVX-512 enable, and XSAVE feature set can be used for AVX opmask, a.k.a. k0-k7 regs"],
            [4, "BNDCSR", "MPX enable, and XSAVE feature set can be used for BNDCFGU and BNDSTATUS regs"],
            [3, "BNDREG", "MPX enable, and XSAVE feature set can be used for BND0-3 regs"],
            [2, "AVX", "AVX enable, and XSAVE feature set can be used to manage YMM regs"],
            [1, "SSE", "XSAVE feature set enable for MXCSR and XMM regs"],
            [0, "X87", "x87 FPU/MMX State", "always 1"],
        ]
        xcr0 = get_register("xcr0", use_monitor=True)
        if xcr0 is not None:
            self.out.extend(BitInfo("XCR0", bit_info=bit_info, desc=desc).make_out(xcr0))

        # DR0-DR3
        self.out.append(titlify("DR0-DR3 (Debug Address Register 0-3)"))
        desc = "Contain linear addresses of up to 4 hardware breakpoints. If paging is enabled, they are translated to physical addresses"
        dr0 = get_register("dr0", use_monitor=True)
        dr1 = get_register("dr1", use_monitor=True)
        dr2 = get_register("dr2", use_monitor=True)
        dr3 = get_register("dr3", use_monitor=True)
        self.out.extend(BitInfo("DR0").make_out(dr0))
        self.out.extend(BitInfo("DR1").make_out(dr1))
        self.out.extend(BitInfo("DR2").make_out(dr2))
        self.out.extend(BitInfo("DR3", desc=desc).make_out(dr3))

        # DR4-DR5
        self.out.append(titlify("DR4-DR5 (Debug Register 4-5)"))
        self.out.append("Reserved")

        # DR6
        self.out.append(titlify("DR6 (Debug Status Register 6)"))
        desc = "It permits the debugger to determine which debug conditions have occurred"
        bit_info = [
            [16, "RTM", "restricted transactional memory", "If 0, the debug exception or breakpoint exception occurred inside an RTM region"],
            [15, "BT", "task switch", "If 1, the debug instruction resulted from a task switch where TSS.T of target task was set"],
            [14, "BS", "single step", "If 1, the debug exception was triggered by the single-step execution mode (enabled with EFLAGS.TF)"],
            [13, "BD", "debug register access detected", "If 1, the next instruction accesses one of the debug registers"],
            [3, "B3", "breakpoint condition detected", "If 1, breakpoint condition was met when a debug exception for DR3"],
            [2, "B2", "breakpoint condition detected", "If 1, breakpoint condition was met when a debug exception for DR2"],
            [1, "B1", "breakpoint condition detected", "If 1, breakpoint condition was met when a debug exception for DR1"],
            [0, "B0", "breakpoint condition detected", "If 1, breakpoint condition was met when a debug exception for DR0"],
        ]
        dr6 = get_register("dr6", use_monitor=True)
        self.out.extend(BitInfo("DR6", 32, bit_info, desc).make_out(dr6))

        # DR7
        self.out.append(titlify("DR7 (Debug Control Register 7)"))
        desc = "A local breakpoint bit deactivates on hardware task switches, while a global does not"
        bit_info = [
            [[30, 31], "LEN3", "Size of DR3 breakpoint"],
            [[28, 29], "R/W3", "Breakpoint conditions for DR3"],
            [[26, 27], "LEN2", "Size of DR2 breakpoint"],
            [[24, 25], "R/W2", "Breakpoint conditions for DR2"],
            [[22, 23], "LEN1", "Size of DR1 breakpoint"],
            [[20, 21], "R/W1", "Breakpoint conditions for DR1"],
            [[18, 19], "LEN0", "Size of DR0 breakpoint"],
            [[16, 17], "R/W0", "Breakpoint conditions for DR0"],
            [13, "GD", "General Detect enable"],
            [11, "RTM", "Restricted Transactional Memory"],
            [9, "GE", "Global Exact breakpoint"],
            [8, "LE", "Local Exact breakpoint"],
            [7, "G3", "Global DR3 breakpoint"],
            [6, "L3", "Local DR3 breakpoint"],
            [5, "G2", "Global DR2 breakpoint"],
            [4, "L2", "Local DR2 breakpoint"],
            [3, "G1", "Global DR1 breakpoint"],
            [2, "L1", "Local DR1 breakpoint"],
            [1, "G0", "Global DR0 breakpoint"],
            [0, "L0", "Local DR0 breakpoint"],
        ]
        dr7 = get_register("dr7", use_monitor=True)
        self.out.extend(BitInfo("DR7", bit_info=bit_info, desc=desc).make_out(dr7))

        # EFER
        self.out.append(titlify("EFER (Extended Feature Enable Register; MSR_EFER:0xc0000080)"))
        efer = get_register("efer", use_monitor=True)
        bit_info = [
            [21, "AIBRSE", "Automatic IBRS Enable"],
            [20, "UAIE", "Upper Address Ignore Enable"],
            [18, "INTWB", "Interruptible WBINVD/WBNOINVD Enable"],
            [17, "MCOMMIT", "MCOMMIT instruction Enable"],
            [15, "TCE", "Translation Cache Extension"],
            [14, "FFXSR", "Fast FXSAVE/FXRSTOR"],
            [13, "LMSLE", "Long Mode Segment Limit Enable"],
            [12, "SVME", "Secure Virtual Machine Enable"],
            [11, "NXE", "No-Execute Enable"],
            [10, "LMA", "Long Mode Active"],
            [8, "LME", "Long Mode Enable"],
            [4, "L2D", "L2 Cache Disable", "only AMD K6"],
            [3, "GEWBED", "Global EWBE# Disable", "only AMD K6"],
            [2, "SEWBED", "Speculative EWBE# Disable", "only AMD K6"],
            [1, "DPE", "Data Prefetch Enable", "only AMD K6"],
            [0, "SCE", "System Call Extensions"],
        ]
        self.out.extend(BitInfo("EFER", bit_info=bit_info).make_out(efer))

        # TR
        res = gdb.execute("monitor info registers", to_string=True)
        self.out.append(titlify("TR (Task Register)"))
        tr = re.search(r"TR\s*=\s*(\S+) (\S+) (\S+) (\S+)", res)
        trseg, base, limit, attr = [int(tr.group(i), 16) for i in range(1, 5)]
        self.out.append("{:s} = {:s}".format(red("TR"), yellow("{:#x}".format(trseg))))
        regv = Color.boldify("{:#x} (rpl:{:d},ti:{:d},index:{:d})".format(trseg, trseg & 0b11, (trseg >> 2) & 1, trseg >> 3))
        self.out.append("seg: {:s}: segment selector for TSS (Task State Segment)".format(regv))
        self.out.append("  base : {:s}: starting address of TSS".format(Color.boldify("{:#x}".format(base))))
        limit_c = Color.boldify("{:#x}".format(limit))
        self.out.append("  limit: {:s}: segment limit or fixed value(=__KERNEL_TSS_LIMIT x64:0x206f/x86:0x206b)".format(limit_c))
        self.out.append("  attr : {:s}: attribute".format(Color.boldify("{:#x}".format(attr))))

        # GDTR
        self.out.append(titlify("GDTR (Global Descriptor Table Register)"))
        gdtr = re.search(r"GDT\s*=\s*(\S+) (\S+)", res)
        base, limit = [int(gdtr.group(i), 16) for i in range(1, 3)]
        self.out.append("{:s} = {:s}:{:s}".format(red("GDTR"), yellow("{:#x}".format(base)), yellow("{:#x}".format(limit))))
        self.out.append("base : {:s}: starting address of GDT (Global Descriptor Table)".format(Color.boldify("{:#x}".format(base))))
        self.out.append("limit: {:s}: (size of GDT) - 1".format(Color.boldify("{:#x}".format(limit))))

        ret = gdb.execute("gdtinfo -q --only-gdt", to_string=True)
        self.out.append(ret.rstrip())

        # IDTR
        self.out.append(titlify("IDTR (Interrupt Descriptor Table Register)"))
        idtr = re.search(r"IDT\s*=\s*(\S+) (\S+)", res)
        base, limit = [int(idtr.group(i), 16) for i in range(1, 3)]
        self.out.append("{:s} = {:s}:{:s}".format(red("IDTR"), yellow("{:#x}".format(base)), yellow("{:#x}".format(limit))))
        self.out.append("base : {:s}: starting address of IDT (Interrupt Descriptor Table)".format(Color.boldify("{:#x}".format(base))))
        self.out.append("limit: {:s}: (size of IDT) - 1".format(Color.boldify("{:#x}".format(limit))))

        ret = gdb.execute("idtinfo -q", to_string=True)
        self.out.append(ret.rstrip())

        # LDTR
        self.out.append(titlify("LDTR (Local Descriptor Table Register)"))
        ldtr = re.search(r"LDT\s*=\s*(\S+) (\S+) (\S+) (\S+)", res)
        seg, base, limit, attr = [int(ldtr.group(i), 16) for i in range(1, 5)]
        self.out.append("{:s} = {:s}".format(red("LDTR"), yellow("{:#x}".format(seg))))
        regv = Color.boldify("{:#x} (rpl:{:d},ti:{:d},index:{:d})".format(seg, seg & 0b11, (seg >> 2) & 1, seg >> 3))
        self.out.append("seg: {:s}: segment selector for LDT (Local Descriptor Table)".format(regv))
        self.out.append("  base : {:s}: starting address of LDT".format(Color.boldify("{:#x}".format(base))))
        self.out.append("  limit: {:s}: segment limit".format(Color.boldify("{:#x}".format(limit))))
        self.out.append("  attr : {:s}: attribute".format(Color.boldify("{:#x}".format(attr))))

        ret = gdb.execute("gdtinfo -q --only-ldt", to_string=True)
        self.out.append(ret.rstrip())
        return

    def qregisters(self):
        res = gdb.execute("monitor info registers", to_string=True).strip()
        self.out.append(titlify("info registers"))
        for line in res.splitlines():
            self.out.append(line)

        if is_x86():
            if not self.add_info:
                self.info("use `-v` for print Additional info")
            else:
                self.info("Additional info")
                self.qregisters_x86_x64()

        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "x86_16"))
    def do_invoke(self, args):
        self.add_info = args.verbose
        self.out = []
        self.qregisters()
        self.print_output(args)
        return


class PageMap:
    @staticmethod
    @Cache.cache_until_next
    def get_page_maps_by_pagewalk(command):
        return gdb.execute(command, to_string=True)

    @staticmethod
    @Cache.cache_until_next
    def get_page_maps_arm64_optee_secure_memory(verbose=False):
        # heuristic search of qemu-system memory
        sm = QemuMonitor.get_secure_memory_map(verbose)
        if sm is None:
            err("Not found secure memory maps")
            return None
        data = XSecureMemAddrCommand.read_secure_memory(sm, 0x0, sm.size, verbose)
        data_list = slice_unpack(data, 8)

        """
        enum teecore_memtypes {
            MEM_AREA_END = 0,
            MEM_AREA_TEE_RAM,
            MEM_AREA_TEE_RAM_RX,
            MEM_AREA_TEE_RAM_RO,
            MEM_AREA_TEE_RAM_RW,
            MEM_AREA_INIT_RAM_RO,
            MEM_AREA_INIT_RAM_RX,
            MEM_AREA_NEX_RAM_RO,
            MEM_AREA_NEX_RAM_RW,
            MEM_AREA_TEE_COHERENT,
            MEM_AREA_TEE_ASAN,
            MEM_AREA_IDENTITY_MAP_RX,
            MEM_AREA_TA_RAM,
            MEM_AREA_NSEC_SHM,
            MEM_AREA_RAM_NSEC,
            MEM_AREA_RAM_SEC,
            MEM_AREA_IO_NSEC,
            MEM_AREA_IO_SEC,
            MEM_AREA_EXT_DT,
            MEM_AREA_RES_VASPACE,
            MEM_AREA_SHM_VASPACE,
            MEM_AREA_TS_VASPACE,
            MEM_AREA_PAGER_VASPACE,
            MEM_AREA_SDP_MEM,
            MEM_AREA_DDR_OVERALL,
            MEM_AREA_SEC_RAM_OVERALL,
            MEM_AREA_MAXTYPE
        };
        struct tee_mmap_region {
            unsigned int type; /* enum teecore_memtypes */
            unsigned int region_size;
            paddr_t pa;
            vaddr_t va;
            size_t size;
            uint32_t attr; /* TEE_MATTR_* above */
        };
        """
        maps = []
        old_i = -1
        for i in range(len(data_list) - 4):
            type = data_list[i] & 0xffffffff
            if 26 < type: # enum teecore_memtypes
                continue
            region_size = (data_list[i] >> 32) & 0xffffffff
            if region_size & 0xfff or region_size < 0x1000 or 0xfffff000 < region_size:
                continue
            pa, va, size, attr = data_list[i + 1:i + 5]
            if pa & 0xfff or 0xfffff000 < pa:
                continue
            if va & 0xfff or 0xfffff000 < va:
                continue
            if size & 0xfff or size < 0x1000 or 0xfffff000 < size:
                continue
            if len(maps) > 0 and old_i + 5 != i: # Judging continuity
                continue
            maps.append([va, va + size, pa, pa + size])
            old_i = i
        if verbose:
            fmt = "{:37s}  {:37s}  {:12s}"
            legend = ["Virtual address start-end", "Physical address start-end", "Total size"]
            gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
            for va_start, va_end, pa_start, pa_end in maps:
                gef_print("{:#018x}-{:#018x}  {:#018x}-{:#018x}  {:<#12x}".format(
                    va_start, va_end, pa_start, pa_end, va_end - va_start,
                ))
        return maps

    @staticmethod
    def get_page_maps(FORCE_PREFIX_S, verbose=False):
        if is_arm64():
            if FORCE_PREFIX_S is True:
                return PageMap.get_page_maps_arm64_optee_secure_memory(verbose) # already parsed
            else:
                res = PageMap.get_page_maps_by_pagewalk("pagewalk 1 --quiet --no-pager --no-merge")
        else:
            if FORCE_PREFIX_S is None:
                res = PageMap.get_page_maps_by_pagewalk("pagewalk --quiet --no-pager --no-merge")
            elif FORCE_PREFIX_S is True:
                res = PageMap.get_page_maps_by_pagewalk("pagewalk -S --quiet --no-pager --no-merge")
            elif FORCE_PREFIX_S is False:
                res = PageMap.get_page_maps_by_pagewalk("pagewalk -s --quiet --no-pager --no-merge")
        res = sorted(set(res.splitlines()))
        res = list(filter(lambda line: line.endswith("]"), res))
        res = list(filter(lambda line: "[+]" not in line, res))
        maps = []
        for line in res:
            vrange, prange, *_ = line.split()
            vstart, vend = [int(x, 16) for x in vrange.split("-")]
            pstart, pend = [int(x, 16) for x in prange.split("-")]
            maps.append((vstart, vend, pstart, pend))
        if maps == []:
            if is_x86():
                warn("Make sure you are in ring0 (=kernel mode)")
            elif is_arm32():
                warn("Make sure you are in supervisor mode (=kernel mode)")
                warn("Make sure qemu 3.x or higher")
            elif is_arm64():
                warn("Make sure you are in EL1 (=kernel mode)")
                warn("Make sure qemu 3.x or higher")
            return None
        return maps

    @staticmethod
    def v2p_from_map(address, maps):
        for vstart, vend, pstart, _pend in maps:
            if vstart <= address < vend:
                offset = address - vstart
                paddr = pstart + offset
                return paddr
        return None

    @staticmethod
    def p2v_from_map(address, maps): # return list
        vaddrs = []
        for vstart, _vend, pstart, pend in maps:
            if pstart <= address < pend:
                offset = address - pstart
                vaddr = vstart + offset
                vaddrs.append(vaddr)
        return vaddrs


@register_command
class Virt2PhysCommand(GenericCommand):
    """Transfer from virtual address to physical address."""
    _cmdline_ = "v2p"
    _category_ = "08-a. Qemu-system Cooperation - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-S", dest="force_secure", action="store_true",
                       help="ARMv7: use TTBRn_ELm_S to parse start. ARMv8: heuristic search the memory of qemu-system.")
    group.add_argument("-s", dest="force_normal", action="store_true",
                       help="ARMv7/v8: use TTBRn_ELm to parse start.")
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="the address of data to translate.")
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="verbose output (for arm64 secure memory).")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0xffffffff855041e0".format(_cmdline_)

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    def do_invoke(self, args):
        FORCE_PREFIX_S = None
        if is_arm32() or is_arm64():
            if args.force_normal:
                FORCE_PREFIX_S = False
            elif args.force_secure:
                FORCE_PREFIX_S = True

        # do not use cache
        maps = PageMap.get_page_maps(FORCE_PREFIX_S, args.verbose)
        if maps is None:
            return
        paddr = PageMap.v2p_from_map(args.address, maps)
        if paddr is not None:
            gef_print("Virt: {:#x} -> Phys: {:#x}".format(args.address, paddr))
        return


@register_command
class Phys2VirtCommand(GenericCommand):
    """Transfer from physical address to virtual address."""
    _cmdline_ = "p2v"
    _category_ = "08-a. Qemu-system Cooperation - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-S", dest="force_secure", action="store_true",
                       help="ARMv7: use TTBRn_ELm_S to parse start. ARMv8: heuristic search the memory of qemu-system.")
    group.add_argument("-s", dest="force_normal", action="store_true",
                       help="ARMv7/v8: use TTBRn_ELm to parse start.")
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="the address of data to translate.")
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="verbose output (for arm64 secure memory).")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0x55041e0".format(_cmdline_)

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    def do_invoke(self, args):
        FORCE_PREFIX_S = None
        if is_arm32() or is_arm64():
            if args.force_normal:
                FORCE_PREFIX_S = False
            elif args.force_secure:
                FORCE_PREFIX_S = True

        # do not use cache
        maps = PageMap.get_page_maps(FORCE_PREFIX_S, args.verbose)
        if maps is None:
            return

        vaddrs = PageMap.p2v_from_map(args.address, maps)

        if args.verbose:
            loop_max = len(vaddrs)
        else:
            loop_max = min(len(vaddrs), 10)

        if loop_max == 0:
            gef_print("Not mapped as virt")
        else:
            for i in range(loop_max):
                gef_print("Phys: {:#x} -> Virt: {:#x}".format(args.address, vaddrs[i]))
            gef_print("Total {:d} results are found".format(len(vaddrs)))
        return


@register_command
class PagewalkCommand(GenericCommand, BufferingOutput):
    """The base command to get physical memory info via qemu-monitor."""
    _cmdline_ = "pagewalk"
    _category_ = "08-a. Qemu-system Cooperation - General"
    _aliases_ = ["pw", "ptdump", "pt"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("x64")
    subparsers.add_parser("x86")
    subparsers.add_parser("arm")
    subparsers.add_parser("arm64")
    _syntax_ = parser.format_help()

    def __init__(self, *args, **kwargs):
        prefix = kwargs.get("prefix", True)
        super().__init__(prefix=prefix)
        return

    def read_physmem_cache(self, paddr, size):
        key = "{:#x}_{:d}".format(paddr, size)
        if key in self.cache:
            return self.cache[key]
        out = read_physmem(paddr, size)
        self.cache[key] = out
        return out

    def add_out(self, msg):
        self.out.append(msg)
        return

    def quiet_info(self, msg):
        if not self.quiet:
            msg = "{} {}".format(Color.colorify("[+]", "bold blue"), msg)
            self.add_out(msg)
        return

    def quiet_add_out(self, msg):
        if not self.quiet:
            self.add_out(msg)
        return

    # merge pages that points same phys page
    def merge1(self, mappings):
        # for example, there are 16 pages,
        #    virt: 0xffffffff11107000  -> phys:0xabcd000
        #    virt: 0xffffffff11117000  -> phys;0xabcd000
        #    virt: 0xffffffff11127000  -> phys;0xabcd000
        #    ...
        #    virt: 0xffffffff111d7000  -> phys;0xabcd000
        #    virt: 0xffffffff111e7000  -> phys;0xabcd000
        #    virt: 0xffffffff111f7000  -> phys;0xabcd000
        # they will be merged by "*". type is changed from int to string.
        #    virt:"0xffffffff111*7000" -> phys:0xabcd000

        # group entries that refer to the same phys page
        tmp = {}
        for entry in mappings: # [virt_addr, phys_addr, page_size, page_count, flags]
            va, other = entry[0], tuple(entry[1:])
            if other not in tmp:
                tmp[other] = []
            tmp[other].append(va)

        # internal merge function
        def recursive_merge(d):
            if d == {}:
                return [""]
            out = []
            if len(d) == 16:
                tmp = list(d.values())
                if tmp.count(tmp[0]) == 16:
                    for vv in recursive_merge(tmp[0]):
                        out.append("*" + vv)
                    return out
            for k, v in d.items():
                for vv in recursive_merge(v):
                    out.append(k + vv)
            return out

        # merge if possible
        merged_mappings = []
        for other, va_array in tmp.items():
            # usually go through this path
            if len(va_array) < 16:
                for va in va_array:
                    merged_mappings.append(["{:016x}".format(va)] + list(other))
                continue

            # fast path for x64
            if len(va_array) == 0x10000:
                va_sorted = sorted([x >> 16 for x in va_array])
                if va_sorted[0] + 0xffff == va_sorted[-1]:
                    new_va_str = "{:016x}".format(va_array[0])
                    new_va_str = new_va_str[:8] + "****" + new_va_str[12:]
                    merged_mappings.append([new_va_str] + list(other))
                    continue

            # slow path
            queue = ["{:016x}".format(x) for x in va_array]
            # extract
            dic = {}
            for q in queue:
                for i in range(16):
                    dst = dic
                    src = dic
                    for j in range(i + 1):
                        src = src.get(q[j], {})
                        if j > 0:
                            dst = dst.get(q[j - 1], {})
                    dst[q[i]] = src

            # merge
            for d in recursive_merge(dic):
                merged_mappings.append([d] + list(other))

        # done
        return sorted(merged_mappings)

    # merge consecutive pages
    def merge2(self, mappings):
        merged_mappings = []
        prev = None
        for now in mappings: # [virt_addr_string, phys_addr, page_size, page_count, flags]
            # specific case
            if isinstance(now[0], str) and "*" in now[0]:
                if prev:
                    merged_mappings += [prev]
                merged_mappings += [now]
                prev = None
                continue

            # first loop case
            if prev is None:
                prev = now
                continue

            now_va = int(now[0], 16) if isinstance(now[0], str) else now[0]
            prev_va = int(prev[0], 16) if isinstance(prev[0], str) else prev[0]
            now_pa = int(now[1], 16) if isinstance(now[1], str) else now[1]
            prev_pa = int(prev[1], 16) if isinstance(prev[1], str) else prev[1]
            now_size = now[2]
            prev_size = prev[2]
            #now_cnt = now[3] # unused
            prev_cnt = prev[3]
            now_flags = now[4]
            prev_flags = prev[4]

            # check consecutiveness
            if self.simple:
                if prev_va + prev_size == now_va: # va consecutiveness
                    if prev_flags == now_flags: # flags equivalence
                        # ok, they are consecutive (at least virt_addr)
                        prev[2] += now[2]
                        # For simple mode, page_size is ignored.
                        # so we use entry[2] as total_size instead of page_size.
                        continue
            else:
                if prev_va + prev_size * prev_cnt == now_va: # va consecutiveness
                    if prev_pa + prev_size * prev_cnt == now_pa: # pa consecutiveness
                        if prev_size == now_size: # page_size equivalence
                            if prev_flags == now_flags: # flags equivalence
                                # ok, they are consecutive
                                prev[3] += 1 # prev_page_cnt update
                                continue

            merged_mappings += [prev]
            prev = now

        if prev:
            merged_mappings += [prev]

        return merged_mappings

    def vrange_filter(self, mappings):
        filtered_mappings = []
        for mapping in mappings:
            va, _, size, cnt = mapping[:4]
            if isinstance(va, str) and "*" in va:
                start = int(va.replace("*", "0"), 16)
                end = int(va.replace("*", "f"), 16)
                for addr in self.vrange:
                    if start <= addr < end + size * cnt:
                        filtered_mappings.append(mapping)
                        break
            else:
                if isinstance(va, str):
                    va = int(va, 16)
                for addr in self.vrange:
                    if va <= addr < va + size * cnt:
                        filtered_mappings.append(mapping)
                        break
        return sorted(filtered_mappings)

    def prange_filter(self, mappings):
        filtered_mappings = []
        for mapping in mappings:
            _, pa, size, cnt = mapping[:4]
            if isinstance(pa, str):
                pa = int(pa, 16)
            for addr in self.prange:
                if pa <= addr < pa + size * cnt:
                    filtered_mappings.append(mapping)
                    break
        return sorted(filtered_mappings)

    def format_legend(self):
        fmt = "{:37s}  {:37s}  {:12s} {:11s} {:6s} {:s}"
        legend = ["Virtual address start-end", "Physical address start-end", "Total size", "Page size", "Count", "Flags"]
        return fmt.format(*legend)

    def format_entry(self, entry):
        va, pa, size, cnt, flags = entry
        if isinstance(va, str) and "*" in va:
            vend = "{:016x}".format(int(va.replace("*", "0"), 16) + size * cnt)
            for pos in [x.span() for x in re.finditer(r"\*", va)]:
                vend = vend[:pos[0]] + "*" + vend[pos[1]:]
            pend = pa + size * cnt
            if self.simple:
                fmt = "0x{:16s}-0x{:16s}  {:37s}  {:<#12x} {:<11s} {:<6s} [{:s}]"
                text = fmt.format(va, vend, "-", size, "-", "-", flags)
            else:
                fmt = "0x{:16s}-0x{:16s}  {:#018x}-{:#018x}  {:<#12x} {:<#11x} {:<6d} [{:s}]"
                text = fmt.format(va, vend, pa, pend, size * cnt, size, cnt, flags)
        else:
            if isinstance(va, str):
                va = int(va, 16)
            vend = va + size * cnt
            pend = pa + size * cnt
            if self.simple:
                fmt = "{:#018x}-{:#018x}  {:37s}  {:<#12x} {:<11s} {:<6s} [{:s}]"
                text = fmt.format(va, vend, "-", size, "-", "-", flags)
            else:
                fmt = "{:#018x}-{:#018x}  {:#018x}-{:#018x}  {:<#12x} {:<#11x} {:<6d} [{:s}]"
                text = fmt.format(va, vend, pa, pend, size * cnt, size, cnt, flags)
        return text

    def merging(self):
        self.mappings = sorted(self.mappings)

        # merging
        if self.no_merge:
            pass
        else:
            if is_x86_64():
                self.mappings = self.merge1(self.mappings)
                self.quiet_info("PT Entry (merged similar pages that refer the same physpage): {:d}".format(len(self.mappings)))
            self.mappings = self.merge2(self.mappings)
            self.quiet_info("PT Entry (merged consecutive pages): {:d}".format(len(self.mappings)))
        return

    def make_out(self, mappings):
        if len(mappings) == 0:
            self.warn("No virtual mappings found")
            return

        filtered_mappings = mappings.copy()

        # filter by virtual address range
        if self.vrange != []:
            filtered_mappings = self.vrange_filter(filtered_mappings)
            self.quiet_info("PT Entry (filtered by virtual address range): {:d}".format(len(filtered_mappings)))

        # filter by physical address range
        if self.prange != []:
            filtered_mappings = self.prange_filter(filtered_mappings)
            self.quiet_info("PT Entry (filtered by physical address range): {:d}".format(len(filtered_mappings)))

        # create output
        lines = []
        for entry_info in filtered_mappings:
            line = self.format_entry(entry_info)
            lines.append(line)

        # filter by keyword
        if self.filter != []:
            filtered_lines = []
            for line in lines:
                for re_pattern in self.filter:
                    if re_pattern.search(line):
                        filtered_lines.append(line)
                        break
            lines = filtered_lines
            self.quiet_info("PT Entry (filtered by keyword): {:d}".format(len(lines)))

        # sort by phys
        if self.sort_by_phys:
            lines = sorted(lines, key=lambda x: x.split()[1])

        # check how many result
        if lines == []:
            self.warn("Nothing to display")
            return

        # add out
        self.out.append(titlify("Memory map"))
        self.out.append(Color.colorify(self.format_legend(), Config.get_gef_setting("theme.table_heading")))
        self.out.extend(lines)
        return

    def is_not_trace_target(self, va_start, va_end):
        if self.trace == []:
            return False
        for tr in self.trace:
            if va_start <= tr and tr < va_end:
                return False
        return True

    def is_not_filter_target(self, line):
        if self.filter == []:
            return False
        for re_pattern in self.filter:
            if re_pattern.search(line):
                return False
        return True

    # Need not @parse_args because argparse can't stop interpreting options for pagewalk sub-command.
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "x86_16", "ARM32", "ARM64"))
    def do_invoke(self, argv):
        if is_x86_32() or is_x86_16():
            gdb.execute("pagewalk x86 {}".format(" ".join(argv)))
        elif is_x86_64():
            gdb.execute("pagewalk x64 {}".format(" ".join(argv)))
        elif is_arm32():
            gdb.execute("pagewalk arm {}".format(" ".join(argv)))
        elif is_arm64():
            gdb.execute("pagewalk arm64 {}".format(" ".join(argv)))
        return


@register_command
class PagewalkX64Command(PagewalkCommand):
    """Dump pagetable for x64/x86 using qemu-monitor."""
    _cmdline_ = "pagewalk x64"
    _category_ = "08-a. Qemu-system Cooperation - General"
    _aliases_ = ["pagewalk x86"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-each-level", action="store_true", help="show all level pagetables.")
    parser.add_argument("--no-merge", action="store_true",
                        help="do not merge similar/consecutive address.")
    parser.add_argument("--sort-by-phys", action="store_true",
                        help="sort by physical address.")
    parser.add_argument("--simple", action="store_true",
                        help="merge with ignoring physical address consecutivness.")
    parser.add_argument("--filter", metavar="REGEX", type=re.compile, default=[], action="append",
                        help="filter by REGEX pattern.")
    parser.add_argument("--vrange", metavar="VADDR", default=[], action="append", type=lambda x: int(x, 16),
                        help="filter by map included specified virtual address.")
    parser.add_argument("--prange", metavar="PADDR", default=[], action="append", type=lambda x: int(x, 16),
                        help="filter by map included specified physical address.")
    parser.add_argument("--trace", metavar="VADDR", default=[], action="append", type=lambda x: int(x, 16),
                        help="show all level pagetables only associated specified address.")
    parser.add_argument("--include-kasan", action="store_true",
                        help="include KASAN shadow memory (sometimes heavy memory use).")
    parser.add_argument("-U", "--user-pt", action="store_true",
                        help="print userland pagetables (for KPTI, only x64, in kernel context).")
    parser.add_argument("--cr3", type=AddressUtil.parse_address, help="use specified value as cr3.")
    parser.add_argument("--cr4", type=AddressUtil.parse_address, help="use specified value as cr4.")
    parser.add_argument("-c", "--use-cache", action="store_true", help="use before result.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=False)
        self.mappings = None
        return

    def format_flags(self, flag_info):
        flag_info_key = tuple(flag_info)
        x = self.flags_strings_cache.get(flag_info_key, None)
        if x is not None:
            return x

        flags = []
        if "NO_RW" in flag_info:
            if "XD" in flag_info:
                flags += ["R--"]
            else:
                flags += ["R-X"]
        else:
            if "XD" in flag_info:
                flags += ["RW-"]
            else:
                flags += ["RWX"]
        if "NO_US" in flag_info:
            flags += ["KERN"]
        else:
            flags += ["USER"]

        if not self.simple:
            if "A" in flag_info:
                flags += ["ACCESSED"]
            if "D" in flag_info:
                flags += ["DIRTY"]
            if "G" in flag_info:
                flags += ["GLOBAL"]

        flag_string = " ".join(flags)
        self.flags_strings_cache[flag_info_key] = flag_string
        return flag_string

    def pagewalk_PML5T(self):
        self.quiet_add_out(titlify("PML5E: Page Map Level 5 Entry"))
        PML5E = []
        COUNT = 0
        for va_base, table_base, parent_flags in self.TABLES:
            entries = self.read_physmem_cache(table_base, 2 ** self.bits["PML5T_BITS"] * self.bits["ENTRY_SIZE"])
            entries = slice_unpack(entries, self.bits["ENTRY_SIZE"])
            COUNT += len(entries)
            for i, entry in enumerate(entries):
                # present flag
                if (entry & 1) == 0:
                    continue

                # calc virtual address
                b = self.bits["PML4T_BITS"] + self.bits["PDPT_BITS"] + self.bits["PDT_BITS"] + self.bits["PT_BITS"] + self.bits["OFFSET"]
                sign_ext = 0xfe00000000000000 if ((i >> (self.bits["PML5T_BITS"] - 1)) & 1) else 0
                new_va = va_base + (sign_ext | (i << b))
                new_va_end = new_va + (1 << b)

                # calc flags
                flags = parent_flags.copy()
                if ((entry >> 1) & 1) == 0:
                    flags.append("NO_RW")
                if ((entry >> 2) & 1) == 0:
                    flags.append("NO_US")
                if ((entry >> 5) & 1) == 1:
                    flags.append("A")
                if ((entry >> 63) & 1) == 1:
                    flags.append("XD")

                # calc next table (drop the flag bits)
                next_level_table = entry & 0x000ffffffffff000

                # make entry
                PML5E.append([new_va, next_level_table, flags])
                entry_type = "TABLE"

                # dump
                if self.print_each_level:
                    if self.is_not_trace_target(new_va, new_va_end):
                        continue
                    addr = table_base + i * self.bits["ENTRY_SIZE"]
                    fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                    line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                    if self.is_not_filter_target(line):
                        continue
                    self.add_out(line)

        self.quiet_info("Number of entries: {:d}".format(COUNT))
        self.quiet_info("PML5 Entry: {:d}".format(len(PML5E)))
        self.quiet_info("Invalid entries: {:d}".format(COUNT - len(PML5E)))
        self.TABLES = PML5E
        return

    def pagewalk_PML4T(self):
        self.quiet_add_out(titlify("PML4E: Page Map Level 4 Entry"))
        PML4E = []
        COUNT = 0
        for va_base, table_base, parent_flags in self.TABLES:
            entries = self.read_physmem_cache(table_base, 2 ** self.bits["PML4T_BITS"] * self.bits["ENTRY_SIZE"])
            entries = slice_unpack(entries, self.bits["ENTRY_SIZE"])
            COUNT += len(entries)
            for i, entry in enumerate(entries):
                # present flag
                if (entry & 1) == 0:
                    continue

                # calc virtual address
                b = self.bits["PDPT_BITS"] + self.bits["PDT_BITS"] + self.bits["PT_BITS"] + self.bits["OFFSET"]
                if "PML5T_BITS" in self.bits:
                    new_va = va_base + (i << b)
                    new_va_end = new_va + (1 << b)
                else:
                    sign_ext = 0xffff000000000000 if ((i >> (self.bits["PML4T_BITS"] - 1)) & 1) else 0
                    new_va = va_base + (sign_ext | (i << b))
                    new_va_end = new_va + (1 << b)

                # calc flags
                flags = parent_flags.copy()
                if ((entry >> 1) & 1) == 0:
                    flags.append("NO_RW")
                if ((entry >> 2) & 1) == 0:
                    flags.append("NO_US")
                if ((entry >> 5) & 1) == 1:
                    flags.append("A")
                if ((entry >> 63) & 1) == 1:
                    flags.append("XD")

                # calc next table (drop the flag bits)
                next_level_table = entry & 0x000ffffffffff000

                # make entry
                PML4E.append([new_va, next_level_table, flags])
                entry_type = "TABLE"

                # dump
                if self.print_each_level:
                    if self.is_not_trace_target(new_va, new_va_end):
                        continue
                    addr = table_base + i * self.bits["ENTRY_SIZE"]
                    fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                    line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                    if self.is_not_filter_target(line):
                        continue
                    self.add_out(line)

        self.quiet_info("Number of entries: {:d}".format(COUNT))
        self.quiet_info("PML4 Entry: {:d}".format(len(PML4E)))
        self.quiet_info("Invalid entries: {:d}".format(COUNT - len(PML4E)))
        self.TABLES = PML4E
        return

    def pagewalk_PDPT(self):
        self.quiet_add_out(titlify("PDPE: Page Directory Pointer Entry"))

        def is_set_PS(entry):
            return ((entry >> 7) & 1) == 1

        PDPTE = []
        PTE = []
        COUNT = 0
        for va_base, table_base, parent_flags in self.TABLES:
            entries = self.read_physmem_cache(table_base, 2 ** self.bits["PDPT_BITS"] * self.bits["ENTRY_SIZE"])
            entries = slice_unpack(entries, self.bits["ENTRY_SIZE"])
            COUNT += len(entries)
            for i, entry in enumerate(entries):
                # present flag
                if (entry & 1) == 0:
                    continue

                # calc virtual address
                new_va = va_base + (i << (self.bits["PDT_BITS"] + self.bits["PT_BITS"] + self.bits["OFFSET"]))
                new_va_end = new_va + (1 << (self.bits["PDT_BITS"] + self.bits["PT_BITS"] + self.bits["OFFSET"]))

                # calc flags
                flags = parent_flags.copy()
                if is_x86_64():
                    if ((entry >> 1) & 1) == 0:
                        flags.append("NO_RW")
                    if ((entry >> 2) & 1) == 0:
                        flags.append("NO_US")
                    if ((entry >> 5) & 1) == 1:
                        flags.append("A")
                    if is_set_PS(entry) and ((entry >> 6) & 1) == 1:
                        flags.append("D")
                    if is_set_PS(entry) and ((entry >> 8) & 1) == 1:
                        flags.append("G")
                    if ((entry >> 63) & 1) == 1:
                        flags.append("XD")
                else: # x86_32 and PAE
                    pass

                # calc next table (drop the flag bits)
                if is_x86_64() and is_set_PS(entry):
                    next_level_table = entry & 0x000fffffffffe000
                else:
                    next_level_table = entry & 0x000ffffffffff000

                # make entry
                if is_set_PS(entry):
                    virt_addr = new_va
                    phys_addr = next_level_table
                    page_size = 1 * 1024 * 1024 * 1024
                    page_count = 1
                    PTE.append([virt_addr, phys_addr, page_size, page_count, self.format_flags(flags)])
                    entry_type = "1GB-PAGE"
                else:
                    PDPTE.append([new_va, next_level_table, flags])
                    entry_type = "TABLE"

                # dump
                if self.print_each_level:
                    if self.is_not_trace_target(new_va, new_va_end):
                        continue
                    addr = table_base + i * self.bits["ENTRY_SIZE"]
                    fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                    line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                    if self.is_not_filter_target(line):
                        continue
                    self.add_out(line)

        self.quiet_info("Number of entries: {:d}".format(COUNT))
        self.quiet_info("PDPT Entry: {:d}".format(len(PDPTE)))
        self.quiet_info("PT Entry (1GB): {:d}".format(len(PTE)))
        self.quiet_info("Invalid entries: {:d}".format(COUNT - len(PDPTE) - len(PTE)))
        self.TABLES = PDPTE
        self.PTE += PTE
        return

    def pagewalk_PDT(self):
        self.quiet_add_out(titlify("PDE: Page Directory Entry"))

        def is_set_PS(entry):
            return ((entry >> 7) & 1) == 1

        PDE = []
        PTE = []
        COUNT = 0
        for va_base, table_base, parent_flags in self.TABLES:
            entries = self.read_physmem_cache(table_base, 2 ** self.bits["PDT_BITS"] * self.bits["ENTRY_SIZE"])
            entries = slice_unpack(entries, self.bits["ENTRY_SIZE"])
            COUNT += len(entries)

            if not self.include_kasan:
                if len({e & ~0b111 for e in entries}) == 1:
                    continue

            for i, entry in enumerate(entries):
                # present flag
                if (entry & 1) == 0:
                    continue

                # calc virtual address
                new_va = va_base + (i << (self.bits["PT_BITS"] + self.bits["OFFSET"]))
                new_va_end = new_va + (1 << (self.bits["PT_BITS"] + self.bits["OFFSET"]))

                # calc flags
                flags = parent_flags.copy()
                if ((entry >> 1) & 1) == 0:
                    flags.append("NO_RW")
                if ((entry >> 2) & 1) == 0:
                    flags.append("NO_US")
                if ((entry >> 5) & 1) == 1:
                    flags.append("A")
                if is_set_PS(entry) and ((entry >> 6) & 1) == 1:
                    flags.append("D")
                if is_set_PS(entry) and ((entry >> 8) & 1) == 1:
                    flags.append("G")
                if self.PAE and ((entry >> 63) & 1) == 1:
                    flags.append("XD")

                # calc next table (drop the flag bits)
                if is_x86_64() and is_set_PS(entry):
                    next_level_table = entry & 0x000fffffffffe000
                elif is_x86_32() and is_set_PS(entry):
                    high = (entry >> 13) & 0xf
                    low = (entry >> 22) & 0x3ff
                    next_level_table = ((high << 10) | low) << 22
                else:
                    next_level_table = entry & 0x000ffffffffff000

                # make entry
                if is_set_PS(entry):
                    virt_addr = new_va
                    phys_addr = next_level_table
                    if self.PAE:
                        page_size = 2 * 1024 * 1024
                        entry_type = "2MB-PAGE"
                    else:
                        page_size = 4 * 1024 * 1024
                        entry_type = "4MB-PAGE"
                    page_count = 1
                    PTE.append([virt_addr, phys_addr, page_size, page_count, self.format_flags(flags)])
                else:
                    PDE.append([new_va, next_level_table, flags])
                    entry_type = "TABLE"

                # dump
                if self.print_each_level:
                    if self.is_not_trace_target(new_va, new_va_end):
                        continue
                    addr = table_base + i * self.bits["ENTRY_SIZE"]
                    fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                    line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                    if self.is_not_filter_target(line):
                        continue
                    self.add_out(line)

        self.quiet_info("Number of entries: {:d}".format(COUNT))
        self.quiet_info("PD Entry: {:d}".format(len(PDE)))
        self.quiet_info("PT Entry ({:d}MB): {:d}".format(2 if self.PAE else 4, len(PTE)))
        self.quiet_info("Invalid entries: {:d}".format(COUNT - len(PDE) - len(PTE)))
        self.TABLES = PDE
        self.PTE += PTE
        return

    def pagewalk_PT(self):
        self.quiet_add_out(titlify("PTE: Page Table Entry"))
        PTE = []
        COUNT = 0
        flag_cache = {}

        tqdm = GefUtil.get_tqdm(not self.quiet)
        for va_base, table_base, parent_flags in tqdm(self.TABLES, leave=False):
            entries = self.read_physmem_cache(table_base, 2 ** self.bits["PT_BITS"] * self.bits["ENTRY_SIZE"])
            entries = slice_unpack(entries, self.bits["ENTRY_SIZE"])
            COUNT += len(entries)

            if not self.include_kasan:
                if len({e & ~0b111 for e in entries}) == 1:
                    continue

            for i, entry in enumerate(entries):
                # present flag
                if (entry & 1) == 0:
                    continue

                # calc virtual address
                virt_addr = va_base + (i << self.bits["OFFSET"])
                virt_addr_end = virt_addr + (1 << self.bits["OFFSET"])

                # calc flags
                flags = parent_flags.copy()
                # This route passes many times, so make a memo
                entry_flags_key = entry & 0x8000000000000166
                x = flag_cache.get(entry_flags_key, None)
                if x is not None:
                    flags.extend(x)
                else:
                    _flags = []
                    if ((entry >> 1) & 1) == 0:
                        _flags.append("NO_RW")
                    if ((entry >> 2) & 1) == 0:
                        _flags.append("NO_US")
                    if ((entry >> 5) & 1) == 1:
                        _flags.append("A")
                    if ((entry >> 6) & 1) == 1:
                        _flags.append("D")
                    if ((entry >> 8) & 1) == 1:
                        _flags.append("G")
                    if self.PAE and ((entry >> 63) & 1) == 1:
                        _flags.append("XD")
                    flag_cache[entry_flags_key] = _flags
                    flags.extend(_flags)

                # calc physical addr (drop the flag bits)
                phys_addr = entry & 0x000ffffffffff000

                # make entry
                page_size = 4 * 1024
                page_count = 1
                PTE.append([virt_addr, phys_addr, page_size, page_count, self.format_flags(flags)])
                entry_type = "4KB-PAGE"

                # dump
                if self.print_each_level:
                    if self.is_not_trace_target(virt_addr, virt_addr_end):
                        continue
                    addr = table_base + i * self.bits["ENTRY_SIZE"]
                    fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                    line = fmt.format(addr, entry, virt_addr, virt_addr_end, entry_type, " ".join(flags))
                    if self.is_not_filter_target(line):
                        continue
                    self.add_out(line)

        self.quiet_info("Number of entries: {:d}".format(COUNT))
        self.quiet_info("PT Entry (4KB): {:d}".format(len(PTE)))
        self.quiet_info("Invalid entries: {:d}".format(COUNT - len(PTE)))
        self.PTE += PTE

        self.quiet_add_out(titlify("Total"))
        self.quiet_info("PT Entry (Total): {:d}".format(len(self.PTE)))
        self.mappings = self.PTE
        return

    def pagewalk(self):
        # `info tlb` on qemu-monitor returns pagetable without intermediate pagetable information.
        # for printing it, we will pagewalk manually.
        if self.user_specified_cr3 is not None:
            cr3 = self.user_specified_cr3
        else:
            cr3 = get_register("cr3", use_monitor=True)
        if self.user_specified_cr4 is not None:
            cr4 = self.user_specified_cr4
        else:
            cr4 = get_register("cr4", use_monitor=True)
        if is_x86_64() and self.user_pt:
            cr3 += gef_getpagesize()
        self.quiet_info("cr3: {:#018x}".format(cr3))
        self.quiet_info("cr4: {:#018x}".format(cr4))

        # virtual address base
        va_base = 0

        # pagewalk base is from CR3 register
        if self.user_specified_cr3 is not None:
            pagewalk_base = cr3 # without mask
        else:
            if is_x86_64(): # 64bit
                pagewalk_base = (cr3 >> 12) << 12
            elif ((cr4 >> 5) & 1) == 1: # 32bit PAE
                pagewalk_base = (cr3 >> 5) << 5
            else: # 32bit non-PAE
                pagewalk_base = (cr3 >> 12) << 12

        # we ignore PWT and PCD flags.
        flags = []

        # do pagewalk
        self.PTE = []
        self.TABLES = [(va_base, pagewalk_base, flags)]
        self.flags_strings_cache = {}
        if is_x86_64():
            if (cr4 >> 12) & 1: # PML5T check
                # 64bit 5-level(4KB): 9,9,9,9,9,12
                # 64bit 5-level(2MB): 9,9,9,9,0,21
                # 64bit 5-level(1GB): 9,9,9,0,0,30
                self.quiet_info("64-bit 5 level page table")
                self.bits = {
                    "ENTRY_SIZE": 8,
                    "PML5T_BITS": 9, "PML4T_BITS": 9, "PDPT_BITS": 9, "PDT_BITS": 9, "PT_BITS": 9, "OFFSET": 12,
                }
                self.PAE = True
                if not self.use_cache or not self.mappings:
                    self.mappings = None
                    self.pagewalk_PML5T()
                    self.pagewalk_PML4T()
                    self.pagewalk_PDPT()
                    self.pagewalk_PDT()
                    self.pagewalk_PT()
                    self.merging()
            else:
                # 64bit 4-level(4KB): 9,9,9,9,12
                # 64bit 4-level(2MB): 9,9,9,0,21
                # 64bit 4-level(1GB): 9,9,0,0,30
                self.quiet_info("64-bit 4 level page table")
                self.bits = {
                    "ENTRY_SIZE": 8,
                    "PML4T_BITS": 9, "PDPT_BITS": 9, "PDT_BITS": 9, "PT_BITS": 9, "OFFSET": 12,
                }
                self.PAE = True
                if not self.use_cache or not self.mappings:
                    self.mappings = None
                    self.pagewalk_PML4T()
                    self.pagewalk_PDPT()
                    self.pagewalk_PDT()
                    self.pagewalk_PT()
                    self.merging()
        elif is_x86_32() or is_x86_16():
            if (cr4 >> 5) & 1: # PAE check
                # 32bit PAE(4KB): 2,9,9,12 (PTE Size: 64bit)
                # 32bit PAE(2MB): 2,9,0,21 (PTE Size: 64bit)
                self.quiet_info("32-bit {:s} page table".format(Color.boldify("PAE")))
                self.bits = {
                    "ENTRY_SIZE": 8,
                    "PDPT_BITS": 2, "PDT_BITS": 9, "PT_BITS": 9, "OFFSET": 12,
                }
                self.PAE = True
                if not self.use_cache or not self.mappings:
                    self.mappings = None
                    self.pagewalk_PDPT()
                    self.pagewalk_PDT()
                    self.pagewalk_PT()
                    self.merging()
            else:
                # 32bit(4KB): 10,10,12
                # 32bit(4MB): 10,0,22
                self.quiet_info("32-bit Non-PAE page table")
                self.bits = {
                    "ENTRY_SIZE": 4,
                    "PDT_BITS": 10, "PT_BITS": 10, "OFFSET": 12,
                }
                self.PAE = False
                if not self.use_cache or not self.mappings:
                    self.mappings = None
                    self.pagewalk_PDT()
                    self.pagewalk_PT()
                    self.merging()
        else:
            self.err("Unsupported CPU")
            return

        self.flags_strings_cache = None
        self.make_out(self.mappings)
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "x86_16"))
    def do_invoke(self, args):
        self.quiet = args.quiet
        self.print_each_level = args.print_each_level
        self.no_merge = args.no_merge
        self.sort_by_phys = args.sort_by_phys
        self.simple = args.simple
        self.filter = args.filter
        self.vrange = args.vrange.copy()
        self.prange = args.prange.copy()
        self.trace = args.trace.copy()
        self.include_kasan = args.include_kasan
        self.use_cache = args.use_cache

        if is_x86_64() and is_in_kernel():
            self.user_pt = args.user_pt # support only x64
        else:
            self.user_pt = False

        self.user_specified_cr3 = args.cr3
        self.user_specified_cr4 = args.cr4
        if self.trace:
            self.vrange.extend(self.trace) # also set --vrange
            self.print_each_level = True # overwrite
            self.use_cache = False # overwrite

        self.out = []
        self.cache = {}
        self.pagewalk()
        self.cache = {}
        self.print_output(args)
        return


@register_command
class PagewalkArmCommand(PagewalkCommand):
    """Dump pagetable for ARM (only Cortex-A) using qemu-monitor. PL2 pagewalk is unsupported."""
    _cmdline_ = "pagewalk arm"
    _category_ = "08-a. Qemu-system Cooperation - General"
    _aliases_ = ["pagewalk arm32"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-S", dest="force_secure", action="store_true", help="use TTBRn_ELm_S to parse start.")
    group.add_argument("-s", dest="force_normal", action="store_true", help="use TTBRn_ELm to parse start.")
    parser.add_argument("--print-each-level", action="store_true", help="show all level pagetables.")
    parser.add_argument("--no-merge", action="store_true", help="do not merge similar/consecutive address.")
    parser.add_argument("--sort-by-phys", action="store_true", help="sort by physical address.")
    parser.add_argument("--simple", action="store_true", help="merge with ignoring physical address consecutivness.")
    parser.add_argument("--filter", metavar="REGEX", type=re.compile, default=[], action="append",
                        help="filter by REGEX pattern.")
    parser.add_argument("--vrange", metavar="VADDR", default=[], action="append", type=lambda x: int(x, 16),
                        help="filter by map included specified virtual address.")
    parser.add_argument("--prange", metavar="PADDR", default=[], action="append", type=lambda x: int(x, 16),
                        help="filter by map included specified physical address.")
    parser.add_argument("--trace", metavar="VADDR", default=[], action="append", type=lambda x: int(x, 16),
                        help="show all level pagetables only associated specified address.")
    parser.add_argument("-c", "--use-cache", action="store_true", help="use before result.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=False)
        self.ttbr0_mappings = None
        self.ttbr1_mappings = None
        return

    def format_flags_short(self, flag_info):
        return self.__format_flags_short(flag_info, self.PXN)

    def __format_flags_short(self, flag_info, gPXN):
        flag_info_key = (tuple(flag_info), gPXN)
        x = self.flags_strings_cache.get(flag_info_key, None)
        if x is not None:
            return x

        flags = []

        XN = "XN" in flag_info
        PXN = ("PXN" in flag_info) & gPXN

        # AP[2:0] access permissions model
        if "AP=000" in flag_info:
            if XN is False and PXN is False:
                flags += ["PL0/---", "PL1/---"] #
            elif XN is False and PXN is True:
                flags += ["PL0/---", "PL1/---"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/---", "PL1/---"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/---", "PL1/---"] # XN, PXN
        elif "AP=001" in flag_info:
            if XN is False and PXN is False:
                flags += ["PL0/---", "PL1/RWX"] #
            elif XN is False and PXN is True:
                flags += ["PL0/---", "PL1/RW-"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/---", "PL1/RW-"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/---", "PL1/RW-"] # XN, PXN
        elif "AP=010" in flag_info:
            if XN is False and PXN is False:
                flags += ["PL0/R-X", "PL1/RWX"] #
            elif XN is False and PXN is True:
                flags += ["PL0/R-X", "PL1/RW-"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/R--", "PL1/RW-"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/R--", "PL1/RW-"] # XN, PXN
        elif "AP=011" in flag_info:
            if XN is False and PXN is False:
                flags += ["PL0/RWX", "PL1/RWX"] #
            elif XN is False and PXN is True:
                flags += ["PL0/RWX", "PL1/RW-"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/RW-", "PL1/RW-"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/RW-", "PL1/RW-"] # XN, PXN
        elif "AP=100" in flag_info:
            flags += ["PL0/???", "PL1/???"] # undefined (reserved)
        elif "AP=101" in flag_info:
            if XN is False and PXN is False:
                flags += ["PL0/---", "PL1/R-X"] #
            elif XN is False and PXN is True:
                flags += ["PL0/---", "PL1/R--"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/---", "PL1/R--"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/---", "PL1/R--"] # XN, PXN
        elif "AP=110" in flag_info: # deprecated
            if XN is False and PXN is False:
                flags += ["PL0/R-X", "PL1/R-X"] #
            elif XN is False and PXN is True:
                flags += ["PL0/R-X", "PL1/R--"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/R--", "PL1/R--"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/R--", "PL1/R--"] # XN, PXN
        elif "AP=111" in flag_info:
            if XN is False and PXN is False:
                flags += ["PL0/R-X", "PL1/R-X"] #
            elif XN is False and PXN is True:
                flags += ["PL0/R-X", "PL1/R--"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/R--", "PL1/R--"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/R--", "PL1/R--"] # XN, PXN
        # AP[2:1] access permissions model
        elif "AP=00" in flag_info:
            if XN is False and PXN is False:
                flags += ["PL0/---", "PL1/RWX"] #
            elif XN is False and PXN is True:
                flags += ["PL0/---", "PL1/RW-"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/---", "PL1/RW-"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/---", "PL1/RW-"] # XN, PXN
        elif "AP=01" in flag_info:
            if XN is False and PXN is False:
                flags += ["PL0/RWX", "PL1/RWX"] #
            elif XN is False and PXN is True:
                flags += ["PL0/RWX", "PL1/RW-"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/RW-", "PL1/RW-"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/RW-", "PL1/RW-"] # XN, PXN
        elif "AP=10" in flag_info:
            if XN is False and PXN is False:
                flags += ["PL0/---", "PL1/R-X"] #
            elif XN is False and PXN is True:
                flags += ["PL0/---", "PL1/R--"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/---", "PL1/R--"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/---", "PL1/R--"] # XN, PXN
        elif "AP=11" in flag_info:
            if XN is False and PXN is False:
                flags += ["PL0/R-X", "PL1/R-X"] #
            elif XN is False and PXN is True:
                flags += ["PL0/R-X", "PL1/R--"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/R--", "PL1/R--"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/R--", "PL1/R--"] # XN, PXN

        if "NS" in flag_info:
            flags += ["NS"]

        if not self.simple:
            # short description has no `AF` bit

            if "nG" not in flag_info:
                flags += ["GLOBAL"]

        flag_string = " ".join(flags)
        self.flags_strings_cache[flag_info_key] = flag_string
        return flag_string

    def format_flags_long(self, flag_info):
        return self.__format_flags_long(flag_info, self.PXN)

    def __format_flags_long(self, flag_info, gPXN):
        flag_info_key = (tuple(flag_info), gPXN)
        x = self.flags_strings_cache.get(flag_info_key, None)
        if x is not None:
            return x

        flags = []

        # AP/APTable parsing
        if "AP=00" in flag_info:
            disable_write_access = 0
            enable_unpriv_access = 0
        elif "AP=01" in flag_info:
            disable_write_access = 0
            enable_unpriv_access = 1
        elif "AP=10" in flag_info:
            disable_write_access = 1
            enable_unpriv_access = 0
        elif "AP=11" in flag_info:
            disable_write_access = 1
            enable_unpriv_access = 1
        if "APTable2=00" in flag_info:
            pass
        elif "APTable2=01" in flag_info:
            enable_unpriv_access &= 0
        elif "APTable2=10" in flag_info:
            disable_write_access |= 1
        elif "APTable2=11" in flag_info:
            disable_write_access |= 1
            enable_unpriv_access &= 0
        if "APTable1=00" in flag_info:
            pass
        elif "APTable1=01" in flag_info:
            enable_unpriv_access &= 0
        elif "APTable1=10" in flag_info:
            disable_write_access |= 1
        elif "APTable1=11" in flag_info:
            disable_write_access |= 1
            enable_unpriv_access &= 0
        AP = (disable_write_access << 1) | enable_unpriv_access

        # XN/XNTable, PXN/PXNTable, NS/NSTable parsing
        XN = "XN" in flag_info
        XN |= "XNTable2" in flag_info
        XN |= "XNTable1" in flag_info
        PXN = "PXN" in flag_info
        PXN |= "PXNTable2" in flag_info
        PXN |= "PXNTable1" in flag_info
        PXN &= gPXN
        NS = "NS" in flag_info
        NS |= "NSTable2" in flag_info
        NS |= "NSTable1" in flag_info

        # AP[2:1] access permissions model
        if AP == 0b00:
            if XN is False and PXN is False:
                flags += ["PL0/---", "PL1/RWX"] #
            elif XN is False and PXN is True:
                flags += ["PL0/---", "PL1/RW-"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/---", "PL1/RW-"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/---", "PL1/RW-"] # XN, PXN
        elif AP == 0b01:
            if XN is False and PXN is False:
                flags += ["PL0/RWX", "PL1/RWX"] #
            elif XN is False and PXN is True:
                flags += ["PL0/RWX", "PL1/RW-"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/RW-", "PL1/RW-"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/RW-", "PL1/RW-"] # XN, PXN
        elif AP == 0b10:
            if XN is False and PXN is False:
                flags += ["PL0/---", "PL1/R-X"] #
            elif XN is False and PXN is True:
                flags += ["PL0/---", "PL1/R--"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/---", "PL1/R--"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/---", "PL1/R--"] # XN, PXN
        elif AP == 0b11:
            if XN is False and PXN is False:
                flags += ["PL0/R-X", "PL1/R-X"] #
            elif XN is False and PXN is True:
                flags += ["PL0/R-X", "PL1/R--"] # PXN
            elif XN is True and PXN is False:
                flags += ["PL0/R--", "PL1/R--"] # XN
            elif XN is True and PXN is True:
                flags += ["PL0/R--", "PL1/R--"] # XN, PXN

        if NS:
            flags += ["NS"]

        if not self.simple:
            if "AF" in flag_info:
                flags += ["ACCESSED"]
            if "nG" not in flag_info:
                flags += ["GLOBAL"]

        flag_string = " ".join(flags)
        self.flags_strings_cache[flag_info_key] = flag_string
        return flag_string

    def do_pagewalk_short(self, table_base, va_base=0):
        self.mappings = []

        def has_next_level(entry):
            return (entry & 0b11) == 0b01

        def is_section(entry):
            return (entry & 0b11) in [0b10, 0b11] and ((entry >> 18) & 1) == 0

        def is_super_section(entry):
            return self.XP and (entry & 0b11) in [0b10, 0b11] and ((entry >> 18) & 1) == 1

        def is_large_page(entry):
            return (entry & 0b11) == 0b01

        def is_small_page(entry):
            return (entry & 0b11) in [0b10, 0b11]

        # 1st level parse
        self.quiet_add_out(titlify("LEVEL 1"))
        LEVEL1 = []
        SECTION = []
        SUPER_SECTION = []
        COUNT = 0
        entries = self.read_physmem_cache(table_base, 4 * (2 ** (12 - self.N)))
        entries = slice_unpack(entries, 4)
        COUNT += len(entries)
        for i, entry in enumerate(entries):
            # present flag
            if (entry & 0b11) == 0b00:
                continue

            # calc virtual address
            new_va = va_base + (i << 20)
            new_va_end = new_va + (1 << 20)

            # calc flags
            flags = []
            if has_next_level(entry):
                if self.XP and ((entry >> 2) & 1) == 1:
                    flags.append("PXN")
                if self.XP and ((entry >> 3) & 1) == 1:
                    flags.append("NS")
                flags.append("domain={:#x}".format((entry >> 5) & 0b1111))
            elif is_section(entry):
                if ((entry >> 0) & 1) == 1:
                    flags.append("PXN")
                if ((entry >> 2) & 1) == 1:
                    flags.append("B")
                if ((entry >> 3) & 1) == 1:
                    flags.append("C")
                if self.XP and ((entry >> 4) & 1) == 1:
                    flags.append("XN")
                flags.append("domain={:#x}".format((entry >> 5) & 0b1111))
                ap = (((entry >> 15) & 1) << 2) + ((entry >> 10) & 0b11)
                if self.AFE: # AP[2:1] access permissions model
                    flags.append("AP={:02b}".format(ap >> 1))
                else: # AP[2:0] access permissions model
                    flags.append("AP={:03b}".format(ap))
                flags.append("TEX={:#x}".format((entry >> 12) & 0b111))
                if self.XP and ((entry >> 16) & 1) == 1:
                    flags.append("S")
                if self.XP and ((entry >> 17) & 1) == 1:
                    flags.append("nG")
                if self.XP and ((entry >> 19) & 1) == 1:
                    flags.append("NS")
            elif is_super_section(entry):
                if ((entry >> 0) & 1) == 1:
                    flags.append("PXN")
                if ((entry >> 2) & 1) == 1:
                    flags.append("B")
                if ((entry >> 3) & 1) == 1:
                    flags.append("C")
                if ((entry >> 4) & 1) == 1:
                    flags.append("XN")
                ap = (((entry >> 15) & 1) << 2) + ((entry >> 10) & 0b11)
                if self.AFE: # AP[2:1] access permissions model
                    flags.append("AP={:02b}".format(ap >> 1))
                else: # AP[2:0] access permissions model
                    flags.append("AP={:03b}".format(ap))
                flags.append("TEX={:#x}".format((entry >> 12) & 0b111))
                if ((entry >> 16) & 1) == 1:
                    flags.append("S")
                if ((entry >> 17) & 1) == 1:
                    flags.append("nG")
                if ((entry >> 19) & 1) == 1:
                    flags.append("NS")
            else:
                raise

            # calc next table (drop the flag bits)
            if has_next_level(entry):
                next_level_table = entry & 0xfffffc00
            elif is_section(entry):
                next_level_table = entry & 0xfff00000
            elif is_super_section(entry):
                next_level_table = entry & 0xff000000         # PA[31:24]
                next_level_table += (entry & 0x00f0000) << 12 # PA[35:32]
                next_level_table += (entry & 0x00001e0) << 31 # PA[39:36]

            # make entry
            if has_next_level(entry):
                LEVEL1.append([new_va, next_level_table, flags])
                entry_type = "TABLE"
            elif is_section(entry):
                virt_addr = new_va
                phys_addr = next_level_table
                page_size = 1 * 1024 * 1024
                page_count = 1
                SECTION.append([virt_addr, phys_addr, page_size, page_count, self.format_flags_short(flags)])
                entry_type = "SECTION"
            elif is_super_section(entry):
                virt_addr = new_va
                phys_addr = next_level_table
                page_size = 16 * 1024 * 1024
                page_count = 1
                SUPER_SECTION.append([virt_addr, phys_addr, page_size, page_count, self.format_flags_short(flags)])
                entry_type = "SUPER_SECTION"

            # dump
            if self.print_each_level:
                if self.is_not_trace_target(new_va, new_va_end):
                    continue
                addr = table_base + i * 4
                fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                if self.is_not_filter_target(line):
                    continue
                self.add_out(line)

        self.quiet_info("Number of entries: {:d}".format(COUNT))
        self.quiet_info("Level 1 Entry: {:d}".format(len(LEVEL1)))
        self.quiet_info("PT Entry (supersection; 16MB): {:d}".format(len(SUPER_SECTION)))
        self.quiet_info("PT Entry (section; 1MB): {:d}".format(len(SECTION)))
        self.quiet_info("Invalid entries: {:d}".format(COUNT - len(LEVEL1) - len(SUPER_SECTION) - len(SECTION)))
        self.mappings += SECTION + SUPER_SECTION

        # 2nd level parse
        self.quiet_add_out(titlify("LEVEL 2"))
        LARGE = []
        SMALL = []
        COUNT = 0

        tqdm = GefUtil.get_tqdm(not self.quiet)
        for va_base, table_base, parent_flags in tqdm(LEVEL1, leave=False):
            entries = self.read_physmem_cache(table_base, 4 * (2 ** 8))
            entries = slice_unpack(entries, 4)
            COUNT += len(entries)
            for i, entry in enumerate(entries):
                # present flag
                if (entry & 0b11) == 0b00:
                    continue

                # calc virtual address
                virt_addr = va_base + (i << 12)
                virt_addr_end = virt_addr + (1 << 12)

                # calc flags
                flags = parent_flags.copy()
                if is_large_page(entry):
                    if ((entry >> 2) & 1) == 1:
                        flags.append("B")
                    if ((entry >> 3) & 1) == 1:
                        flags.append("C")
                    ap = (((entry >> 9) & 1) << 2) + ((entry >> 4) & 0b11)
                    if self.AFE: # AP[2:1] access permissions model
                        flags.append("AP={:02b}".format(ap >> 1))
                    else: # AP[2:0] access permissions model
                        flags.append("AP={:03b}".format(ap))
                    if ((entry >> 10) & 1) == 1:
                        flags.append("S")
                    if ((entry >> 11) & 1) == 1:
                        flags.append("nG")
                    flags.append("TEX={:#x}".format((entry >> 12) & 0b111))
                    if ((entry >> 15) & 1) == 1:
                        flags.append("XN")
                elif is_small_page(entry):
                    if ((entry >> 0) & 1) == 1:
                        flags.append("XN")
                    if ((entry >> 2) & 1) == 1:
                        flags.append("B")
                    if ((entry >> 3) & 1) == 1:
                        flags.append("C")
                    ap = (((entry >> 9) & 1) << 2) + ((entry >> 4) & 0b11)
                    if self.AFE: # AP[2:1] access permissions model
                        flags.append("AP={:02b}".format(ap >> 1))
                    else: # AP[2:0] access permissions model
                        flags.append("AP={:03b}".format(ap))
                    flags.append("TEX={:#x}".format((entry >> 6) & 0b111))
                    if ((entry >> 10) & 1) == 1:
                        flags.append("S")
                    if ((entry >> 11) & 1) == 1:
                        flags.append("nG")

                # calc physical addr (drop the flag bits)
                if is_large_page(entry):
                    phys_addr = entry & 0xffff0000
                elif is_small_page(entry):
                    phys_addr = entry & 0xfffff000

                # make entry
                if is_large_page(entry):
                    page_size = 64 * 1024
                    page_count = 1
                    LARGE.append([virt_addr, phys_addr, page_size, page_count, self.format_flags_short(flags)])
                    entry_type = "LARGE"
                elif is_small_page(entry):
                    page_size = 4 * 1024
                    page_count = 1
                    SMALL.append([virt_addr, phys_addr, page_size, page_count, self.format_flags_short(flags)])
                    entry_type = "SMALL"

                # dump
                if self.print_each_level:
                    if self.is_not_trace_target(virt_addr, virt_addr_end):
                        continue
                    addr = table_base + i * 4
                    fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                    line = fmt.format(addr, entry, virt_addr, virt_addr_end, entry_type, " ".join(flags))
                    if self.is_not_filter_target(line):
                        continue
                    self.add_out(line)

        self.quiet_info("Number of entries: {:d}".format(COUNT))
        self.quiet_info("PT Entry (large; 64KB): {:d}".format(len(LARGE)))
        self.quiet_info("PT Entry (small; 4KB): {:d}".format(len(SMALL)))
        self.quiet_info("Invalid entries: {:d}".format(COUNT - len(LARGE) - len(SMALL)))
        self.mappings += LARGE + SMALL

        self.quiet_add_out(titlify("Total"))
        self.quiet_info("PT Entry (Total): {:d}".format(len(self.mappings)))
        self.mappings = sorted(self.mappings)
        return

    def do_pagewalk_long(self, table_base, va_base=0):
        self.mappings = []

        def has_next_level(entry):
            return (entry & 0b11) == 0b11

        def is_1GB_page(entry):
            return (entry & 0b11) == 0b01

        def is_2MB_page(entry):
            return (entry & 0b11) == 0b01

        self.quiet_add_out(titlify("LEVEL 1"))
        if self.N < 2:
            # 1st level parse
            LEVEL1 = []
            GB = []
            COUNT = 0
            entries = self.read_physmem_cache(table_base, 8 * (2 ** 2))
            entries = slice_unpack(entries, 8)
            COUNT += len(entries)
            for i, entry in enumerate(entries):
                # present flag
                if (entry & 1) == 0:
                    continue

                # calc virtual address
                new_va = va_base | (i << 30)
                new_va_end = new_va + (1 << 30)

                # calc flags
                flags = []
                if has_next_level(entry):
                    if ((entry >> 59) & 1) == 1:
                        flags.append("PXNTable1")
                    if ((entry >> 60) & 1) == 1:
                        flags.append("XNTable1")
                    flags.append("APTable1={:02b}".format((entry >> 61) & 0b11))
                    if ((entry >> 63) & 1) == 1:
                        flags.append("NSTable1")
                elif is_1GB_page(entry):
                    flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                    if ((entry >> 5) & 1) == 1:
                        flags.append("NS")
                    flags.append("AP={:02b}".format((entry >> 6) & 0b11))
                    flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                    if ((entry >> 10) & 1) == 1:
                        flags.append("AF")
                    if ((entry >> 11) & 1) == 1:
                        flags.append("nG")
                    if ((entry >> 52) & 1) == 1:
                        flags.append("Contiguous")
                    if ((entry >> 53) & 1) == 1:
                        flags.append("PXN")
                    if ((entry >> 54) & 1) == 1:
                        flags.append("XN")

                # calc next table (drop the flag bits)
                if has_next_level(entry):
                    next_level_table = entry & 0x000000fffffff000
                elif is_1GB_page(entry):
                    next_level_table = entry & 0x000000ffc0000000

                # make entry
                if has_next_level(entry):
                    LEVEL1.append([new_va, next_level_table, flags])
                    entry_type = "TABLE"
                elif is_1GB_page(entry):
                    virt_addr = new_va
                    phys_addr = next_level_table
                    page_size = 1 * 1024 * 1024 * 1024
                    page_count = 1
                    GB.append([virt_addr, phys_addr, page_size, page_count, self.format_flags_long(flags)])
                    entry_type = "1GB-PAGE"

                # dump
                if self.print_each_level:
                    if self.is_not_trace_target(new_va, new_va_end):
                        continue
                    addr = table_base + i * 8
                    fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                    line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                    if self.is_not_filter_target(line):
                        continue
                    self.add_out(line)

            self.quiet_info("Number of entries: {:d}".format(COUNT))
            self.quiet_info("Level 1 Entry: {:d}".format(len(LEVEL1)))
            self.quiet_info("PT Entry (1GB): {:d}".format(len(GB)))
            self.quiet_info("Invalid entries: {:d}".format(COUNT - len(LEVEL1) - len(GB)))
            self.mappings += GB
        else:
            self.quiet_info("LEVEL 1 is skipped")
            flags = []
            LEVEL1 = [[va_base, table_base, flags]]

        # 2nd level parse
        self.quiet_add_out(titlify("LEVEL 2"))
        LEVEL2 = []
        MB = []
        COUNT = 0
        for va_base, table_base, parent_flags in LEVEL1:
            entries = self.read_physmem_cache(table_base, 8 * (2 ** 9))
            entries = slice_unpack(entries, 8)
            COUNT += len(entries)
            for i, entry in enumerate(entries):
                # present flag
                if (entry & 1) == 0:
                    continue

                # calc virtual address
                new_va = va_base | (i << 21)
                new_va_end = new_va + (1 << 21)

                # calc flags
                flags = parent_flags.copy()
                if has_next_level(entry):
                    if ((entry >> 59) & 1) == 1:
                        flags.append("PXNTable2")
                    if ((entry >> 60) & 1) == 1:
                        flags.append("XNTable2")
                    flags.append("APTable2={:02b}".format((entry >> 61) & 0b11))
                    if ((entry >> 63) & 1) == 1:
                        flags.append("NSTable2")
                elif is_2MB_page(entry):
                    flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                    if ((entry >> 5) & 1) == 1:
                        flags.append("NS")
                    flags.append("AP={:02b}".format((entry >> 6) & 0b11))
                    flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                    if ((entry >> 10) & 1) == 1:
                        flags.append("AF")
                    if ((entry >> 11) & 1) == 1:
                        flags.append("nG")
                    if ((entry >> 52) & 1) == 1:
                        flags.append("Contiguous")
                    if ((entry >> 53) & 1) == 1:
                        flags.append("PXN")
                    if ((entry >> 54) & 1) == 1:
                        flags.append("XN")

                # calc next table (drop the flag bits)
                if has_next_level(entry):
                    next_level_table = entry & 0x000000fffffff000
                elif is_2MB_page(entry):
                    next_level_table = entry & 0x000000ffffe00000

                # make entry
                if has_next_level(entry):
                    LEVEL2.append([new_va, next_level_table, flags])
                    entry_type = "TABLE"
                elif is_2MB_page(entry):
                    virt_addr = new_va
                    phys_addr = next_level_table
                    page_size = 2 * 1024 * 1024
                    page_count = 1
                    MB.append([virt_addr, phys_addr, page_size, page_count, self.format_flags_long(flags)])
                    entry_type = "2MB-PAGE"

                # dump
                if self.print_each_level:
                    if self.is_not_trace_target(new_va, new_va_end):
                        continue
                    addr = table_base + i * 8
                    fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                    line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                    if self.is_not_filter_target(line):
                        continue
                    self.add_out(line)

        self.quiet_info("Number of entries: {:d}".format(COUNT))
        self.quiet_info("Level 2 Entry: {:d}".format(len(LEVEL2)))
        self.quiet_info("PT Entry (2MB): {:d}".format(len(MB)))
        self.quiet_info("Invalid entries: {:d}".format(COUNT - len(LEVEL2) - len(MB)))
        self.mappings += MB

        # 3rd level parse
        self.quiet_add_out(titlify("LEVEL 3"))
        KB = []
        COUNT = 0

        tqdm = GefUtil.get_tqdm(not self.quiet)
        for va_base, table_base, parent_flags in tqdm(LEVEL2, leave=False):
            entries = self.read_physmem_cache(table_base, 8 * (2 ** 9))
            entries = slice_unpack(entries, 8)
            COUNT += len(entries)
            for i, entry in enumerate(entries):
                # present flag
                if (entry & 0b11) != 0b11:
                    continue

                # calc virtual address
                virt_addr = va_base | (i << 12)
                virt_addr_end = virt_addr + (1 << 12)

                # calc flags
                flags = parent_flags.copy()
                flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                if ((entry >> 5) & 1) == 1:
                    flags.append("NS")
                flags.append("AP={:02b}".format((entry >> 6) & 0b11))
                flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                if ((entry >> 10) & 1) == 1:
                    flags.append("AF")
                if ((entry >> 11) & 1) == 1:
                    flags.append("nG")
                if ((entry >> 52) & 1) == 1:
                    flags.append("Contiguous")
                if ((entry >> 53) & 1) == 1:
                    flags.append("PXN")
                if ((entry >> 54) & 1) == 1:
                    flags.append("XN")

                # calc physical addr (drop the flag bits)
                phys_addr = entry & 0x000000fffffff000

                # make entry
                page_size = 4 * 1024
                page_count = 1
                KB.append([virt_addr, phys_addr, page_size, page_count, self.format_flags_long(flags)])
                entry_type = "1KB-PAGE"

                # dump
                if self.print_each_level:
                    if self.is_not_trace_target(virt_addr, virt_addr_end):
                        continue
                    addr = table_base + i * 8
                    fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                    line = fmt.format(addr, entry, virt_addr, virt_addr_end, entry_type, " ".join(flags))
                    if self.is_not_filter_target(line):
                        continue
                    self.add_out(line)

        self.quiet_info("Number of entries: {:d}".format(COUNT))
        self.quiet_info("PT Entry (4KB): {:d}".format(len(KB)))
        self.quiet_info("Invalid entries: {:d}".format(COUNT - len(KB)))
        self.mappings += KB

        self.quiet_add_out(titlify("Total"))
        self.quiet_info("PT Entry (Total): {:d}".format(len(self.mappings)))
        self.mappings = sorted(self.mappings)
        return

    def pagewalk_short(self):
        self.add_out(titlify("$TTBR0_EL1{}".format(self.suffix)))

        TTBR0_EL1 = get_register("$TTBR0_EL1{}".format(self.suffix))
        if TTBR0_EL1 is None:
            TTBR0_EL1 = get_register("$TTBR0", use_mbed_exec=True)
        if TTBR0_EL1 is None:
            self.err("$TTBR0_EL1{} is not found".format(self.suffix))
            return

        TTBCR = get_register("$TTBCR{}".format(self.suffix))
        if TTBCR is None:
            TTBCR = get_register("$TTBCR", use_mbed_exec=True)
        if TTBCR is None:
            self.err("$TTBCR{} is not found".format(self.suffix))
            return

        # pagewalk TTBR0_EL1
        self.N = TTBCR & 0b111
        ml = 14 - self.N
        pl0_base = ((TTBR0_EL1 & ((1 << 32) - 1)) >> ml) << ml
        self.quiet_info("$TTBR0_EL1{}: {:#x}".format(self.suffix, TTBR0_EL1))
        self.quiet_info("$TTBCR{}: {:#x}".format(self.suffix, TTBCR))
        self.quiet_info("PL0 base: {:#x}".format(pl0_base))
        if not self.use_cache or not self.ttbr0_mappings:
            self.flags_strings_cache = {}
            self.do_pagewalk_short(pl0_base)
            self.flags_strings_cache = None
            self.merging()
            self.ttbr0_mappings = self.mappings.copy()
        self.make_out(self.ttbr0_mappings)

        # pagewalk TTBR1_EL1
        self.add_out(titlify("$TTBR1_EL1{}".format(self.suffix)))

        TTBR1_EL1 = get_register("$TTBR1_EL1{}".format(self.suffix))
        if TTBR1_EL1 is None:
            TTBR1_EL1 = get_register("$TTBR1", use_mbed_exec=True)
        if TTBR1_EL1 is None:
            self.err("$TTBR1_EL1{} is not found".format(self.suffix))
            return

        if self.suffix:
            pl1_vabase = 0 # I don't know why, but vabase of PL1 seems to be 0x0 when using TTBR1_EL1_S.
        else:
            pl1_vabase = {
                0: None, 1: 0x80000000, 2: 0x40000000, 3: 0x20000000,
                4: 0x10000000, 5: 0x08000000, 6: 0x04000000, 7: 0x02000000
            }[self.N]
        pl1_base = ((TTBR1_EL1 & ((1 << 32) - 1)) >> ml) << ml
        self.N = 0 # Whenever TTBCR.N is nonzero, the size of the translation table addressed by TTBR1 is 16KB (N=0).
        if pl1_vabase is not None:
            self.quiet_info("$TTBR1_EL1{}: {:#x}".format(self.suffix, TTBR1_EL1))
            self.quiet_info("$TTBCR{}: {:#x}".format(self.suffix, TTBCR))
            self.quiet_info("PL1 base: {:#x}".format(pl1_base))
            self.quiet_info("PL1 va_base: {:#x}".format(pl1_vabase))
            if not self.use_cache or not self.ttbr1_mappings:
                self.flags_strings_cache = {}
                self.do_pagewalk_short(pl1_base, pl1_vabase)
                self.flags_strings_cache = None
                self.merging()
                self.ttbr1_mappings = self.mappings.copy()
            self.make_out(self.ttbr1_mappings)
        else:
            self.quiet_info("$TTBR1_EL1{} is unused".format(self.suffix))
        return

    def pagewalk_long(self):
        self.add_out(titlify("$TTBR0_EL1{}".format(self.suffix)))

        TTBR0_EL1 = get_register("$TTBR0_EL1{}".format(self.suffix))
        if TTBR0_EL1 is None:
            TTBR0_EL1 = get_register("$TTBR0", use_mbed_exec=True)
        if TTBR0_EL1 is None:
            self.err("$TTBR0_EL1{} is not found".format(self.suffix))
            return

        TTBCR = get_register("$TTBCR{}".format(self.suffix))
        if TTBCR is None:
            TTBCR = get_register("$TTBCR", use_mbed_exec=True)
        if TTBCR is None:
            self.err("$TTBCR{} is not found".format(self.suffix))
            return

        # pagewalk TTBR0_EL1
        T0SZ = TTBCR & 0b111
        T1SZ = (TTBCR >> 16) & 0b111
        self.N = T0SZ
        pl0_base = TTBR0_EL1 & ((1 << 40) - 1)
        self.quiet_info("$TTBR0_EL1{}: {:#x}".format(self.suffix, TTBR0_EL1))
        self.quiet_info("$TTBCR{}: {:#x}".format(self.suffix, TTBCR))
        self.quiet_info("PL0 base: {:#x}".format(pl0_base))
        if not self.use_cache or not self.ttbr0_mappings:
            self.flags_strings_cache = {}
            self.do_pagewalk_long(pl0_base)
            self.flags_strings_cache = None
            self.merging()
            self.ttbr0_mappings = self.mappings.copy()
        self.make_out(self.ttbr0_mappings)

        # pagewalk TTBR1_EL1
        self.add_out(titlify("$TTBR1_EL1{}".format(self.suffix)))

        TTBR1_EL1 = get_register("$TTBR1_EL1{}".format(self.suffix))
        if TTBR1_EL1 is None:
            TTBR1_EL1 = get_register("$TTBR1", use_mbed_exec=True)
        if TTBR1_EL1 is None:
            self.err("$TTBR1_EL1{} is not found".format(self.suffix))
            return

        if T0SZ != 0 or T1SZ != 0:
            self.N = T1SZ
            pl1_base = TTBR1_EL1 & ((1 << 40) - 1)
            if T1SZ == 0:
                pl1_vabase = 2 ** (32 - T0SZ)
            else:
                pl1_vabase = (2 ** 32) - (2 ** (32 - T1SZ))
            self.quiet_info("$TTBR1_EL1{}: {:#x}".format(self.suffix, TTBR1_EL1))
            self.quiet_info("PL1 base: {:#x}".format(pl1_base))
            self.quiet_info("PL1 va_base: {:#x}".format(pl1_vabase))
            if not self.use_cache or not self.ttbr1_mappings:
                self.flags_strings_cache = {}
                self.do_pagewalk_long(pl1_base, pl1_vabase)
                self.flags_strings_cache = None
                self.merging()
                self.ttbr1_mappings = self.mappings.copy()
            self.make_out(self.ttbr1_mappings)
        else:
            self.quiet_info("$TTBR1_EL1{} is unused".format(self.suffix))
        return

    def pagewalk(self):
        # check use the register with`_S` suffix or not, and Seucre mode or not
        if self.FORCE_PREFIX_S is None:
            # auto detect
            SCR_S = get_register("$SCR_S")
            SCR = get_register("$SCR")

            if (SCR, SCR_S) == (None, None):
                self.SECURE = False
                self.suffix = ""

            elif SCR is not None and SCR_S is None:
                # do not use "_S"
                self.SECURE = (SCR & 0x1) == 0 # NS bit
                self.suffix = ""

            elif SCR is None and SCR_S is not None:
                # use "_S"
                self.SECURE = (SCR_S & 0x1) == 0 # NS bit
                self.suffix = "_S"

            elif SCR is not None and SCR_S is not None:
                r = gdb.execute("monitor info mtree -f", to_string=True)
                if ".secure-ram" in r:
                    # do not use "_S"
                    self.SECURE = (SCR & 0x1) == 0 # NS bit
                    self.suffix = ""
                else:
                    # use "_S"
                    self.SECURE = (SCR_S & 0x1) == 0 # NS bit
                    self.suffix = "_S"

        elif self.FORCE_PREFIX_S is True:
            # use "_S"
            SCR_S = get_register("$SCR_S")
            if SCR_S is not None:
                self.SECURE = (SCR_S & 0x1) == 0 # NS bit
            else:
                self.SECURE = False
            self.suffix = "_S"

        elif self.FORCE_PREFIX_S is False:
            # do not use "_S"
            SCR = get_register("$SCR")
            if SCR is not None:
                self.SECURE = (SCR & 0x1) == 0 # NS bit
            else:
                self.SECURE = False
            self.suffix = ""

        # check XP, AFE
        SCTLR = get_register("$SCTLR{}".format(self.suffix))
        if SCTLR is not None:
            self.XP = ((SCTLR >> 23) & 0x1) == 1
            self.AFE = ((SCTLR >> 29) & 0x1) == 1
        else:
            self.XP = False
            self.AFE = False

        if not self.XP:
            self.quiet_info("VMSAv6 subpages is enabled")
            self.SECURE = False
        else:
            self.quiet_info("Secure world: {}".format(self.SECURE))

        # check enabled LPAE
        TTBCR = get_register("$TTBCR{}".format(self.suffix))
        if TTBCR is not None:
            self.LPAE = ((TTBCR >> 31) & 0x1) == 1
        else:
            self.LPAE = False

        # check PXN supported
        ID_MMFR0 = get_register("$ID_MMFR0{}".format(self.suffix))
        if ID_MMFR0 is not None:
            self.PXN = ((ID_MMFR0 >> 2) & 0x1) == 1
        else:
            self.PXN = False

        if self.PXN:
            self.quiet_info("{:s} is supported".format(Color.boldify("PXN")))
        else:
            self.quiet_info("PXN is unsupported")
        self.quiet_info("PAN is unimplemented on all ARMv7")

        # pagewalk
        if self.LPAE:
            self.quiet_info("{:s} is enabled (using long description)".format(Color.boldify("LPAE")))
            self.pagewalk_long()
        else:
            self.quiet_info("LPAE is disabled (using short description)")
            self.pagewalk_short()
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM32",))
    def do_invoke(self, args):
        self.FORCE_PREFIX_S = None
        if args.force_secure:
            self.FORCE_PREFIX_S = True
        elif args.force_normal:
            self.FORCE_PREFIX_S = False

        self.quiet = args.quiet
        self.print_each_level = args.print_each_level
        self.no_merge = args.no_merge
        self.sort_by_phys = args.sort_by_phys
        self.simple = args.simple
        self.filter = args.filter
        self.vrange = args.vrange.copy()
        self.prange = args.prange.copy()
        self.trace = args.trace.copy()
        self.use_cache = args.use_cache
        if self.trace:
            self.vrange.extend(self.trace) # also set --vrange
            self.print_each_level = True # overwrite
            self.use_cache = False # overwrite

        self.out = []
        self.cache = {}
        self.pagewalk()
        self.cache = {}
        self.print_output(args)
        return


@register_command
class PagewalkArm64Command(PagewalkCommand):
    """Dump pagetable for ARM64 (only Cortex-A; ARM v8.7 base) using qemu-monitor."""
    _cmdline_ = "pagewalk arm64"
    _category_ = "08-a. Qemu-system Cooperation - General"
    _aliases_ = [] # re-overwrite

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("target_el", metavar="TARGET_EL", nargs="?", type=int,
                        help="target Exception Level. (default: current EL)")
    parser.add_argument("--print-each-level", action="store_true", help="show all level pagetables.")
    parser.add_argument("--no-merge", action="store_true", help="do not merge similar/consecutive address.")
    parser.add_argument("--sort-by-phys", action="store_true", help="sort by physical address.")
    parser.add_argument("--simple", action="store_true", help="merge with ignoring physical address consecutivness.")
    parser.add_argument("--filter", metavar="REGEX", type=re.compile, default=[], action="append",
                        help="filter by REGEX pattern.")
    parser.add_argument("--vrange", metavar="VADDR", default=[], action="append", type=lambda x: int(x, 16),
                        help="filter by map included specified virtual address.")
    parser.add_argument("--prange", metavar="PADDR", default=[], action="append", type=lambda x: int(x, 16),
                        help="filter by map included specified physical address.")
    parser.add_argument("--trace", metavar="VADDR", default=[], action="append", type=lambda x: int(x, 16),
                        help="show all level pagetables only associated specified address.")
    parser.add_argument("--optee", action="store_true", help="show the secure world memory maps if used OP-TEE.")
    parser.add_argument("-c", "--use-cache", action="store_true", help="use before result.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-q", "--quiet", action="store_true", help="show result only.")
    _syntax_ = parser.format_help()

    # If you want to dump the secure world memory map, you need to break in the secure world.
    # This is because unlike ARMv7, TTBR0_EL1_S and TTBR1_EL1_S do not exist.
    # It is difficult to know the correct value of the secure world's system registers while in the normal world,
    # as the secure monitor saves all system registers to memory when the world changes.

    def __init__(self):
        super().__init__(prefix=False)
        self.ttbr0el1_mappings = None
        self.ttbr1el1_mappings = None
        self.ttbr0el2_mappings = None
        self.ttbr1el2_mappings = None
        self.vttbrel2_mappings = None
        self.ttbr0el3_mappings = None
        return

    def read_mem_wrapper(self, addr, size=8):
        """
        When pagewalking EL0/EL1 of the guest OS, gdb pagewalks the physical memory according to $TTBR0_ELx.
        However, even if you try to read the physical memory, access to the address will fail
        because it is actually an intermediate physical memory.
        Therefore, in order to perform a pagewalk of EL0/EL1, EL2 mapping information is required.
        This function is for reading from physical memory with that in mind.
        """

        if self.EL3_M and self.TargetEL == 3:
            return read_memory(addr, size)

        # translate via EL2 mappings
        if self.EL2_VM and self.TargetEL == 1 and self.el2_mappings:
            def search_pa(addr):
                for entry_info in self.el2_mappings:
                    va, entry, sz, cnt, flags = entry_info
                    if isinstance(va, str):
                        va = int(va, 16)
                    pa = entry & 0x0000fffffffff000
                    if va <= addr < va + sz:
                        offset = addr - va
                        return pa + offset, sz - offset
                else: # not found
                    raise
            out = b""
            while size > 0:
                paddr, available_sz = search_pa(addr)
                out += self.read_physmem_cache(paddr, min([size, available_sz]))
                size -= min(size, available_sz)
            return out

        # direct physmem read
        else:
            return self.read_physmem_cache(addr, size)

    def format_flags_stage2(self, flag_info):
        flag_info_key = tuple(flag_info)
        x = self.flags_strings_cache.get(flag_info_key, None)
        if x is not None:
            return x

        flags = []

        if "S2AP=00" in flag_info:
            if "XN=00" in flag_info:
                flags += ["EL0/---", "EL1/---"]
            elif "XN=01" in flag_info:
                flags += ["EL0/---", "EL1/---"]
            elif "XN=10" in flag_info:
                flags += ["EL0/---", "EL1/---"]
            elif "XN=11" in flag_info:
                flags += ["EL0/---", "EL1/---"]
        elif "S2AP=01" in flag_info:
            if "XN=00" in flag_info:
                flags += ["EL0/R-X", "EL1/R-X"]
            elif "XN=01" in flag_info:
                flags += ["EL0/R-X", "EL1/R--"]
            elif "XN=10" in flag_info:
                flags += ["EL0/R--", "EL1/R--"]
            elif "XN=11" in flag_info:
                flags += ["EL0/R--", "EL1/R-X"]
        elif "S2AP=10" in flag_info:
            if "XN=00" in flag_info:
                flags += ["EL0/-W-", "EL1/-W-"]
            elif "XN=01" in flag_info:
                flags += ["EL0/-W-", "EL1/-W-"]
            elif "XN=10" in flag_info:
                flags += ["EL0/-W-", "EL1/-W-"]
            elif "XN=11" in flag_info:
                flags += ["EL0/-W-", "EL1/-W-"]
        elif "S2AP=11" in flag_info:
            if "XN=00" in flag_info:
                flags += ["EL0/RWX", "EL1/RWX"]
            elif "XN=01" in flag_info:
                flags += ["EL0/RWX", "EL1/RW-"]
            elif "XN=10" in flag_info:
                flags += ["EL0/RW-", "EL1/RW-"]
            elif "XN=11" in flag_info:
                flags += ["EL0/RW-", "EL1/RWX"]

        if not self.simple:
            if "AF" in flag_info:
                flags += ["ACCESSED"]
            if "DBM" in flag_info:
                flags += ["DIRTY"]
            # stage2 has no `nG` bit

        flag_string = " ".join(flags)
        self.flags_strings_cache[flag_info_key] = flag_string
        return flag_string

    def format_flags(self, flag_info):
        return self.__format_flags(flag_info, self.TargetEL, self.EL1_WXN, self.EL2_WXN, self.EL2_M20, self.EL3_WXN)

    def __format_flags(self, flag_info, TargetEL, EL1_WXN, EL2_WXN, EL2_M20, EL3_WXN):
        flag_info_key = (tuple(flag_info), TargetEL, EL1_WXN, EL2_WXN, EL2_M20, EL3_WXN)
        x = self.flags_strings_cache.get(flag_info_key, None)
        if x is not None:
            return x

        flags = []

        # AP/APTable parsing
        if "AP=00" in flag_info:
            disable_write_access = 0
            enable_unpriv_access = 0
        elif "AP=01" in flag_info:
            disable_write_access = 0
            enable_unpriv_access = 1
        elif "AP=10" in flag_info:
            disable_write_access = 1
            enable_unpriv_access = 0
        elif "AP=11" in flag_info:
            disable_write_access = 1
            enable_unpriv_access = 1
        if "APTable2=00" in flag_info:
            pass
        elif "APTable2=01" in flag_info:
            enable_unpriv_access &= 0
        elif "APTable2=10" in flag_info:
            disable_write_access |= 1
        elif "APTable2=11" in flag_info:
            disable_write_access |= 1
            enable_unpriv_access &= 0
        if "APTable1=00" in flag_info:
            pass
        elif "APTable1=01" in flag_info:
            enable_unpriv_access &= 0
        elif "APTable1=10" in flag_info:
            disable_write_access |= 1
        elif "APTable1=11" in flag_info:
            disable_write_access |= 1
            enable_unpriv_access &= 0
        if "APTable0=00" in flag_info:
            pass
        elif "APTable0=01" in flag_info:
            enable_unpriv_access &= 0
        elif "APTable0=10" in flag_info:
            disable_write_access |= 1
        elif "APTable0=11" in flag_info:
            disable_write_access |= 1
            enable_unpriv_access &= 0
        if "APTable-1=00" in flag_info:
            pass
        elif "APTable-1=01" in flag_info:
            enable_unpriv_access &= 0
        elif "APTable-1=10" in flag_info:
            disable_write_access |= 1
        elif "APTable-1=11" in flag_info:
            disable_write_access |= 1
            enable_unpriv_access &= 0

        # UXN/UXNTable, XN/XNTable, PXN/PXNTable, NS/NSTable parsing
        UXN = "UXN" in flag_info
        UXN |= "UXNTable2" in flag_info
        UXN |= "UXNTable1" in flag_info
        UXN |= "UXNTable0" in flag_info
        UXN |= "UXNTable-1" in flag_info
        XN = "XN" in flag_info
        XN |= "XNTable2" in flag_info
        XN |= "XNTable1" in flag_info
        XN |= "XNTable0" in flag_info
        XN |= "XNTable-1" in flag_info
        PXN = "PXN" in flag_info
        PXN |= "PXNTable2" in flag_info
        PXN |= "PXNTable1" in flag_info
        PXN |= "PXNTable0" in flag_info
        PXN |= "PXNTable-1" in flag_info
        NS = "NS" in flag_info
        NS |= "NSTable2" in flag_info
        NS |= "NSTable1" in flag_info
        NS |= "NSTable0" in flag_info
        NS |= "NSTable-1" in flag_info

        if TargetEL == 1:
            # always support 2VA ranges
            if UXN is False and PXN is False:
                if disable_write_access == 0 and enable_unpriv_access == 0:
                    if not EL1_WXN:
                        flags += ["EL0/--X", "EL1/RWX"]
                    else:
                        flags += ["EL0/--X", "EL1/RW-"]
                elif disable_write_access == 0 and enable_unpriv_access == 1:
                    if not EL1_WXN:
                        flags += ["EL0/RWX", "EL1/RW-"]
                    else:
                        flags += ["EL0/RW-", "EL1/RW-"]
                elif disable_write_access == 1 and enable_unpriv_access == 0:
                    flags += ["EL0/--X", "EL1/R-X"]
                elif disable_write_access == 1 and enable_unpriv_access == 1:
                    flags += ["EL0/R-X", "EL1/R-X"]
            elif UXN is False and PXN is True:
                if disable_write_access == 0 and enable_unpriv_access == 0:
                    flags += ["EL0/--X", "EL1/RW-"]
                elif disable_write_access == 0 and enable_unpriv_access == 1:
                    if not EL1_WXN:
                        flags += ["EL0/RWX", "EL1/RW-"]
                    else:
                        flags += ["EL0/RW-", "EL1/RW-"]
                elif disable_write_access == 1 and enable_unpriv_access == 0:
                    flags += ["EL0/--X", "EL1/R--"]
                elif disable_write_access == 1 and enable_unpriv_access == 1:
                    flags += ["EL0/R-X", "EL1/R--"]
            elif UXN is True and PXN is False:
                if disable_write_access == 0 and enable_unpriv_access == 0:
                    if not EL1_WXN:
                        flags += ["EL0/---", "EL1/RWX"]
                    else:
                        flags += ["EL0/---", "EL1/RW-"]
                elif disable_write_access == 0 and enable_unpriv_access == 1:
                    flags += ["EL0/RW-", "EL1/RW-"]
                elif disable_write_access == 1 and enable_unpriv_access == 0:
                    flags += ["EL0/---", "EL1/R-X"]
                elif disable_write_access == 1 and enable_unpriv_access == 1:
                    flags += ["EL0/R--", "EL1/R-X"]
            elif UXN is True and PXN is True:
                if disable_write_access == 0 and enable_unpriv_access == 0:
                    flags += ["EL0/---", "EL1/RW-"]
                elif disable_write_access == 0 and enable_unpriv_access == 1:
                    flags += ["EL0/RW-", "EL1/RW-"]
                elif disable_write_access == 1 and enable_unpriv_access == 0:
                    flags += ["EL0/---", "EL1/R--"]
                elif disable_write_access == 1 and enable_unpriv_access == 1:
                    flags += ["EL0/R--", "EL1/R--"]
        elif TargetEL == 2:
            if EL2_M20:
                # support 2VA ranges if HCR_EL2.{TGE,E2H} == {1,1}
                if UXN is False and PXN is False:
                    if disable_write_access == 0 and enable_unpriv_access == 0:
                        if not EL2_WXN:
                            flags += ["EL0/--X", "EL2/RWX"]
                        else:
                            flags += ["EL0/--X", "EL2/RW-"]
                    elif disable_write_access == 0 and enable_unpriv_access == 1:
                        if not EL2_WXN:
                            flags += ["EL0/RWX", "EL2/RW-"]
                        else:
                            flags += ["EL0/RW-", "EL2/RW-"]
                    elif disable_write_access == 1 and enable_unpriv_access == 0:
                        flags += ["EL0/--X", "EL2/R-X"]
                    elif disable_write_access == 1 and enable_unpriv_access == 1:
                        flags += ["EL0/R-X", "EL2/R-X"]
                elif UXN is False and PXN is True:
                    if disable_write_access == 0 and enable_unpriv_access == 0:
                        flags += ["EL0/--X", "EL2/RW-"]
                    elif disable_write_access == 0 and enable_unpriv_access == 1:
                        if not EL2_WXN:
                            flags += ["EL0/RWX", "EL2/RW-"]
                        else:
                            flags += ["EL0/RW-", "EL2/RW-"]
                    elif disable_write_access == 1 and enable_unpriv_access == 0:
                        flags += ["EL0/--X", "EL2/R--"]
                    elif disable_write_access == 1 and enable_unpriv_access == 1:
                        flags += ["EL0/R-X", "EL2/R--"]
                elif UXN is True and PXN is False:
                    if disable_write_access == 0 and enable_unpriv_access == 0:
                        if not EL2_WXN:
                            flags += ["EL0/---", "EL2/RWX"]
                        else:
                            flags += ["EL0/---", "EL2/RW-"]
                    elif disable_write_access == 0 and enable_unpriv_access == 1:
                        flags += ["EL0/RW-", "EL2/RW-"]
                    elif disable_write_access == 1 and enable_unpriv_access == 0:
                        flags += ["EL0/---", "EL2/R-X"]
                    elif disable_write_access == 1 and enable_unpriv_access == 1:
                        flags += ["EL0/R--", "EL2/R-X"]
                elif UXN is True and PXN is True:
                    if disable_write_access == 0 and enable_unpriv_access == 0:
                        flags += ["EL0/---", "EL2/RW-"]
                    elif disable_write_access == 0 and enable_unpriv_access == 1:
                        flags += ["EL0/RW-", "EL2/RW-"]
                    elif disable_write_access == 1 and enable_unpriv_access == 0:
                        flags += ["EL0/---", "EL2/R--"]
                    elif disable_write_access == 1 and enable_unpriv_access == 1:
                        flags += ["EL0/R--", "EL2/R--"]
            else:
                # not support 2VA ranges if HCR_EL2.{TGE,E2H} != {1,1}
                if XN is False:
                    if disable_write_access == 0:
                        if not EL2_WXN:
                            flags += ["EL2/RWX"]
                        else:
                            flags += ["EL2/RW-"]
                    elif disable_write_access == 1:
                        flags += ["EL2/R-X"]
                elif XN is True:
                    if disable_write_access == 0:
                        flags += ["EL2/RW-"]
                    elif disable_write_access == 1:
                        flags += ["EL2/R--"]
        elif TargetEL == 3:
            if XN is False:
                if disable_write_access == 0:
                    if not EL3_WXN:
                        flags += ["EL3/RWX"]
                    else:
                        flags += ["EL3/RW-"]
                elif disable_write_access == 1:
                    flags += ["EL3/R-X"]
            elif XN is True:
                if disable_write_access == 0:
                    flags += ["EL3/RW-"]
                elif disable_write_access == 1:
                    flags += ["EL3/R--"]
        if NS:
            flags += ["NS"]

        if not self.simple:
            if "AF" in flag_info:
                flags += ["ACCESSED"]
            if "DBM" in flag_info:
                flags += ["DIRTY"]
            if "nG" not in flag_info:
                flags += ["GLOBAL"]

        flag_string = " ".join(flags)
        self.flags_strings_cache[flag_info_key] = flag_string
        return flag_string

    """
    Relation diagram when CPU uses

      Stage1                  |     Stage2
    -------------------------------------------------------
    +----------------------+  |   +----------------------+
    | Guest OS table       | -|-> | Virtualization table |
    +----------------------+  |   +----------------------+
      TTBR0_EL1, TTBR1_EL1    |     VTTBR0_EL2
                              |
    +----------------------+  |
    | Hypervisor table     |  |
    +----------------------+  |
      TTBR0_EL2, TTBR1_EL2    |
                              |
    +----------------------+  |
    | Secure monitor table |  |
    +----------------------+  |
      TTBR0_EL3               |
                              |

    Since it is an implementation that dumps for each EL, consider as follows.

      TargetEL=1              |    TargetEL=2              |    TargetEL=3
    ---------------------------------------------------------------------------------
    +----------------------+  |  +----------------------+  |  +----------------------+
    | Guest OS table       |  |  | Virtualization table |  |  | Secure monitor table |
    +----------------------+  |  +----------------------+  |  +----------------------+
      TTBR0_EL1, TTBR1_EL1    |    VTTBR0_EL2              |    TTBR0_EL3
                              |                            |
                              |  +----------------------+  |
                              |  | Hypervisor table     |  |
                              |  +----------------------+  |
                              |    TTBR0_EL2, TTBR1_EL2    |
                              |                            |
    """
    def parse_bit_range(self, granule_bits, region_bits):
        IA_LVA_MAX = 52 if self.FEAT_LVA else 48
        if granule_bits == 12: # 4KB granule
            self.LEVELM1_BIT_RANGE = [48, min(IA_LVA_MAX, region_bits)] if region_bits > 48 else None # no block descriptor
            self.LEVEL0_BIT_RANGE = [39, min(48, region_bits)] if region_bits > 39 else None          # 512GB
            self.LEVEL1_BIT_RANGE = [30, min(39, region_bits)] if region_bits > 30 else None          # 1GB
            self.LEVEL2_BIT_RANGE = [21, min(30, region_bits)] if region_bits > 21 else None          # 2MB
            self.LEVEL3_BIT_RANGE = [12, min(21, region_bits)] if region_bits > 12 else None          # 4KB
            self.OFFSET_BIT_RANGE = [0, 12]
        elif granule_bits == 14: # 16KB granule
            self.LEVELM1_BIT_RANGE = None
            self.LEVEL0_BIT_RANGE = [47, min(IA_LVA_MAX, region_bits)] if region_bits > 47 else None  # no block descriptor
            self.LEVEL1_BIT_RANGE = [36, min(47, region_bits)] if region_bits > 36 else None          # 64GB
            self.LEVEL2_BIT_RANGE = [25, min(36, region_bits)] if region_bits > 25 else None          # 32MB
            self.LEVEL3_BIT_RANGE = [14, min(25, region_bits)] if region_bits > 14 else None          # 16KB
            self.OFFSET_BIT_RANGE = [0, 14]
        elif granule_bits == 16: # 64KB granule
            self.LEVELM1_BIT_RANGE = None
            self.LEVEL0_BIT_RANGE = None
            self.LEVEL1_BIT_RANGE = [42, min(IA_LVA_MAX, region_bits)] if region_bits > 42 else None  # 4TB
            self.LEVEL2_BIT_RANGE = [29, min(42, region_bits)] if region_bits > 29 else None          # 512MB
            self.LEVEL3_BIT_RANGE = [16, min(29, region_bits)] if region_bits > 16 else None          # 64KB
            self.OFFSET_BIT_RANGE = [0, 16]
        else:
            if not self.silent:
                self.err("Unsupported granule_bits")
            return

        if not self.silent:
            self.quiet_info("granule_bits: {:d}".format(granule_bits))
            self.quiet_info("LEVELM1_BIT_RANGE: " + str(self.LEVELM1_BIT_RANGE))
            self.quiet_info("LEVEL0_BIT_RANGE: " + str(self.LEVEL0_BIT_RANGE))
            self.quiet_info("LEVEL1_BIT_RANGE: " + str(self.LEVEL1_BIT_RANGE))
            self.quiet_info("LEVEL2_BIT_RANGE: " + str(self.LEVEL2_BIT_RANGE))
            self.quiet_info("LEVEL3_BIT_RANGE: " + str(self.LEVEL3_BIT_RANGE))
            self.quiet_info("OFFSET_BIT_RANGE: " + str(self.OFFSET_BIT_RANGE))
        return

    def do_pagewalk(self, table_base, granule_bits, region_start, start_level=0, is_stage2=False, is_2VAranges=False):
        # table_base: The start address of pagewalk.
        # granule_bits: One of [12, 14, 16]; It specifies how to separate the bits used for address translation.
        # region_start: The base address of translated address.
        # start_level: Only used at stage2. In stage2, the starting level will fluctuate.
        # is_stage2: Whether VTTBR0_EL2 or not. Affects how the bitfield of each entry is interpreted.
        # is_2VAranges: Whether the target EL has TTBR0 and TTBR1. Affects how the bitfield of each entry is interpreted.
        self.mappings = []

        is_4k_granule = granule_bits == 12
        is_16k_granule = granule_bits == 14
        is_64k_granule = granule_bits == 16

        def get_entries_per_table(BIT_RANGE):
            entries_per_table = 2 ** (BIT_RANGE[1] - BIT_RANGE[0])
            if not self.silent:
                self.quiet_info("Entries per table: {:d}".format(entries_per_table))
            return entries_per_table

        def has_next_level(entry): # for Level0, 1, 2 but not Level3
            return (entry & 0b11) == 0b11

        flags = []
        TABLE_BASE = [[region_start, table_base, flags]]

        # level -1 parse for 4KB granule
        if not self.silent:
            self.quiet_add_out(titlify("LEVEL -1"))
        if self.LEVELM1_BIT_RANGE is not None and start_level == -1:
            entries_per_table = get_entries_per_table(self.LEVELM1_BIT_RANGE)
            LEVELM1 = []
            COUNT = 0
            for va_base, table_base, parent_flags in TABLE_BASE:
                entries = self.read_mem_wrapper(table_base, 8 * entries_per_table)
                entries = slice_unpack(entries, 8)
                COUNT += len(entries)
                for i, entry in enumerate(entries):
                    # present flag
                    if entry & 1 == 0:
                        continue

                    # calc virtual address
                    new_va = va_base + (i << self.LEVELM1_BIT_RANGE[0])
                    new_va_end = new_va + (1 << self.LEVELM1_BIT_RANGE[0])

                    # calc flags
                    flags = parent_flags.copy()
                    if has_next_level(entry):
                        if is_stage2:
                            # VTTBR_EL2 does not have level -1
                            raise
                        elif is_2VAranges:
                            if ((entry >> 59) & 1) == 1:
                                flags.append("PXNTable-1")
                            if ((entry >> 60) & 1) == 1:
                                flags.append("UXNTable-1")
                            flags.append("APTable-1={:02b}".format((entry >> 61) & 0b11))
                            if ((entry >> 63) & 1) == 1:
                                flags.append("NSTable-1")
                        else:
                            if ((entry >> 60) & 1) == 1:
                                flags.append("XNTable-1") # Use XNTable, not UXNTable # PXNTable is undefined
                            flags.append("APTable-1={:02b}".format((entry >> 61) & 0b11 & 0b10)) # APTable[0] must be 0
                            if ((entry >> 63) & 1) == 1:
                                flags.append("NSTable-1")
                    else:
                        # In ARMv8.7, level -1 has no block descriptors
                        raise

                    # calc next table / output phys addr (drop the flag bits)
                    if has_next_level(entry):
                        next_level_table = (entry & 0x0003fffffffff000) | (((entry >> 8) & 0b11) << 50)
                    else:
                        # In ARMv8.7, level -1 has no block descriptors
                        raise

                    # make entry
                    if has_next_level(entry):
                        LEVELM1.append([new_va, next_level_table, flags])
                        entry_type = "TABLE"
                    else:
                        # In ARMv8.7, level -1 has no block descriptors
                        raise

                    # dump
                    if self.print_each_level:
                        if self.is_not_trace_target(new_va, new_va_end):
                            continue
                        addr = table_base + i * 8
                        fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                        line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                        if self.is_not_filter_target(line):
                            continue
                        self.add_out(line)

            if not self.silent:
                self.quiet_info("Number of entries: {:d}".format(COUNT))
                self.quiet_info("Level -1 Entry: {:d}".format(len(LEVELM1)))
                self.quiet_info("Invalid entries: {:d}".format(COUNT - len(LEVELM1)))
            self.mappings += []
        else:
            if not self.silent:
                self.quiet_info("LEVEL -1 is skipped")
            LEVELM1 = TABLE_BASE

        # level 0 parse for 4KB/16KB granule
        if not self.silent:
            self.quiet_add_out(titlify("LEVEL 0"))
        if self.LEVEL0_BIT_RANGE is not None and start_level <= 0:
            entries_per_table = get_entries_per_table(self.LEVEL0_BIT_RANGE)
            LEVEL0 = []
            GB512 = []
            COUNT = 0
            for va_base, table_base, parent_flags in LEVELM1:
                entries = self.read_mem_wrapper(table_base, 8 * entries_per_table)
                entries = slice_unpack(entries, 8)
                COUNT += len(entries)
                for i, entry in enumerate(entries):
                    # present flag
                    if entry & 1 == 0:
                        continue

                    # calc virtual address
                    new_va = va_base + (i << self.LEVEL0_BIT_RANGE[0])
                    new_va_end = new_va + (1 << self.LEVEL0_BIT_RANGE[0])

                    # calc flags
                    flags = parent_flags.copy()
                    if has_next_level(entry):
                        if is_stage2:
                            # There are no flags in the table for VTTBR0_EL2.
                            pass
                        elif is_2VAranges:
                            if ((entry >> 59) & 1) == 1:
                                flags.append("PXNTable0")
                            if ((entry >> 60) & 1) == 1:
                                flags.append("UXNTable0")
                            flags.append("APTable0={:02b}".format((entry >> 61) & 0b11))
                            if ((entry >> 63) & 1) == 1:
                                flags.append("NSTable0")
                        else:
                            if ((entry >> 60) & 1) == 1:
                                flags.append("XNTable0") # Use XNTable, not UXNTable # PXNTable is undefined
                            flags.append("APTable0={:02b}".format((entry >> 61) & 0b11 & 0b10)) # APTable[0] must be 0
                            if ((entry >> 63) & 1) == 1:
                                flags.append("NSTable0")
                    else:
                        if is_stage2:
                            flags.append("MemAttr={:#x}".format((entry >> 2) & 0b1111))
                            flags.append("S2AP={:02b}".format((entry >> 6) & 0b11))
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            flags.append("XN={:02b}".format((entry >> 53) & 0b11)) # Use XN, not UXN
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))
                        elif is_2VAranges:
                            flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                            if ((entry >> 5) & 1) == 1:
                                flags.append("NS")
                            flags.append("AP={:02b}".format((entry >> 6) & 0b11))
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 11) & 1) == 1:
                                flags.append("nG")
                            if ((entry >> 16) & 1) == 1:
                                flags.append("nT")
                            if ((entry >> 50) & 1) == 1:
                                flags.append("GP")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            if ((entry >> 53) & 1) == 1:
                                flags.append("PXN")
                            if ((entry >> 54) & 1) == 1:
                                flags.append("UXN")
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))
                        else:
                            flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                            if ((entry >> 5) & 1) == 1:
                                flags.append("NS")
                            flags.append("AP={:02b}".format((entry >> 6) & 0b11 & 0b10)) # AP[0] must be 0
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 11) & 1) == 1:
                                flags.append("nG")
                            if ((entry >> 16) & 1) == 1:
                                flags.append("nT")
                            if ((entry >> 50) & 1) == 1:
                                flags.append("GP")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            if ((entry >> 54) & 1) == 1:
                                flags.append("XN") # Use XN, not UXN # PXN is undefined
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))

                    # calc next table / output phys addr (drop the flag bits)
                    if has_next_level(entry):
                        if self.FEAT_LPA:
                            next_level_table = (entry & 0x0003fffffffff000) | (((entry >> 8) & 0b11) << 50)
                        else:
                            next_level_table = entry & 0x0000fffffffff000
                    else:
                        if self.FEAT_LPA:
                            phys_addr = (entry & 0x0003fffffffe0000) | (((entry >> 8) & 0b11) << 50)
                        else:
                            # In ARMv8.7, level 0 + no-FEAT_LPA has no block descriptors
                            raise

                    # make entry
                    if has_next_level(entry):
                        LEVEL0.append([new_va, next_level_table, flags])
                        entry_type = "TABLE"
                    else:
                        virt_addr = new_va
                        page_count = 1
                        if is_stage2:
                            flag_string = self.format_flags_stage2(flags)
                        else:
                            flag_string = self.format_flags(flags)
                        if is_4k_granule:
                            page_size = 512 * 1024 * 1024 * 1024
                            GB512.append([virt_addr, phys_addr, page_size, page_count, flag_string])
                            entry_type = "512GB-PAGE"
                        else:
                            raise

                    # dump
                    if self.print_each_level:
                        if self.is_not_trace_target(new_va, new_va_end):
                            continue
                        addr = table_base + i * 8
                        fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                        line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                        if self.is_not_filter_target(line):
                            continue
                        self.add_out(line)

            if not self.silent:
                self.quiet_info("Number of entries: {:d}".format(COUNT))
                self.quiet_info("Level 0 Entry: {:d}".format(len(LEVEL0)))
                self.quiet_info("PT Entry (512GB): {:d}".format(len(GB512)))
                self.quiet_info("Invalid entries: {:d}".format(COUNT - len(LEVEL0) - len(GB512)))
            self.mappings += GB512
        else:
            if not self.silent:
                self.quiet_info("LEVEL 0 is skipped")
            LEVEL0 = TABLE_BASE

        # level 1 parse for 4KB/16KB/64KB granule
        if not self.silent:
            self.quiet_add_out(titlify("LEVEL 1"))
        if self.LEVEL1_BIT_RANGE is not None and start_level <= 1:
            entries_per_table = get_entries_per_table(self.LEVEL1_BIT_RANGE)
            LEVEL1 = []
            GB1 = []
            TB4 = []
            GB64 = []
            COUNT = 0
            for va_base, table_base, parent_flags in LEVEL0:
                entries = self.read_mem_wrapper(table_base, 8 * entries_per_table)
                entries = slice_unpack(entries, 8)
                COUNT += len(entries)
                for i, entry in enumerate(entries):
                    # present flag
                    if entry & 1 == 0:
                        continue

                    # calc virtual address
                    new_va = va_base + (i << self.LEVEL1_BIT_RANGE[0])
                    new_va_end = new_va + (1 << self.LEVEL1_BIT_RANGE[0])

                    # calc flags
                    flags = parent_flags.copy()
                    if has_next_level(entry):
                        if is_stage2:
                            # There are no flags in the table for VTTBR0_EL2.
                            pass
                        elif is_2VAranges:
                            if ((entry >> 59) & 1) == 1:
                                flags.append("PXNTable1")
                            if ((entry >> 60) & 1) == 1:
                                flags.append("UXNTable1")
                            flags.append("APTable1={:02b}".format((entry >> 61) & 0b11))
                            if ((entry >> 63) & 1) == 1:
                                flags.append("NSTable1")
                        else:
                            if ((entry >> 60) & 1) == 1:
                                flags.append("XNTable1") # Use XNTable, not UXNTable # PXNTable is undefined
                            flags.append("APTable1={:02b}".format((entry >> 61) & 0b11 & 0b10)) # APTable[0] must be 0
                            if ((entry >> 63) & 1) == 1:
                                flags.append("NSTable1")
                    else:
                        if is_stage2:
                            flags.append("MemAttr={:#x}".format((entry >> 2) & 0b1111))
                            flags.append("S2AP={:02b}".format((entry >> 6) & 0b11))
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            flags.append("XN={:02b}".format((entry >> 53) & 0b11)) # Use XN, not UXN
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))
                        elif is_2VAranges:
                            flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                            if ((entry >> 5) & 1) == 1:
                                flags.append("NS")
                            flags.append("AP={:02b}".format((entry >> 6) & 0b11))
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 11) & 1) == 1:
                                flags.append("nG")
                            if ((entry >> 16) & 1) == 1:
                                flags.append("nT")
                            if ((entry >> 50) & 1) == 1:
                                flags.append("GP")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            if ((entry >> 53) & 1) == 1:
                                flags.append("PXN")
                            if ((entry >> 54) & 1) == 1:
                                flags.append("UXN")
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))
                        else:
                            flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                            if ((entry >> 5) & 1) == 1:
                                flags.append("NS")
                            flags.append("AP={:02b}".format((entry >> 6) & 0b11 & 0b10)) # AP[0] must be 0
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 11) & 1) == 1:
                                flags.append("nG")
                            if ((entry >> 16) & 1) == 1:
                                flags.append("nT")
                            if ((entry >> 50) & 1) == 1:
                                flags.append("GP")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            if ((entry >> 54) & 1) == 1:
                                flags.append("XN") # Use XN, not UXN # PXN is undefined
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))

                    # calc next table / output phys addr (drop the flag bits)
                    if has_next_level(entry):
                        if self.FEAT_LPA:
                            if is_64k_granule:
                                next_level_table = (entry & 0x0000ffffffff0000) | (((entry >> 12) & 0b1111) << 48)
                            else:
                                next_level_table = (entry & 0x0003fffffffff000) | (((entry >> 8) & 0b11) << 50)
                        else:
                            next_level_table = entry & 0x0000fffffffff000
                    else:
                        if self.FEAT_LPA:
                            if is_64k_granule:
                                phys_addr = (entry & 0x0000fffffffe0000) | (((entry >> 12) & 0b1111) << 48)
                            else:
                                phys_addr = (entry & 0x0003fffffffe0000) | (((entry >> 8) & 0b11) << 50)
                        else:
                            phys_addr = entry & 0x0000fffffffe0000

                    # make entry
                    if has_next_level(entry):
                        LEVEL1.append([new_va, next_level_table, flags])
                        entry_type = "TABLE"
                    else:
                        virt_addr = new_va
                        page_count = 1
                        if is_stage2:
                            flag_string = self.format_flags_stage2(flags)
                        else:
                            flag_string = self.format_flags(flags)
                        if is_4k_granule:
                            page_size = 1 * 1024 * 1024 * 1024
                            GB1.append([virt_addr, phys_addr, page_size, page_count, flag_string])
                            entry_type = "1GB-PAGE"
                        elif is_16k_granule:
                            page_size = 64 * 1024 * 1024 * 1024
                            GB64.append([virt_addr, phys_addr, page_size, page_count, flag_string])
                            entry_type = "64GB-PAGE"
                        elif is_64k_granule:
                            page_size = 4 * 1024 * 1024 * 1024 * 1024
                            TB4.append([virt_addr, phys_addr, page_size, page_count, flag_string])
                            entry_type = "4TB-PAGE"

                    # dump
                    if self.print_each_level:
                        if self.is_not_trace_target(new_va, new_va_end):
                            continue
                        addr = table_base + i * 8
                        fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                        line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                        if self.is_not_filter_target(line):
                            continue
                        self.add_out(line)

            if not self.silent:
                self.quiet_info("Number of entries: {:d}".format(COUNT))
                self.quiet_info("Level 1 Entry: {:d}".format(len(LEVEL1)))
                self.quiet_info("PT Entry (1GB): {:d}".format(len(GB1)))
                self.quiet_info("PT Entry (64GB): {:d}".format(len(GB64)))
                self.quiet_info("PT Entry (4TB): {:d}".format(len(TB4)))
                self.quiet_info("Invalid entries: {:d}".format(COUNT - len(LEVEL1) - len(GB1) - len(GB64) - len(TB4)))
            self.mappings += GB1 + GB64 + TB4
        else:
            if not self.silent:
                self.quiet_info("LEVEL 1 is skipped")
            LEVEL1 = LEVEL0

        # level 2 parse for 4KB/16KB/64KB granule
        if not self.silent:
            self.quiet_add_out(titlify("LEVEL 2"))
        if self.LEVEL2_BIT_RANGE is not None and start_level <= 2:
            entries_per_table = get_entries_per_table(self.LEVEL2_BIT_RANGE)
            LEVEL2 = []
            MB2 = []
            MB32 = []
            MB512 = []
            COUNT = 0
            for va_base, table_base, parent_flags in LEVEL1:
                entries = self.read_mem_wrapper(table_base, 8 * entries_per_table)
                entries = slice_unpack(entries, 8)
                COUNT += len(entries)
                for i, entry in enumerate(entries):
                    # present flag
                    if entry & 1 == 0:
                        continue

                    # calc virtual address
                    new_va = va_base + (i << self.LEVEL2_BIT_RANGE[0])
                    new_va_end = new_va + (1 << self.LEVEL2_BIT_RANGE[0])

                    # calc flags
                    flags = parent_flags.copy()
                    if has_next_level(entry):
                        if is_stage2:
                            # There are no flags in the table for VTTBR0_EL2.
                            pass
                        elif is_2VAranges:
                            if ((entry >> 59) & 1) == 1:
                                flags.append("PXNTable2")
                            if ((entry >> 60) & 1) == 1:
                                flags.append("UXNTable2")
                            flags.append("APTable2={:02b}".format((entry >> 61) & 0b11))
                            if ((entry >> 63) & 1) == 1:
                                flags.append("NSTable2")
                        else:
                            if ((entry >> 60) & 1) == 1:
                                flags.append("XNTable2") # Use XNTable, not UXNTable # PXNTable is undefined
                            flags.append("APTable2={:02b}".format((entry >> 61) & 0b11 & 0b10)) # APTable[0] must be 0
                            if ((entry >> 63) & 1) == 1:
                                flags.append("NSTable2")
                    else:
                        if is_stage2:
                            flags.append("MemAttr={:#x}".format((entry >> 2) & 0b1111))
                            flags.append("S2AP={:02b}".format((entry >> 6) & 0b11))
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            flags.append("XN={:02b}".format((entry >> 53) & 0b11)) # Use XN, not UXN
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))
                        elif is_2VAranges:
                            flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                            if ((entry >> 5) & 1) == 1:
                                flags.append("NS")
                            flags.append("AP={:02b}".format((entry >> 6) & 0b11))
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 11) & 1) == 1:
                                flags.append("nG")
                            if ((entry >> 16) & 1) == 1:
                                flags.append("nT")
                            if ((entry >> 50) & 1) == 1:
                                flags.append("GP")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            if ((entry >> 53) & 1) == 1:
                                flags.append("PXN")
                            if ((entry >> 54) & 1) == 1:
                                flags.append("UXN")
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))
                        else:
                            flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                            if ((entry >> 5) & 1) == 1:
                                flags.append("NS")
                            flags.append("AP={:02b}".format((entry >> 6) & 0b11 & 0b10)) # AP[0] must be 0
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 11) & 1) == 1:
                                flags.append("nG")
                            if ((entry >> 16) & 1) == 1:
                                flags.append("nT")
                            if ((entry >> 50) & 1) == 1:
                                flags.append("GP")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            if ((entry >> 54) & 1) == 1:
                                flags.append("XN") # Use XN, not UXN # PXN is undefined
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))

                    # calc next table / output phys addr (drop the flag bits)
                    if has_next_level(entry):
                        if self.FEAT_LPA:
                            if is_64k_granule:
                                next_level_table = (entry & 0x0000ffffffff0000) | (((entry >> 12) & 0b1111) << 48)
                            else:
                                next_level_table = (entry & 0x0003fffffffff000) | (((entry >> 8) & 0b11) << 50)
                        else:
                            next_level_table = entry & 0x0000fffffffff000
                    else:
                        if self.FEAT_LPA:
                            if is_64k_granule:
                                phys_addr = (entry & 0x0000fffffffe0000) | (((entry >> 12) & 0b1111) << 48)
                            else:
                                phys_addr = (entry & 0x0003fffffffe0000) | (((entry >> 8) & 0b11) << 50)
                        else:
                            phys_addr = entry & 0x0000fffffffe0000

                    # make entry
                    if has_next_level(entry):
                        LEVEL2.append([new_va, next_level_table, flags])
                        entry_type = "TABLE"
                    else:
                        virt_addr = new_va
                        page_count = 1
                        if is_stage2:
                            flag_string = self.format_flags_stage2(flags)
                        else:
                            flag_string = self.format_flags(flags)
                        if is_4k_granule:
                            page_size = 2 * 1024 * 1024
                            MB2.append([virt_addr, phys_addr, page_size, page_count, flag_string])
                            entry_type = "2MB-PAGE"
                        elif is_16k_granule:
                            page_size = 32 * 1024 * 1024
                            MB32.append([virt_addr, phys_addr, page_size, page_count, flag_string])
                            entry_type = "32MB-PAGE"
                        elif is_64k_granule:
                            page_size = 512 * 1024 * 1024
                            MB512.append([virt_addr, phys_addr, page_size, page_count, flag_string])
                            entry_type = "512MB-PAGE"

                    # dump
                    if self.print_each_level:
                        if self.is_not_trace_target(new_va, new_va_end):
                            continue
                        addr = table_base + i * 8
                        fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                        line = fmt.format(addr, entry, new_va, new_va_end, entry_type, " ".join(flags))
                        if self.is_not_filter_target(line):
                            continue
                        self.add_out(line)

            if not self.silent:
                self.quiet_info("Number of entries: {:d}".format(COUNT))
                self.quiet_info("Level 2 Entry: {:d}".format(len(LEVEL2)))
                self.quiet_info("PT Entry (2MB): {:d}".format(len(MB2)))
                self.quiet_info("PT Entry (32MB): {:d}".format(len(MB32)))
                self.quiet_info("PT Entry (512MB): {:d}".format(len(MB512)))
                self.quiet_info("Invalid entries: {:d}".format(COUNT - len(LEVEL2) - len(MB2) - len(MB32) - len(MB512)))
            self.mappings += MB2 + MB32 + MB512
        else:
            if not self.silent:
                self.quiet_info("LEVEL 2 is skipped")
            LEVEL2 = LEVEL1

        # level 3 parse for 4KB/16KB/64KB granule
        if not self.silent:
            self.quiet_add_out(titlify("LEVEL 3"))
        if self.LEVEL3_BIT_RANGE is not None and start_level <= 3:
            entries_per_table = get_entries_per_table(self.LEVEL3_BIT_RANGE)
            KB4 = []
            KB16 = []
            KB64 = []
            COUNT = 0
            flag_cache = {}

            tqdm = GefUtil.get_tqdm(not self.quiet)
            for va_base, table_base, parent_flags in tqdm(LEVEL2, leave=False):
                entries = self.read_mem_wrapper(table_base, 8 * entries_per_table)
                entries = slice_unpack(entries, 8)
                COUNT += len(entries)
                for i, entry in enumerate(entries):
                    # present flag
                    if entry & 1 == 0:
                        continue

                    # calc virtual address
                    virt_addr = va_base + (i << self.LEVEL3_BIT_RANGE[0])
                    virt_addr_end = virt_addr + (1 << self.LEVEL3_BIT_RANGE[0])

                    # calc flags
                    flags = parent_flags.copy()
                    if (entry & 0b11) == 0b11:
                        if is_stage2:
                            flags.append("MemAttr={:#x}".format((entry >> 2) & 0b1111))
                            flags.append("S2AP={:02b}".format((entry >> 6) & 0b11))
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            flags.append("XN={:02b}".format((entry >> 53) & 0b11)) # Use XN, not UXN
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))
                        elif is_2VAranges:
                            # This route passes many times, so make a memo
                            entry_flags_key = entry & 0x787c000000010ffc
                            x = flag_cache.get(entry_flags_key, None)
                            if x is not None:
                                flags.extend(x)
                            else:
                                _flags = []
                                _flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                                if ((entry >> 5) & 1) == 1:
                                    _flags.append("NS")
                                _flags.append("AP={:02b}".format((entry >> 6) & 0b11))
                                _flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                                if ((entry >> 10) & 1) == 1:
                                    _flags.append("AF")
                                if ((entry >> 11) & 1) == 1:
                                    _flags.append("nG")
                                if ((entry >> 16) & 1) == 1:
                                    _flags.append("nT")
                                if ((entry >> 50) & 1) == 1:
                                    _flags.append("GP")
                                if ((entry >> 51) & 1) == 1:
                                    _flags.append("DBM")
                                if ((entry >> 52) & 1) == 1:
                                    _flags.append("Contiguous")
                                if ((entry >> 53) & 1) == 1:
                                    _flags.append("PXN")
                                if ((entry >> 54) & 1) == 1:
                                    _flags.append("UXN")
                                _flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))
                                flag_cache[entry_flags_key] = _flags
                                flags.extend(_flags)
                        else:
                            flags.append("AttrIndx={:03b}".format((entry >> 2) & 0b111))
                            if ((entry >> 5) & 1) == 1:
                                flags.append("NS")
                            flags.append("AP={:02b}".format((entry >> 6) & 0b11 & 0b10)) # AP[0] must be 0
                            flags.append("SH={:02b}".format((entry >> 8) & 0b11))
                            if ((entry >> 10) & 1) == 1:
                                flags.append("AF")
                            if ((entry >> 11) & 1) == 1:
                                flags.append("nG")
                            if ((entry >> 16) & 1) == 1:
                                flags.append("nT")
                            if ((entry >> 50) & 1) == 1:
                                flags.append("GP")
                            if ((entry >> 51) & 1) == 1:
                                flags.append("DBM")
                            if ((entry >> 52) & 1) == 1:
                                flags.append("Contiguous")
                            if ((entry >> 54) & 1) == 1:
                                flags.append("XN") # Use XN, not UXN # PXN is undefined
                            flags.append("PBHA={:#x}".format((entry >> 59) & 0b1111))
                    else:
                        # In ARMv8.7, level 3 has no table descriptors
                        raise

                    # calc next table / output phys addr (drop the flag bits)
                    if is_4k_granule:
                        if self.FEAT_LPA:
                            phys_addr = (entry & 0x0003fffffffff000) | (((entry >> 8) & 0b11) << 50)
                        else:
                            phys_addr = entry & 0x0000fffffffff000
                    elif is_16k_granule:
                        if self.FEAT_LPA:
                            phys_addr = (entry & 0x0003ffffffffc000) | (((entry >> 8) & 0b11) << 50)
                        else:
                            phys_addr = entry & 0x0000ffffffffc000
                    elif is_64k_granule:
                        if self.FEAT_LPA:
                            phys_addr = (entry & 0x0000ffffffff0000) | (((entry >> 12) & 0b1111) << 48)
                        else:
                            phys_addr = entry & 0x0000ffffffff0000

                    # make entry
                    page_count = 1
                    if is_stage2:
                        flag_string = self.format_flags_stage2(flags)
                    else:
                        flag_string = self.format_flags(flags)
                    if is_4k_granule:
                        page_size = 4 * 1024
                        KB4.append([virt_addr, phys_addr, page_size, page_count, flag_string])
                        entry_type = "4KB-PAGE"
                    elif is_16k_granule:
                        page_size = 16 * 1024
                        KB16.append([virt_addr, phys_addr, page_size, page_count, flag_string])
                        entry_type = "16KB-PAGE"
                    elif is_64k_granule:
                        page_size = 64 * 1024
                        KB64.append([virt_addr, phys_addr, page_size, page_count, flag_string])
                        entry_type = "64KB-PAGE"

                    # dump
                    if self.print_each_level:
                        if self.is_not_trace_target(virt_addr, virt_addr_end):
                            continue
                        addr = table_base + i * 8
                        fmt = "{:#018x}: {:#018x} (virt:{:#018x}-{:#018x},type:{:s}) {:s}"
                        line = fmt.format(addr, entry, virt_addr, virt_addr_end, entry_type, " ".join(flags))
                        if self.is_not_filter_target(line):
                            continue
                        self.add_out(line)

            if not self.silent:
                self.quiet_info("Number of entries: {:d}".format(COUNT))
                self.quiet_info("PT Entry (4KB): {:d}".format(len(KB4)))
                self.quiet_info("PT Entry (16KB): {:d}".format(len(KB16)))
                self.quiet_info("PT Entry (64KB): {:d}".format(len(KB64)))
                self.quiet_info("Invalid entries: {:d}".format(COUNT - len(KB4) - len(KB16) - len(KB64)))
            self.mappings += KB4 + KB16 + KB64
        else:
            if not self.silent:
                self.quiet_info("LEVEL 3 is skipped")

        # Finalize
        if not self.silent:
            self.quiet_add_out(titlify("Total"))
            self.quiet_info("PT Entry (Total): {:d}".format(len(self.mappings)))
        self.mappings = sorted(self.mappings)
        return

    def switch_el(self):
        self.SAVED_CPSR = 0
        CPSR = get_register("$cpsr") & 0xffffffff
        CurrentEL = int((CPSR >> 2) & 0b11)
        # change EL
        try:
            if self.TargetEL < 1 or self.TargetEL > 3:
                self.err("Invalid argument (ELx>=1 && ELx<=3)")
                return
            if self.TargetEL != CurrentEL:
                self.SAVED_CPSR = CPSR
                CPSR = CPSR & ~(0b11 << 2) # clear EL
                CPSR |= self.TargetEL << 2 # set desired EL
                gdb.parse_and_eval("$cpsr = {:#x}".format(CPSR))
                self.quiet_info("Moving to EL{:d}".format(self.TargetEL))
        except ValueError:
            self.err("Invalid argument (ELx integer required)")
            return
        except gdb.error:
            self.err("Maybe unsupported to change to EL{:d}".format(self.TargetEL))
            return
        # reload CPSR
        CPSR = get_register("$cpsr") & 0xffffffff
        CurrentEL = int((CPSR >> 2) & 0b11)
        self.quiet_info("CPSR: EL{:d}".format(CurrentEL))
        return True

    def revert_el(self):
        if self.SAVED_CPSR:
            gdb.parse_and_eval("$cpsr = {:#x}".format(self.SAVED_CPSR))
            SavedEL = (self.SAVED_CPSR >> 2) & 0b11
            self.quiet_info("Moving back to EL{:d}".format(SavedEL))
        return

    def pagewalk_TTBR0_EL1(self):
        self.add_out(titlify("$TTBR0_EL1"))

        TTBR0_EL1 = get_register("$TTBR0_EL1")
        TCR_EL1 = get_register("$TCR_EL1")
        if TTBR0_EL1 == 0:
            self.warn("Maybe unused TTBR0_EL1")
            return

        IPS = (TCR_EL1 >> 32) & 0b111
        TG0 = (TCR_EL1 >> 14) & 0b11
        T0SZ = TCR_EL1 & 0b111111
        try:
            granule_bits = {0b00: 12, 0b01: 16, 0b10: 14}[TG0]
        except KeyError:
            self.err("Unsupported $TCR_EL1.TG0")
            return
        region_start = 0
        region_end = region_start + (2 ** (64 - T0SZ))
        region_bits = GefUtil.log2(region_end - region_start)
        page_size = 2 ** (granule_bits - 10)
        intermediate_pa_size = 32 + (IPS * 4)

        if IPS == 0b110:
            if self.FEAT_LPA:
                translation_base_addr = (TTBR0_EL1 & 0xffffffffffc0) | (((TTBR0_EL1 >> 2) & 0b1111) << 48)
            else:
                self.err("Unsupported FEAT_LPA and IPS pair")
                return
        else:
            translation_base_addr = TTBR0_EL1 & 0xfffffffffffe

        self.quiet_info("$TTBR0_EL1: {:#x}".format(TTBR0_EL1))
        self.quiet_info("$TCR_EL1: {:#x}".format(TCR_EL1))
        self.quiet_info("Intermediate Physical Address Size: {:d} bits".format(intermediate_pa_size))
        self.quiet_info("EL1 User Region: {:#018x} - {:#018x} ({:d} bits)".format(region_start, region_end - 1, region_bits))
        self.quiet_info("EL1 User Page Size: {:d}KB (per page)".format(page_size))

        self.parse_bit_range(granule_bits, region_bits)
        if not self.use_cache or not self.ttbr0el1_mappings:
            self.flags_strings_cache = {}
            self.do_pagewalk(translation_base_addr, granule_bits, region_start, is_2VAranges=True)
            self.flags_strings_cache = None
            self.merging()
            self.ttbr0el1_mappings = self.mappings.copy()
        self.make_out(self.ttbr0el1_mappings)
        return

    def pagewalk_TTBR1_EL1(self):
        self.add_out(titlify("$TTBR1_EL1"))

        TTBR1_EL1 = get_register("$TTBR1_EL1")
        TCR_EL1 = get_register("$TCR_EL1")
        if TTBR1_EL1 == 0:
            self.warn("Maybe unused TTBR1_EL1")
            return

        IPS = (TCR_EL1 >> 32) & 0b111
        TG1 = (TCR_EL1 >> 30) & 0b11
        T1SZ = (TCR_EL1 >> 16) & 0b111111
        try:
            granule_bits = {0b01: 14, 0b10: 12, 0b11: 16}[TG1]
        except KeyError:
            self.err("Unsupported $TCR_EL1.TG1")
            return
        region_end = 2 ** 64
        region_start = region_end - (2 ** (64 - T1SZ))
        region_bits = GefUtil.log2(region_end - region_start)
        page_size = 2 ** (granule_bits - 10)
        intermediate_pa_size = 32 + (IPS * 4)

        if IPS == 0b110:
            if self.FEAT_LPA:
                translation_base_addr = (TTBR1_EL1 & 0xffffffffffc0) | (((TTBR1_EL1 >> 2) & 0b1111) << 48)
            else:
                self.err("Unsupported FEAT_LPA and IPS pair")
                return
        else:
            translation_base_addr = TTBR1_EL1 & 0xfffffffffffe

        self.quiet_info("$TTBR1_EL1: {:#x}".format(TTBR1_EL1))
        self.quiet_info("$TCR_EL1: {:#x}".format(TCR_EL1))
        self.quiet_info("Intermediate Physical Address Size: {:d} bits".format(intermediate_pa_size))
        self.quiet_info("EL1 Kernel Region: {:#018x} - {:#018x} ({:d} bits)".format(region_start, region_end - 1, region_bits))
        self.quiet_info("EL1 Kernel Page Size: {:d}KB (per page)".format(page_size))

        self.parse_bit_range(granule_bits, region_bits)
        if not self.use_cache or not self.ttbr1el1_mappings:
            self.flags_strings_cache = {}
            self.do_pagewalk(translation_base_addr, granule_bits, region_start, is_2VAranges=True)
            self.flags_strings_cache = None
            self.merging()
            self.ttbr1el1_mappings = self.mappings.copy()
        self.make_out(self.ttbr1el1_mappings)
        return

    def pagewalk_VTTBR_EL2(self):
        if not self.silent:
            self.add_out(titlify("$VTTBR_EL2"))

        VTTBR_EL2 = get_register("$VTTBR_EL2")
        VTCR_EL2 = get_register("$VTCR_EL2")
        if VTTBR_EL2 == 0:
            if not self.silent:
                self.warn("Maybe unused VTTBR_EL2")
            return

        SL2 = (VTCR_EL2 >> 33) & 0b1
        PS = (VTCR_EL2 >> 16) & 0b11
        TG0 = (VTCR_EL2 >> 14) & 0b11
        SL0 = (VTCR_EL2 >> 6) & 0b11
        T0SZ = VTCR_EL2 & 0b111111
        try:
            granule_bits = {0b00: 12, 0b01: 16, 0b10: 14}[TG0]
        except KeyError:
            if not self.silent:
                self.err("Unsupported $VTCR_EL2.TG0")
            return
        region_start = 0
        region_end = region_start + (2 ** (64 - T0SZ))
        region_bits = GefUtil.log2(region_end - region_start)
        page_size = 2 ** (granule_bits - 10)
        pa_size = 32 + (PS * 4)

        if self.FEAT_TTST:
            if SL0 == 0b00:
                if TG0 == 0b00:
                    if self.FEAT_LPA2 and SL2 == 1:
                        stage2_start_level = -1
                    else:
                        stage2_start_level = 2
                else:
                    stage2_start_level = 3
            elif SL0 == 0b01:
                if TG0 == 0b00:
                    if self.FEAT_LPA2 and SL2 == 1:
                        if not self.silent:
                            self.err("Unsupported stage2 start level")
                        return
                    else:
                        stage2_start_level = 1
                else:
                    stage2_start_level = 2
            elif SL0 == 0b10:
                if TG0 == 0b00:
                    if self.FEAT_LPA2 and SL2 == 1:
                        if not self.silent:
                            self.err("Unsupported stage2 start level")
                        return
                    else:
                        stage2_start_level = 0
                else:
                    stage2_start_level = 1
            elif SL0 == 0b11:
                if TG0 == 0b00:
                    if self.FEAT_LPA2 and SL2 == 1:
                        if not self.silent:
                            self.err("Unsupported stage2 start level")
                        return
                    else:
                        stage2_start_level = 3
                else:
                    stage2_start_level = 0
        else:
            if SL0 == 0b00:
                if TG0 == 0b00:
                    stage2_start_level = 2
                else:
                    stage2_start_level = 3
            elif SL0 == 0b01:
                if TG0 == 0b00:
                    stage2_start_level = 1
                else:
                    stage2_start_level = 2
            elif SL0 == 0b10:
                if TG0 == 0b00:
                    stage2_start_level = 0
                else:
                    stage2_start_level = 1
            else:
                if not self.silent:
                    self.err("Unsupported stage2 start level")
                return

        if PS == 0b110:
            if self.FEAT_LPA:
                translation_base_addr = (VTTBR_EL2 & 0xffffffffffc0) | (((VTTBR_EL2 >> 2) & 0b1111) << 48)
            else:
                if not self.silent:
                    self.err("Unsupported FEAT_LPA and PS pair")
                return
        else:
            translation_base_addr = VTTBR_EL2 & 0xfffffffffffe

        if not self.silent:
            self.quiet_info("$VTTBR_EL2: {:#x}".format(VTTBR_EL2))
            self.quiet_info("$VTCR_EL2: {:#x}".format(VTCR_EL2))
            self.quiet_info("Physical Address Size: {:d} bits".format(pa_size))
            self.quiet_info("EL2 Starting Level: {:d}".format(SL0))
            self.quiet_info("EL2 Region: {:#018x} - {:#018x} ({:d} bits)".format(region_start, region_end - 1, region_bits))
            self.quiet_info("EL2 Page Size: {:d}KB (per page)".format(page_size))

        self.parse_bit_range(granule_bits, region_bits)
        if not self.use_cache or not self.vttbrel2_mappings:
            self.flags_strings_cache = {}
            self.do_pagewalk(translation_base_addr, granule_bits, region_start, start_level=stage2_start_level, is_stage2=True)
            self.flags_strings_cache = None
            if not self.silent:
                self.merging()
                self.vttbrel2_mappings = self.mappings.copy()

        if not self.silent:
            self.make_out(self.vttbrel2_mappings)
        return

    def pagewalk_TTBR0_EL2(self):
        self.add_out(titlify("$TTBR0_EL2"))

        TTBR0_EL2 = get_register("$TTBR0_EL2")
        TCR_EL2 = get_register("$TCR_EL2")
        if TTBR0_EL2 == 0:
            self.warn("Maybe unused TTBR0_EL2")
            return

        if self.EL2_E2H:
            IPS = (TCR_EL2 >> 32) & 0b111
        else:
            PS = (TCR_EL2 >> 16) & 0b111
        TG0 = (TCR_EL2 >> 14) & 0b11
        T0SZ = TCR_EL2 & 0b111111
        try:
            granule_bits = {0b00: 12, 0b01: 16, 0b10: 14}[TG0]
        except KeyError:
            self.err("Unsupported $TCR_EL2.TG0")
            return
        region_start = 0
        region_end = region_start + (2 ** (64 - T0SZ))
        region_bits = GefUtil.log2(region_end - region_start)
        page_size = 2 ** (granule_bits - 10)
        if self.EL2_E2H:
            intermediate_pa_size = 32 + (IPS * 4)
        else:
            pa_size = 32 + (PS * 4)

        if not self.EL2_E2H and PS == 0b110:
            if self.FEAT_LPA:
                translation_base_addr = (TTBR0_EL2 & 0xffffffffffc0) | (((TTBR0_EL2 >> 2) & 0b1111) << 48)
            else:
                self.err("Unsupported FEAT_LPA and PS pair")
                return
        elif self.EL2_E2H and IPS == 0b110:
            if self.FEAT_LPA:
                translation_base_addr = (TTBR0_EL2 & 0xffffffffffc0) | (((TTBR0_EL2 >> 2) & 0b1111) << 48)
            else:
                self.err("Unsupported FEAT_LPA and IPS pair")
                return
        else:
            translation_base_addr = TTBR0_EL2 & 0xfffffffffffe

        self.quiet_info("$TTBR0_EL2: {:#x}".format(TTBR0_EL2))
        self.quiet_info("$TCR_EL2: {:#x}".format(TCR_EL2))
        if self.EL2_E2H:
            self.quiet_info("Intermediate Physical Address Size: {:d} bits".format(intermediate_pa_size))
        else:
            self.quiet_info("Physical Address Size: {:d} bits".format(pa_size))
        if self.EL2_M20:
            self.quiet_info("EL2 User Region: {:#018x} - {:#018x} ({:d} bits)".format(region_start, region_end - 1, region_bits))
            self.quiet_info("EL2 USer Page Size: {:d}KB (per page)".format(page_size))
        else:
            self.quiet_info("EL2 Region: {:#018x} - {:#018x} ({:d} bits)".format(region_start, region_end - 1, region_bits))
            self.quiet_info("EL2 Page Size: {:d}KB (per page)".format(page_size))

        self.parse_bit_range(granule_bits, region_bits)
        if not self.use_cache or not self.ttbr0el2_mappings:
            self.flags_strings_cache = {}
            self.do_pagewalk(translation_base_addr, granule_bits, region_start, is_2VAranges=self.EL2_M20)
            self.flags_strings_cache = None
            self.merging()
            self.ttbr0el2_mappings = self.mappings.copy()
        self.make_out(self.ttbr0el2_mappings)
        return

    def pagewalk_TTBR1_EL2(self):
        self.add_out(titlify("$TTBR1_EL2"))

        TTBR1_EL2 = get_register("$TTBR1_EL2")
        TCR_EL2 = get_register("$TCR_EL2")
        if TTBR1_EL2 == 0:
            self.warn("Maybe unused TTBR1_EL2")
            return

        IPS = (TCR_EL2 >> 32) & 0b111
        TG1 = (TCR_EL2 >> 30) & 0b11
        T1SZ = (TCR_EL2 >> 16) & 0b111111
        try:
            granule_bits = {0b01: 14, 0b10: 12, 0b11: 16}[TG1]
        except KeyError:
            self.err("Unsupported $TCR_EL2.TG1")
            return
        region_end = 2 ** 64
        region_start = region_end - (2 ** (64 - T1SZ))
        region_bits = GefUtil.log2(region_end - region_start)
        page_size = 2 ** (granule_bits - 10)
        intermediate_pa_size = 32 + (IPS * 4)

        if IPS == 0b110:
            if self.FEAT_LPA:
                translation_base_addr = (TTBR1_EL2 & 0xffffffffffc0) | (((TTBR1_EL2 >> 2) & 0b1111) << 48)
            else:
                self.err("Unsupported FEAT_LPA and IPS pair")
                return
        else:
            translation_base_addr = TTBR1_EL2 & 0xfffffffffffe

        self.quiet_info("$TTBR1_EL2: {:#x}".format(TTBR1_EL2))
        self.quiet_info("$TCR_EL2: {:#x}".format(TCR_EL2))
        self.quiet_info("Intermediate Physical Address Size: {:d} bits".format(intermediate_pa_size))
        self.quiet_info("EL2 Kernel Region: {:#018x} - {:#018x} ({:d} bits)".format(region_start, region_end - 1, region_bits))
        self.quiet_info("EL2 Kernel Page Size: {:d}KB (per page)".format(page_size))

        self.parse_bit_range(granule_bits, region_bits)
        if not self.use_cache or not self.ttbr1el2_mappings:
            self.flags_strings_cache = {}
            self.do_pagewalk(translation_base_addr, granule_bits, region_start, is_2VAranges=self.EL2_M20)
            self.flags_strings_cache = None
            self.merging()
            self.ttbr1el2_mappings = self.mappings.copy()
        self.make_out(self.ttbr1el2_mappings)
        return

    def pagewalk_TTBR0_EL3(self):
        self.add_out(titlify("$TTBR0_EL3"))

        TTBR0_EL3 = get_register("$TTBR0_EL3")
        TCR_EL3 = get_register("$TCR_EL3")
        if TTBR0_EL3 == 0:
            self.warn("Maybe unused TTBR0_EL3")
            return

        PS = (TCR_EL3 >> 16) & 0b111
        TG0 = (TCR_EL3 >> 14) & 0b11
        T0SZ = TCR_EL3 & 0b111111
        try:
            granule_bits = {0b00: 12, 0b01: 16, 0b10: 14}[TG0]
        except KeyError:
            self.err("Unsupported $TCR_EL3.TG0")
            return
        region_start = 0
        region_end = region_start + (2 ** (64 - T0SZ))
        region_bits = GefUtil.log2(region_end - region_start)
        page_size = 2 ** (granule_bits - 10)
        pa_size = 32 + (PS * 4)

        if PS == 0b110:
            if self.FEAT_LPA:
                translation_base_addr = (TTBR0_EL3 & 0xffffffffffc0) | (((TTBR0_EL3 >> 2) & 0b1111) << 48)
            else:
                self.err("Unsupported FEAT_LPA and PS pair")
                return
        else:
            translation_base_addr = TTBR0_EL3 & 0xfffffffffffe

        self.quiet_info("$TTBR0_EL3: {:#x}".format(TTBR0_EL3))
        self.quiet_info("$TCR_EL3: {:#x}".format(TCR_EL3))
        self.quiet_info("Physical Address Size: {:d} bits".format(pa_size))
        self.quiet_info("EL3 Region: {:#018x} - {:#018x} ({:d} bits)".format(region_start, region_end - 1, region_bits))
        self.quiet_info("EL3 Page Size: {:d}KB (per page)".format(page_size))

        self.parse_bit_range(granule_bits, region_bits)
        if not self.use_cache or not self.ttbr0el3_mappings:
            self.flags_strings_cache = {}
            self.do_pagewalk(translation_base_addr, granule_bits, region_start)
            self.flags_strings_cache = None
            self.merging()
            self.ttbr0el3_mappings = self.mappings.copy()
        self.make_out(self.ttbr0el3_mappings)
        return

    def pagewalk_init(self):
        res = gdb.execute("info registers", to_string=True)
        if "TTBR" not in res:
            self.err("Not found system registers. Check qemu version (at least: 3.x~, recommend: 5.x~).")
            return

        SCTLR_EL1 = get_register("$SCTLR_EL1")
        if SCTLR_EL1 is None:
            SCTLR_EL1 = get_register("$SCTLR")
        if SCTLR_EL1 is not None:
            self.EL1_M = (SCTLR_EL1 & 1) == 1
            self.EL1_WXN = ((SCTLR_EL1 >> 19) & 1) == 1
        else:
            self.EL1_M = False
            self.EL1_WXN = False

        HCR_EL2 = get_register("$HCR_EL2")
        if HCR_EL2 is not None:
            self.EL2_TGE = ((HCR_EL2 >> 27) & 1) == 1
            self.EL2_E2H = ((HCR_EL2 >> 34) & 1) == 1
            self.EL2_M20 = self.EL2_TGE and self.EL2_E2H
            self.EL2_VM = (HCR_EL2 & 1) == 1
        else:
            self.EL2_TGE = False
            self.EL2_E2H = False
            self.EL2_M20 = False
            self.EL2_VM = False

        SCTLR_EL2 = get_register("$SCTLR_EL2")
        if SCTLR_EL2 is not None:
            self.EL2_M = (SCTLR_EL2 & 1) == 1
            self.EL2_WXN = ((SCTLR_EL2 >> 19) & 1) == 1
        else:
            self.EL2_M = False
            self.EL2_WXN = False

        SCTLR_EL3 = get_register("$SCTLR_EL3")
        if SCTLR_EL3 is not None:
            self.EL3_M = (SCTLR_EL3 & 1) == 1
            self.EL3_WXN = ((SCTLR_EL3 >> 19) & 1) == 1
        else:
            self.EL3_M = False
            self.EL3_WXN = False

        ID_AA64MMFR0_EL1 = get_register("$ID_AA64MMFR0_EL1")
        if ID_AA64MMFR0_EL1 is not None:
            TGran4_2 = (ID_AA64MMFR0_EL1 >> 40) & 0b1111
            TGran16_2 = (ID_AA64MMFR0_EL1 >> 32) & 0b1111
            TGran4 = (ID_AA64MMFR0_EL1 >> 28) & 0b1111
            TGran16 = (ID_AA64MMFR0_EL1 >> 20) & 0b1111
            self.FEAT_LPA2 = (TGran4_2 == 0b0011) or (TGran16_2 == 0b0011) or (TGran4 == 0b0001) or (TGran16 == 0b0010)
            self.FEAT_LPA = (ID_AA64MMFR0_EL1 & 0b1111) == 0b0110
        else:
            self.FEAT_LPA2 = False
            self.FEAT_LPA = False

        ID_AA64MMFR1_EL1 = get_register("$ID_AA64MMFR1_EL1")
        if ID_AA64MMFR1_EL1 is not None:
            self.FEAT_PAN = ((ID_AA64MMFR1_EL1 >> 20) & 0b1111) != 0b0000
        else:
            self.FEAT_PAN = False
        self.quiet_info("{:s} is supported on all ARMv8".format(Color.boldify("PXN")))
        if self.FEAT_PAN:
            self.quiet_info("{:s} is supported".format(Color.boldify("PAN")))
        else:
            self.quiet_info("PAN is unsupported")

        ID_AA64MMFR2_EL1 = get_register("$ID_AA64MMFR2_EL1")
        if ID_AA64MMFR2_EL1 is not None:
            self.FEAT_TTST = ((ID_AA64MMFR2_EL1 >> 28) & 0b1111) == 0b0001
            self.FEAT_LVA = ((ID_AA64MMFR2_EL1 >> 16) & 0b1111) == 0b0001
        else:
            self.FEAT_TTST = False
            self.FEAT_LVA = False

        return

    def pagewalk(self):
        # parse system registers
        self.pagewalk_init()

        self.silent = False
        self.mappings = None
        self.el2_mappings = None

        # TODO: implementation for VSTTBR_EL2, VSTCR_EL2 pattern

        # do pagewalk
        if self.TargetEL < 1 or 3 < self.TargetEL:
            self.warn("No paging in EL{:d}".format(self.TargetEL))
            return
        if self.TargetEL == 1 and self.EL1_M:
            if self.EL2_VM:
                # el2_mapping is needed because read_mem() uses PA, but not IPA
                self.silent = True
                self.pagewalk_VTTBR_EL2()
                if self.mappings:
                    self.el2_mappings = self.mappings.copy()
                    self.mappings = None
                self.silent = False
            self.pagewalk_TTBR0_EL1()
            self.pagewalk_TTBR1_EL1()
        if self.TargetEL == 1 and not self.EL1_M:
            self.quiet_info("EL1/0 translation is unused")
        if self.TargetEL == 2 and self.EL2_VM:
            self.pagewalk_VTTBR_EL2()
        if self.TargetEL == 2 and not self.EL2_VM:
            self.quiet_info("EL2(as stage2) translation is unused")
        if self.TargetEL == 2 and self.EL2_M:
            self.pagewalk_TTBR0_EL2()
            if self.EL2_M20:
                self.pagewalk_TTBR1_EL2()
        if self.TargetEL == 2 and self.EL2_VM:
            self.quiet_info("EL2(as stage1) translation is unused")
        if self.TargetEL == 3 and self.EL3_M:
            if not self.switch_el():
                return
            self.pagewalk_TTBR0_EL3()
            self.revert_el()
        if self.TargetEL == 3 and not self.EL3_M:
            self.quiet_info("EL3 translation is unused")
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM64",))
    def do_invoke(self, args):
        if args.optee:
            Cache.reset_gef_caches(function=PageMap.get_page_maps_arm64_optee_secure_memory)
            PageMap.get_page_maps_arm64_optee_secure_memory(True)
            return

        if args.target_el is None:
            CPSR = get_register("$cpsr")
            self.TargetEL = (CPSR >> 2) & 0b11
            if self.TargetEL == 0:
                # Since $pc is currently in EL0 (userland), so it is not privileged to be able to view the page table.
                # Temporarily switch to EL1 and display TTBR0_EL1 and TTBR1_EL1 pagetable.
                self.TargetEL = 1
        else:
            self.TargetEL = args.target_el

        self.quiet = args.quiet
        self.print_each_level = args.print_each_level
        self.no_merge = args.no_merge
        self.sort_by_phys = args.sort_by_phys
        self.simple = args.simple
        self.filter = args.filter
        self.vrange = args.vrange.copy()
        self.prange = args.prange.copy()
        self.trace = args.trace.copy()
        self.use_cache = args.use_cache
        if self.trace:
            self.vrange.extend(self.trace) # also set --vrange
            self.print_each_level = True # overwrite
            self.use_cache = False # overwrite

        self.out = []
        self.cache = {}
        self.pagewalk()
        self.cache = {}
        self.print_output(args)
        return


@register_command
class SwitchELCommand(GenericCommand):
    """Switch EL (Exception Level) on ARM64 architecture."""
    _cmdline_ = "switch-el"
    _category_ = "08-a. Qemu-system Cooperation - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("target_el", metavar="TARGET_EL", nargs="?", type=int, help="Exception Level to change to.")
    _syntax_ = parser.format_help()

    def switch_el(self):
        # current EL
        CPSR = get_register("$cpsr") & 0xffffffff
        CurrentEL = (CPSR >> 2) & 0b11

        # check argv
        if self.target_el is None:
            info("$cpsr = {:#x} (EL{:d})".format(CPSR, CurrentEL))
            return

        # check target EL
        try:
            if self.target_el < 0 or self.target_el > 3:
                err("Invalid argument (ELx>=0 && ELx<=3)")
                return
        except ValueError:
            err("Invalid argument (ELx integer required)")
            return

        # change CPSR
        if self.target_el != CurrentEL:
            CPSR = CPSR & ~(0b11 << 2) # clear EL
            CPSR |= self.target_el << 2 # set desired EL
            gdb.parse_and_eval("$cpsr = {:#x}".format(CPSR))
            info("Moving to EL{:d}".format(self.target_el))
        else:
            info("Already at EL{:d}".format(self.target_el))

        # reprint CPSR
        CPSR = int(gdb.parse_and_eval("$cpsr")) & 0xffffffff
        CurrentEL = (CPSR >> 2) & 0b11
        info("$cpsr = {:#x} (EL{:d})".format(CPSR, CurrentEL))
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM64",))
    def do_invoke(self, args):
        self.target_el = args.target_el
        self.switch_el()
        return


@register_command
class PagewalkWithHintsCommand(GenericCommand):
    """Add hint to the result of pagewalk."""
    _cmdline_ = "pagewalk-with-hints"
    _category_ = "08-a. Qemu-system Cooperation - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--skip-full-slab-cache", action="store_true",
                        help="skip search full slab cache. use this option if take a long time to parse.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use map cache.")
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet execution.")
    _syntax_ = parser.format_help()

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.prev_out = None
        return

    class Region:
        def __init__(self, addr_start, addr_end, perm, description="", merge=True):
            self.addr_start = addr_start
            self.addr_end = addr_end
            self.size = addr_end - addr_start
            self.perm = perm
            self.description = description
            self.merge = merge
            return

        def add_description(self, description):
            if not self.description:
                self.description = description
                return
            if description in self.description:
                return
            self.description = "{:s}, {:s}".format(self.description, description)
            return

    def page_start_align(self, x):
        return x & gef_getpagesize_mask_high()

    def page_end_align(self, x):
        if x & gef_getpagesize_mask_low():
            return (x & gef_getpagesize_mask_high()) + gef_getpagesize()
        else:
            return x

    def insert_region(self, to_insert_address, to_insert_size, description, merge=True):
        target_address_start = to_insert_address
        target_address_end = to_insert_address + to_insert_size

        for _key, r in sorted(self.regions.items()):
            # no overwrap
            if r.addr_end <= target_address_start:
                continue
            if target_address_end <= r.addr_start:
                break

            # found, let's split
            # pattern1
            #   - target_address_start
            #     (ignore)
            #   - r.addr_start
            #     (size_2nd)
            #   - target_address_end
            #     (size_3rd)
            #   - r.addr_end

            # pattern2
            #   - target_address_start
            #     (ignore)
            #   - r.addr_start
            #     (size_2nd)
            #   - r.addr_end
            #     (treat by next loop)
            #   - target_address_end

            # pattern3
            #   - r.addr_start
            #     (size_1st)
            #   - target_address_start
            #     (size_2nd)
            #   - target_address_end
            #     (size_3rd)
            #   - r.addr_end

            # pattern4
            #   - r.addr_start
            #     (size_1st)
            #   - target_address_start
            #     (size_2nd)
            #   - r.addr_end
            #     (treat by next loop)
            #   - target_address_end

            size_1st = max(target_address_start - r.addr_start, 0)
            size_2nd = min(target_address_end, r.addr_end) - max(target_address_start, r.addr_start)
            size_3rd = max(r.addr_end - target_address_end, 0)

            # then insert (old one is overwritten)
            if size_1st > 0:
                addr_start_1st = r.addr_start
                addr_end_1st = addr_start_1st + size_1st
                self.regions[addr_start_1st] = self.Region(addr_start_1st, addr_end_1st, r.perm, r.description, merge)
            if size_2nd > 0:
                addr_start_2nd = max(target_address_start, r.addr_start)
                addr_end_2nd = addr_start_2nd + size_2nd
                if r.description:
                    if description in r.description:
                        new_description = r.description
                    else:
                        new_description = r.description + ", " + description
                else:
                    new_description = description
                self.regions[addr_start_2nd] = self.Region(addr_start_2nd, addr_end_2nd, r.perm, new_description, merge)
            if size_3rd > 0:
                addr_start_3rd = target_address_end
                addr_end_3rd = addr_start_3rd + size_3rd
                self.regions[addr_start_3rd] = self.Region(addr_start_3rd, addr_end_3rd, r.perm, r.description, merge)

            if r.addr_end < target_address_end:
                target_address_start = r.addr_end
        return

    def merge_region(self):
        new_regions = {}
        prev_key, prev_r = None, None
        for key, r in sorted(self.regions.items()):
            # for 1st element
            if prev_key is None:
                prev_key, prev_r = key, r
                continue

            # no_merge flag
            if not r.merge:
                new_regions[prev_key] = prev_r
                prev_key, prev_r = key, r
                continue

            if prev_r and not prev_r.merge:
                new_regions[prev_key] = prev_r
                prev_key, prev_r = key, r
                continue

            # not match, so append
            if prev_r.addr_end != r.addr_start:
                new_regions[prev_key] = prev_r
                prev_key, prev_r = key, r
                continue

            if prev_r.perm != r.perm:
                new_regions[prev_key] = prev_r
                prev_key, prev_r = key, r
                continue

            if prev_r.description != r.description:
                new_regions[prev_key] = prev_r
                prev_key, prev_r = key, r
                continue

            # match, so let's merge
            prev_r.size += r.size
            prev_r.addr_end += r.size

        # add last element
        if prev_key is not None:
            new_regions[prev_key] = prev_r

        # replace
        self.regions = new_regions
        return

    def get_maps(self):
        res = PageMap.get_page_maps_by_pagewalk("pagewalk --quiet --no-pager")
        res = sorted(set(res.splitlines()))
        res = list(filter(lambda line: line.endswith("]"), res))
        res = list(filter(lambda line: "[+]" not in line, res))
        res = list(filter(lambda line: "*" not in line, res))

        regions = {}
        for line in res:
            line = line.split()
            addr_start, addr_end = [int(x, 16) for x in line[0].split("-")]
            # TODO: more suitable check for kernel address
            if (addr_start >> ((current_arch.ptrsize * 8) - 1)) != 1:
                continue
            if is_x86():
                perm = Permission.from_process_maps(line[5][1:4].lower())
            elif is_arm64() or is_arm32():
                perm = Permission.from_process_maps(line[6][4:7].lower())
            regions[addr_start] = self.Region(addr_start, addr_end, str(perm))
        return regions

    def resolve_kbase(self):
        if not self.quiet:
            info("resolve kbase")
        kinfo = Kernel.get_kernel_base()

        # .text
        _stext = Symbol.get_ksymaddr("_stext")
        _etext = Symbol.get_ksymaddr("_etext")
        if _stext and _etext:
            _stext = self.page_start_align(_stext)
            _etext = self.page_end_align(_etext)
            self.insert_region(_stext, _etext - _stext, "kernel .text")
        else:
            if kinfo.text_base in self.regions:
                self.regions[kinfo.text_base].add_description("maybe kernel .text")

        # .rodata
        __start_rodata = Symbol.get_ksymaddr("__start_rodata")
        __end_rodata = Symbol.get_ksymaddr("__end_rodata")
        if __start_rodata and __end_rodata:
            __start_rodata = self.page_start_align(__start_rodata)
            __end_rodata = self.page_end_align(__end_rodata)
            self.insert_region(__start_rodata, __end_rodata - __start_rodata, "kernel .rodata")
        else:
            # In a 32-bit environment, the range of rodata may not be measured correctly, so it is not used.
            if is_64bit():
                if kinfo.ro_base in self.regions:
                    self.regions[kinfo.ro_base].add_description("maybe kernel .rodata")

        # .data
        _sdata = Symbol.get_ksymaddr("_sdata")
        _edata = Symbol.get_ksymaddr("_edata")
        if _sdata and _edata:
            _sdata = self.page_start_align(_sdata)
            _edata = self.page_end_align(_edata)
            self.insert_region(_sdata, _edata - _sdata, "kernel .data")
        else:
            # In a 32-bit environment, the range of rodata may not be measured correctly, so it is not used.
            if is_64bit():
                if kinfo.rw_base in self.regions:
                    self.regions[kinfo.rw_base].add_description("maybe kernel .data")
        return

    def resolve_direct_map(self):
        if not self.quiet:
            info("resolve direct map")
        page_offset = KernelAddressHeuristicFinder.get_page_offset()
        if not page_offset:
            return
        vmalloc_start = KernelAddressHeuristicFinder.get_vmalloc_start()
        if not vmalloc_start:
            return

        phys_page_start = page_offset
        phys_mem_size = vmalloc_start - phys_page_start

        self.insert_region(phys_page_start, phys_mem_size, "physmem direct map")
        return

    def resolve_vmalloc(self):
        if not self.quiet:
            info("resolve vmalloc")
        vmalloc_start = KernelAddressHeuristicFinder.get_vmalloc_start()
        if not vmalloc_start:
            return

        cr4 = get_register("cr4", use_monitor=True)
        if (cr4 >> 12) & 1: # PML5T check
            VMALLOC_SIZE_TB = 12800
        else:
            VMALLOC_SIZE_TB = 32

        vmalloc_region_size = VMALLOC_SIZE_TB << 40
        self.insert_region(vmalloc_start, vmalloc_region_size, "vmalloc area")
        return

    def resolve_page(self):
        if not self.quiet:
            info("resolve page")

        if is_x86_64():
            vmemmap = KernelAddressHeuristicFinder.get_vmemmap()
            if vmemmap is None:
                return
            if vmemmap in self.regions:
                self.regions[vmemmap].add_description("struct page area")

        elif is_x86_32() or is_arm32():
            # TODO support x86_32 mem_section
            mem_map = KernelAddressHeuristicFinder.get_mem_map()
            if mem_map is None:
                return
            if mem_map in self.regions:
                self.regions[mem_map].add_description("struct page area")

        elif is_arm64():
            VMEMMAP_START, _ = KernelAddressHeuristicFinder.get_VMEMMAP_START()
            # It will shift due to KASLR, so we will correct it.
            for key in sorted(self.regions.keys()):
                if key >= VMEMMAP_START:
                    self.regions[key].add_description("struct page area")
        return

    def resolve_buddy(self):
        if not self.quiet:
            info("resolve buddy")
        res = gdb.execute("buddy-dump --quiet --no-pager --sort", to_string=True)

        for line in res.splitlines():
            line = Color.remove_color(line)
            if not line.startswith("    "):
                continue

            _page_str, size_str, virt_str, _phys_str, *pcp = line.split()

            if "???" in virt_str: # maybe x86 highmem
                continue

            size = int(size_str[5:], 16)
            virt = int(virt_str[5:].split("-")[0], 16)
            if pcp:
                description = "free page in buddy allocator (pcp)"
            else:
                description = "free page in buddy allocator"
            self.insert_region(virt, size, description, merge=False)
        return

    def resolve_kstack(self):
        if not self.quiet:
            info("resolve kstack")
        res = gdb.execute("ktask --quiet --no-pager --print-thread", to_string=True)

        # calc kstack address pattern
        kstacks = []
        for line in res.splitlines():
            line = line.split()
            kstack = int(line[-2], 16)
            kstacks.append(kstack & 0xffff)

        # calc kstack size
        kstacks = sorted(set(kstacks))
        diffs = []
        for i in range(len(kstacks) - 1):
            diff = kstacks[i + 1] - kstacks[i]
            diffs.append(diff)
        if len(diffs) == 0:
            kstack_size = gef_getpagesize() *2
        else:
            kstack_size = min(diffs)

        # kstack
        for line in res.splitlines():
            elems = line.split()
            pid, kstack = int(elems[2]), int(elems[-2], 16)
            process_name = line.split(maxsplit=3)[3][:16].strip()
            description = "kernel stack of PID:{:d} ({:s})".format(pid, process_name)
            self.insert_region(kstack, kstack_size, description)
        return

    def resolve_more_slub(self):
        if not self.quiet:
            info("resolve slub (search full slab cache; skip if target region size >= 0x200000)")
        old_regions = list(self.regions.items())[::]

        tqdm = GefUtil.get_tqdm()
        for _region_addr, region in tqdm(old_regions, leave=False):
            if "slab cache" in region.description:
                continue
            if region.perm != "rw-":
                continue
            if region.size >= 0x200000: # heuristic threshold
                continue
            current = region.addr_start
            while current < region.addr_end:
                res = Kernel.get_slab_contains(current)
                if not res:
                    current += gef_getpagesize()
                    continue

                r = re.search(r"name: (\S+)  size: \S+  num_pages: (\S+)", res)
                if not r:
                    current += gef_getpagesize()
                    continue

                name = r.group(1)
                # something is wrong
                if name and not all(x in String.STRING_PRINTABLE for x in name):
                    current += gef_getpagesize()
                    continue

                num_pages = int(r.group(2), 16)
                # something is wrong
                if num_pages == 0:
                    current += gef_getpagesize()
                    continue

                description = "slab cache ({:s}; full)".format(name)
                total_page_size = gef_getpagesize() * num_pages

                self.insert_region(current, total_page_size, description, merge=False)
                current += total_page_size
        return

    def resolve_slub(self):
        if not self.quiet:
            info("resolve slub")
        res = gdb.execute("slub-dump --quiet --no-pager -vv", to_string=True)
        name, address, size = None, None, None
        for line in res.splitlines():
            r = re.search(r"name: (.+)", line)
            if r:
                name = Color.remove_color(r.group(1))
                continue
            r = re.search(r"virtual address: (.+0x.+)", line)
            if r:
                address = Color.remove_color(r.group(1))
                address = int(address, 16)
                continue
            r = re.search(r"num pages: (\d+)", line)
            if r:
                size = int(r.group(1)) * gef_getpagesize()
                description = "slab cache ({:s})".format(name)
                if address:
                    self.insert_region(address, size, description, merge=False)
                address, size = None, None # for detect logic error. name will be reused
                continue

        if self.skip_full_slab_cache:
            return

        self.resolve_more_slub()
        return

    def resolve_slab(self):
        if not self.quiet:
            info("resolve slab")
        res = gdb.execute("slab-dump --quiet --no-pager", to_string=True)
        name, address, size = None, None, None
        for line in res.splitlines():
            r = re.search(r"name: (.+)", line)
            if r:
                name = Color.remove_color(r.group(1))
                continue
            r = re.search(r"virtual address \(s_mem & ~0xfff\): (.+0x.+)", line)
            if r:
                address = Color.remove_color(r.group(1))
                address = int(address, 16)
                continue
            r = re.search(r"num pages: (\d+)", line)
            if r:
                size = int(r.group(1)) * gef_getpagesize()
                description = "slab cache ({:s})".format(name)
                if address:
                    self.insert_region(address, size, description, merge=False)
                address, size = None, None # for detect logic error. name will be reused
                continue
        return

    def resolve_slob(self):
        if not self.quiet:
            info("resolve slob")
        res = gdb.execute("slob-dump --quiet --no-pager", to_string=True)
        address, size = None, None, None
        for line in res.splitlines():
            r = re.search(r"virtual address: (.+0x.+)", line)
            if r:
                address = Color.remove_color(r.group(1))
                address = int(address, 16)
                continue
            r = re.search(r"num pages: (\d+)", line)
            if r:
                size = int(r.group(1)) * gef_getpagesize()
                description = "slab cache"
                if address:
                    self.insert_region(address, size, description, merge=False)
                address, size = None, None # for detect logic error
                continue
        return

    def resolve_slub_tiny(self):
        if not self.quiet:
            info("resolve slub-tiny")
        res = gdb.execute("slub-tiny-dump --quiet --no-pager", to_string=True)
        name, address, size = None, None, None
        for line in res.splitlines():
            r = re.search(r"name: (.+)", line)
            if r:
                name = Color.remove_color(r.group(1))
                continue
            r = re.search(r"virtual address: (.+0x.+)", line)
            if r:
                address = Color.remove_color(r.group(1))
                address = int(address, 16)
                continue
            r = re.search(r"num pages: (\d+)", line)
            if r:
                size = int(r.group(1)) * gef_getpagesize()
                description = "slab cache ({:s})".format(name)
                if address:
                    self.insert_region(address, size, description, merge=False)
                address, size = None, None # for detect logic error. name will be reused
                continue
        return

    def resolve_each_slab(self):
        allocator = KernelChecksecCommand.get_slab_type()
        if allocator == "SLUB":
            self.resolve_slub()
        elif allocator == "SLUB_TINY":
            self.resolve_slub_tiny()
        elif allocator == "SLAB":
            self.resolve_slab()
        elif allocator == "SLOB":
            self.resolve_slob()
        return

    def resolve_module(self):
        if not self.quiet:
            info("resolve module")
        res = gdb.execute("kmod --quiet --no-pager", to_string=True)
        for line in res.splitlines():
            if not line:
                continue
            line = line.split()
            module_name = line[1]
            module_base = int(line[2], 16)
            module_size = AddressUtil.align_address_to_size(int(line[3], 16), gef_getpagesize())
            description = "kernel module ({:s})".format(module_name)
            self.insert_region(module_base, module_size, description)
        return

    def resolve_vdso(self):
        if not self.quiet:
            info("resolve vdso")

        if is_x86_64():
            vdso_image_64 = KernelAddressHeuristicFinder.get_vdso_image_64()
            if vdso_image_64:
                vdso_start = read_int_from_memory(vdso_image_64)
                vdso_size = read_int_from_memory(vdso_image_64 + current_arch.ptrsize)
                self.insert_region(vdso_start, vdso_size, "vdso_image_64")

        if is_x86_64() or is_x86_32():
            vdso_image_32 = KernelAddressHeuristicFinder.get_vdso_image_32()
            if vdso_image_32:
                vdso_start = read_int_from_memory(vdso_image_32)
                vdso_size = read_int_from_memory(vdso_image_32 + current_arch.ptrsize)
                self.insert_region(vdso_start, vdso_size, "vdso_image_32")

        if is_x86_64():
            vdso_image_x32 = KernelAddressHeuristicFinder.get_vdso_image_x32()
            if vdso_image_x32:
                vdso_start = read_int_from_memory(vdso_image_x32)
                vdso_size = read_int_from_memory(vdso_image_x32 + current_arch.ptrsize)
                self.insert_region(vdso_start, vdso_size, "vdso_image_x32")

        if is_arm64() or is_arm32():
            vdso_start = KernelAddressHeuristicFinder.get_vdso_start()
            if vdso_start:
                vdso_size = gef_getpagesize()
                self.insert_region(vdso_start, vdso_size, "vdso_start")

        if is_arm64():
            vdso32_start = KernelAddressHeuristicFinder.get_vdso32_start()
            if vdso32_start:
                vdso_size = gef_getpagesize()
                self.insert_region(vdso32_start, vdso_size, "vdso32_start")
        return

    def resolve_device_physmem(self):
        if not self.quiet:
            info("resolve device physmem")

        try:
            res = gdb.execute("monitor info mtree -f", to_string=True)
        except gdb.error:
            return

        maps = PageMap.get_page_maps(None)
        if maps is None:
            return

        for line in res.splitlines():
            if not line.startswith("  "):
                continue

            m = re.search(r"  ([0-9a-f]+)-([0-9a-f]+) \(.+?\): (.+)", line)
            if not m:
                continue

            paddr = int(m.group(1), 16)
            if paddr % 0x1000:
                continue

            pend = int(m.group(2), 16)
            if (pend & 0xfff) == 0xfff:
                pend += 1
            if pend % 0x1000:
                continue

            size = pend - paddr
            if size % 0x1000 or size == 0:
                continue

            device_name = "device ({:s})".format(m.group(3))

            vaddrs = PageMap.p2v_from_map(paddr, maps)
            for vaddr in vaddrs:
                self.insert_region(vaddr, size, device_name)
        return

    def detect_zero_page(self):
        if not self.quiet:
            info("detect zero page")
        page_size = gef_getpagesize()
        z10 = b"\0" * 0x10
        cc10 = b"\xcc" * 0x10
        ff10 = b"\xff" * 0x10
        z1000 = b"\0" * page_size
        ff1000 = b"\xff" * page_size
        cc1000 = b"\xcc" * page_size

        for _key, r in self.regions.copy().items():
            if r.description != "":
                continue
            if r.size >= page_size * 0x10:
                continue
            for addr in range(r.addr_start, r.addr_end, page_size):
                try:
                    x = read_memory(addr, 0x10)
                except gdb.MemoryError:
                    self.insert_region(addr, page_size, "can not access")
                    continue

                if x not in [z10, ff10, cc10]:
                    continue
                try:
                    x = read_memory(addr, page_size)
                except gdb.MemoryError:
                    continue
                if x == z1000:
                    self.insert_region(addr, page_size, "0x00-filled")
                elif x == cc1000:
                    self.insert_region(addr, page_size, "0xcc-filled")
                elif x == ff1000:
                    self.insert_region(addr, page_size, "0xff-filled")
        return

    def add_legend(self):
        if not self.quiet:
            fmt = "{:37s} {:18s} {:5s} {:s}"
            legend = ["Virtual address start-end", "Total size", "Perm", "Hint"]
            self.out.append(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_64", "x86_32", "ARM64", "ARM32"))
    def do_invoke(self, args):
        if not args.reparse and self.prev_out:
            gef_print("\n".join(self.prev_out), less=not args.no_pager)
            return

        self.quiet = args.quiet
        self.skip_full_slab_cache = args.skip_full_slab_cache
        self.out = []

        self.add_legend()
        self.regions = self.get_maps()
        self.resolve_device_physmem()
        self.resolve_kbase()
        if is_x86_64():
            self.resolve_direct_map()
            self.resolve_vmalloc()
        self.resolve_page()
        self.resolve_buddy()
        self.resolve_kstack()
        self.resolve_each_slab()
        self.resolve_module()
        self.resolve_vdso()
        self.detect_zero_page()

        self.merge_region()
        for _, r in sorted(self.regions.items()):
            self.out.append("{:#018x}-{:#018x} {:#018x} [{:s}] {:s}".format(
                r.addr_start, r.addr_end, r.size, r.perm, r.description,
            ))
        self.prev_out = self.out.copy()

        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class PageCommand(GenericCommand):
    """The base command for converting virtual addresses and physical addresses from page."""
    _cmdline_ = "page"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("mode", choices=["to-virt", "to-phys", "from-virt", "from-phys"], help="conversion mode.")
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address, help="the address to convert.")
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use map cache.")
    _syntax_ = parser.format_help()

    _note_ = "Simplified page structure (CONFIG_SPARSEMEM_VMEMMAP/CONFIG_FLATMEM):\n"
    _note_ += "\n"
    _note_ += "VMEMMAP_START--------->+-struct page[]-+\n"
    _note_ += "  or                   | pfn#0 page    | --> physmem 0x0000-0x1000\n"
    _note_ += "mem_map                +---------------+\n"
    _note_ += "                       | pfn#1 page    | --> physmem 0x1000-0x2000\n"
    _note_ += "                       +---------------+\n"
    _note_ += "                       | ...           |\n"
    _note_ += "                    ^  +---------------+\n"
    _note_ += "sizeof(struct page) |  | pfn#N page    | --> physmem 0xXXX000-0xXXY000\n"
    _note_ += "                    v  +---------------+\n"
    _note_ += "\n"
    _note_ += "* x64/arm64: CONFIG_SPARSEMEM_VMEMMAP; They use `VMEMMAP_START`.\n"
    _note_ += "* x86(when CONFIG_NUMA=n)/arm32: CONFIG_FLATMEM; They use `mem_map`.\n"
    _note_ += "* Add PAGE_OFFSET to the physical address to get the virtual address.\n"
    _note_ += "\n"
    _note_ += "Simplified page structure (CONFIG_SPARSEMEM):\n"
    _note_ += "\n"
    _note_ += "+-------------------------------------------------------------------------------+\n"
    _note_ += "|                                                                               |\n"
    _note_ += "|  +-struct mem_section[]-+                                                     |\n"
    _note_ += "|  | section_mem_map      |     +-->+-struct page[]-+                           |\n"
    _note_ += "|  +----------------------+     |   | pfn#0 page    | --> physmem 0xX000-0xY000 |\n"
    _note_ += "+->| section_mem_map      |-----+   |  flags        | --> section_id (=idx)-----+\n"
    _note_ += "   +----------------------+         +---------------+\n"
    _note_ += "   | ...                  |         | pfn#1 page    | --> physmem 0xY000-0xZ000\n"
    _note_ += "   +----------------------+         |  flags        |\n"
    _note_ += "   | section_mem_map      |         +---------------+\n"
    _note_ += "   +----------------------+         | ...           |\n"
    _note_ += "                                    +---------------+  ^\n"
    _note_ += "                                    | pfn#N page    |  | sizeof(struct page)\n"
    _note_ += "                                    |  flags        |  |\n"
    _note_ += "                                    +---------------+  v\n"
    _note_ += "\n"
    _note_ += "* x86(when CONFIG_NUMA=y): CONFIG_SPARSEMEM; It uses `mem_section[]`.\n"
    _note_ += "* In other words, there are multiple mem_maps.\n"
    _note_ += "* It is possible to obtain which `section_mem_map` to use from `page->flags`.\n"
    _note_ += "* Add PAGE_OFFSET to the physical address to get the virtual address."

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        return

    def get_page_virt_pair(self):
        allocator = KernelChecksecCommand.get_slab_type()

        if allocator in ["SLUB", "SLUB_TINY"]:
            # get valid page and vaddr pair
            command = {"SLUB": "slub-dump --node", "SLUB_TINY": "slub-tiny-dump"}[allocator]
            for n in [8, 16, 32, 64, 96, 128, 192, 256, 512]:
                # this page2virt command is called from slub-dump itself.
                # * slub-dump (not --skip-page2virt)
                #   -> page2virt
                #     -> get_vmemmap
                #       -> slub-dump --skip-page2virt
                #     -> calculates sizeof_struct_page
                #       -> slub-dump --skip-page2virt
                # To avoid infinite recursion, must add the `--skip-page2virt` option when calling slub-dump from page2virt.
                ret = gdb.execute("{:s} --simple --no-pager --quiet --skip-page2virt kmalloc-{:d}".format(command, n), to_string=True)
                r1 = re.findall(r"(?:active|partial|node) page: (0x\S\S+)", Color.remove_color(ret))
                r2 = re.findall(r"virtual address: (0x\S+|\?\?\?)", Color.remove_color(ret))
                valid_pairs = [(p, v) for p, v in zip(r1, r2) if v != "???"]
                if valid_pairs:
                    page = int(valid_pairs[0][0], 16)
                    vaddr = int(valid_pairs[0][1], 16)
                    break
            else:
                return False

        elif allocator == "SLAB":
            # get valid page and vaddr pair
            ret = gdb.execute("slab-dump --simple --cpu 0 --no-pager --quiet kmalloc-256", to_string=True)
            r1 = re.search(r"node\[\d+\]\.slabs_(?:partial|full): (0x\S+)", Color.remove_color(ret))
            r2 = re.search(r"virtual address \(s_mem & ~0xfff\): (0x\S+)", Color.remove_color(ret))
            if not r1 or not r2:
                return False
            page = int(r1.group(1), 16)
            vaddr = int(r2.group(1), 16)

        elif allocator == "SLOB":
            # get valid page and vaddr pair
            ret = gdb.execute("slob-dump --simple --large --no-pager --quiet", to_string=True)
            r1 = re.search(r"page: (0x\S+)", Color.remove_color(ret))
            r2 = re.search(r"virtual address: (0x\S+)", Color.remove_color(ret))
            if not r1 or not r2:
                return False
            page = int(r1.group(1), 16)
            vaddr = int(r2.group(1), 16)

        else:
            return False

        return page, vaddr

    def initialize(self):
        self.PAGE_SHIFT = 12

        if is_x86_64():
            # CONFIG_SPARSEMEM_VMEMMAP

            self.VMEMMAP_START = KernelAddressHeuristicFinder.get_vmemmap()
            if self.VMEMMAP_START is None:
                err("Not found VMEMMAP_START")
                return False

            self.PAGE_OFFSET = KernelAddressHeuristicFinder.get_page_offset()
            if self.PAGE_OFFSET is None:
                err("Not found PAGE_OFFSET")
                return False

            self.phys_base = KernelAddressHeuristicFinder.get_phys_base()
            if self.phys_base is None:
                err("Not found phys_base")
                return False

            self.START_KERNEL_map = 0xffffffff80000000

            ret = self.get_page_virt_pair()
            if not ret:
                err("Not found valid page/vaddr pair")
                return False
            page, vaddr = ret

            # calc sizeof(struct page)
            pfn = (vaddr - self.PAGE_OFFSET) >> self.PAGE_SHIFT
            self.sizeof_struct_page = (page - self.VMEMMAP_START) // pfn

        elif is_x86_32():
            # calc PAGE_OFFSET
            maps = Kernel.get_maps()
            if not maps:
                err("Not found maps")
                return False
            kern_min = maps[0][0]
            if kern_min < 0x78000000:
                self.PAGE_OFFSET = 0x40000000 # VMSPLIT_1G
            elif kern_min < 0x80000000:
                self.PAGE_OFFSET = 0x78000000 # VMSPLIT_2G_OPT
            elif kern_min < 0xB0000000:
                self.PAGE_OFFSET = 0x80000000 # VMSPLIT_2G
            elif kern_min < 0xC0000000:
                self.PAGE_OFFSET = 0xB0000000 # VMSPLIT_3G_OPT
            else:
                self.PAGE_OFFSET = 0xC0000000 # VMSPLIT_3G

            # Determine whether it is CONFIG_FLATMEM or CONFIG_SPARSEMEM.
            self.mem_map = KernelAddressHeuristicFinder.get_mem_map()
            self.mem_section = KernelAddressHeuristicFinder.get_mem_section()

            if self.mem_map is None and self.mem_section is None:
                err("Not found mem_map and mem_section")
                return False

            if self.mem_map:
                # CONFIG_FLATMEM (when CONFIG_NUMA=n)
                self.mode = "FLATMEM"

                # calc sizeof(struct page)
                ret = self.get_page_virt_pair()
                if not ret:
                    err("Not found valid page/vaddr pair")
                    return False
                page, vaddr = ret
                pfn = (vaddr - self.PAGE_OFFSET) >> self.PAGE_SHIFT
                self.sizeof_struct_page = (page - self.mem_map) // pfn

            elif self.mem_section:
                # CONFIG_SPARSEMEM (when CONFIG_NUMA=y)
                self.mode = "SPARSEMEM"

                # PAE check
                cr4 = get_register("cr4", use_monitor=True)
                if (cr4 >> 5) & 1: # PAE
                    MAX_PHYSMEM_BITS = 36
                    SECTION_SIZE_BITS = 29
                else:
                    MAX_PHYSMEM_BITS = 32
                    SECTION_SIZE_BITS = 26
                SECTIONS_SHIFT = MAX_PHYSMEM_BITS - SECTION_SIZE_BITS
                SECTIONS_WIDTH = SECTIONS_SHIFT
                SECTIONS_PGOFF = 32 - SECTIONS_WIDTH
                self.SECTIONS_PGSHIFT = SECTIONS_PGOFF
                self.SECTIONS_MASK = (1 << SECTIONS_WIDTH) - 1

                # SECTIONS_PER_ROOT = 1
                # NR_MEM_SECTIONS = 1 << SECTIONS_SHIFT
                # NR_SECTION_ROOTS = NR_MEM_SECTIONS // SECTIONS_PER_ROOT

                self.PFN_SECTION_SHIFT = SECTION_SIZE_BITS - self.PAGE_SHIFT

                SECTION_MAP_LAST_BIT = 1 << 3
                self.SECTION_MAP_MASK = ~(SECTION_MAP_LAST_BIT - 1) & 0xffffffff

                # calc sizeof(mem_section)
                v = read_int_from_memory(self.mem_section + current_arch.ptrsize * 3)
                if v == 0: # pad check
                    self.sizeof_mem_section = current_arch.ptrsize * 4 # CONFIG_PAGE_EXTENSION=y
                else:
                    self.sizeof_mem_section = current_arch.ptrsize * 2 # CONFIG_PAGE_EXTENSION=n

                # calc sizeof(struct page)
                ret = self.get_page_virt_pair()
                if not ret:
                    err("Not found valid page/vaddr pair")
                    return False
                page, vaddr = ret
                flags = read_int_from_memory(page)
                section_id = (flags >> self.SECTIONS_PGSHIFT) & self.SECTIONS_MASK
                mem_section = self.mem_section + self.sizeof_mem_section * section_id
                if not is_valid_addr(mem_section):
                    err("mem_section is not valid")
                    return False
                section_mem_map = read_int_from_memory(mem_section)
                if section_mem_map == 0:
                    err("section_mem_map == 0")
                    return False
                mem_map = section_mem_map & self.SECTION_MAP_MASK
                pfn = (vaddr - self.PAGE_OFFSET) >> self.PAGE_SHIFT
                self.sizeof_struct_page = (page - mem_map) // pfn

        elif is_arm64():
            # CONFIG_SPARSEMEM_VMEMMAP
            self.VMEMMAP_START, self.PAGE_OFFSET = KernelAddressHeuristicFinder.get_VMEMMAP_START()

            # calc sizeof(struct page)
            STRUCT_PAGE_MAX_SHIFT = 6
            self.sizeof_struct_page = 2 ** STRUCT_PAGE_MAX_SHIFT

        elif is_arm32():
            # calc PAGE_OFFSET
            maps = Kernel.get_maps()
            if not maps:
                err("Not found maps")
                return False
            kern_min = maps[0][0]
            if kern_min < 0x80000000:
                self.PAGE_OFFSET = 0x40000000 # VMSPLIT_1G
            elif kern_min < 0xB0000000:
                self.PAGE_OFFSET = 0x80000000 # VMSPLIT_2G
            elif kern_min < 0xBF000000: # 0xBF000000-0xC0000000 is kernel module area. Even if it is VMSPLIT_3G, this is used.
                self.PAGE_OFFSET = 0xB0000000 # VMSPLIT_3G_OPT
            else:
                self.PAGE_OFFSET = 0xC0000000 # VMSPLIT_3G

            self.mem_map = KernelAddressHeuristicFinder.get_mem_map()
            if self.mem_map is None:
                err("Not found mem_map")
                return False

            # calc sizeof(struct page)
            ret = self.get_page_virt_pair()
            if not ret:
                err("Not found valid page/vaddr pair")
                return False
            page, vaddr = ret
            pfn = (vaddr - self.PAGE_OFFSET) >> self.PAGE_SHIFT
            self.sizeof_struct_page = (page - self.mem_map) // pfn

        self.initialized = True
        return True

    def page2virt(self, page):
        if not is_valid_addr(page):
            err("Memory error")
            return None

        if is_x86_64():
            # page -> pfn
            pfn = (page - self.VMEMMAP_START) // self.sizeof_struct_page
            if pfn < 0:
                return None
            # pfn -> virt
            virt = (pfn << self.PAGE_SHIFT) + self.PAGE_OFFSET

        elif is_x86_32():
            if self.mode == "FLATMEM":
                # page -> pfn
                pfn = (page - self.mem_map) // self.sizeof_struct_page
                if pfn < 0:
                    return None
                # pfn -> virt
                virt = (pfn << self.PAGE_SHIFT) + self.PAGE_OFFSET

            elif self.mode == "SPARSEMEM":
                # page -> section_id
                flags = read_int_from_memory(page)
                section_id = (flags >> self.SECTIONS_PGSHIFT) & self.SECTIONS_MASK
                # section_id -> mem_section
                # SECTION_NR_TO_ROOT(nr) always returns nr
                # (nr & SECTION_ROOT_MASK) always returns 0
                mem_section = self.mem_section + self.sizeof_mem_section * section_id
                if not is_valid_addr(mem_section):
                    return None
                # section -> mem_map
                section_mem_map = read_int_from_memory(mem_section)
                if section_mem_map == 0:
                    return None
                mem_map = section_mem_map & self.SECTION_MAP_MASK
                # page -> pfn
                pfn = (page - mem_map) // self.sizeof_struct_page
                if pfn < 0:
                    return None
                # pfn -> virt
                virt = (pfn << self.PAGE_SHIFT) + self.PAGE_OFFSET

        elif is_arm64():
            # page -> pfn
            pfn = (page - self.VMEMMAP_START) // self.sizeof_struct_page
            if pfn < 0:
                return None
            # pfn -> virt
            virt = (pfn << self.PAGE_SHIFT) + self.PAGE_OFFSET

        elif is_arm32():
            # page -> pfn
            pfn = (page - self.mem_map) // self.sizeof_struct_page
            if pfn < 0:
                return None
            # pfn -> virt
            virt = (pfn << self.PAGE_SHIFT) + self.PAGE_OFFSET

        virt = AddressUtil.align_address(virt)
        if not is_valid_addr(virt):
            err("Address in invalid range")
            return None
        return virt

    def virt2page(self, virt):
        if not is_valid_addr(virt):
            err("Memory error")
            return None

        if is_x86_64():
            # virt -> pfn
            if self.START_KERNEL_map <= virt:
                pfn = AddressUtil.align_address(virt - self.START_KERNEL_map + self.phys_base) >> self.PAGE_SHIFT
            else:
                pfn = (virt - self.PAGE_OFFSET) >> self.PAGE_SHIFT
            if pfn < 0:
                return None
            # pfn -> page
            page = self.VMEMMAP_START + (pfn * self.sizeof_struct_page)

        elif is_x86_32():
            if self.mode == "FLATMEM":
                # virt -> pfn
                pfn = (virt - self.PAGE_OFFSET) >> self.PAGE_SHIFT
                if pfn < 0:
                    return None
                # pfn -> page
                page = self.mem_map + (pfn * self.sizeof_struct_page)

            elif self.mode == "SPARSEMEM":
                # virt -> pfn
                pfn = (virt - self.PAGE_OFFSET) >> self.PAGE_SHIFT
                if pfn < 0:
                    return None
                # pfn -> section_id
                section_id = pfn >> self.PFN_SECTION_SHIFT
                # section_id -> mem_section
                # SECTION_NR_TO_ROOT(nr) always returns nr
                # (nr & SECTION_ROOT_MASK) always returns 0
                mem_section = self.mem_section + self.sizeof_mem_section * section_id
                if not is_valid_addr(mem_section):
                    return None
                # section -> mem_map
                section_mem_map = read_int_from_memory(mem_section)
                if section_mem_map == 0:
                    return None
                mem_map = section_mem_map & self.SECTION_MAP_MASK
                # pfn -> page
                page = mem_map + (pfn * self.sizeof_struct_page)

        elif is_arm64():
            # virt -> pfn
            pfn = (virt - self.PAGE_OFFSET) >> self.PAGE_SHIFT
            if pfn < 0:
                return None
            # pfn -> page
            page = self.VMEMMAP_START + (pfn * self.sizeof_struct_page)

        elif is_arm32():
            # virt -> pfn
            pfn = (virt - self.PAGE_OFFSET) >> self.PAGE_SHIFT
            if pfn < 0:
                return None
            # pfn -> page
            page = self.mem_map + (pfn * self.sizeof_struct_page)

        page = AddressUtil.align_address(page)
        if not is_valid_addr(page):
            err("Address in invalid range")
            return None
        return page

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_64", "x86_32", "ARM64", "ARM32"))
    @only_if_in_kernel
    def do_invoke(self, args):
        if args.reparse:
            self.initialized = False

        if is_arm64():
            kversion = Kernel.kernel_version()
            if kversion < "4.7":
                err("Unsupported v4.6 or before")
                return

        if not self.initialized:
            info("Wait for memory scan")
            ret = self.initialize()
            if ret is False:
                err("Failed to initialize")
                return

        out = []
        # doit
        if args.mode == "to-virt":
            # A page may be associated with multiple virtual addresses.
            vaddr = self.page2virt(args.address)
            if vaddr is None:
                err("Failed to resolve")
                return
            out.append("Page: {:#x} -> Virt: {:#x}".format(args.address, vaddr))

        elif args.mode == "to-phys":
            # A page may be associated with multiple virtual addresses.
            vaddr = self.page2virt(args.address)
            if vaddr is None:
                err("Failed to resolve")
                return

            # Get the physical addresses pointed to by those virtual addresses.
            paddr = Kernel.v2p(vaddr)
            if not paddr:
                err("Failed to resolve")
                return
            out.append("Page: {:#x} -> Phys: {:#x}".format(args.address, paddr))

        elif args.mode == "from-virt":
            vaddr = args.address
            if args.address & 0xfff:
                warn("The address must be 0x1000 aligned, round down and then calculate.")
                vaddr = args.address & gef_getpagesize_mask_high()

            # A virtual address is always associated with one physical address.
            page = self.virt2page(vaddr)
            if page is None:
                err("Failed to resolve")
                return
            out.append("Virt: {:#x} -> Page: {:#x}".format(vaddr, page))

        elif args.mode == "from-phys":
            paddr = args.address
            if args.address & 0xfff:
                warn("The address must be 0x1000 aligned, round down and then calculate.")
                paddr = args.address & gef_getpagesize_mask_high()

            r = Kernel.p2v(paddr)
            if not r:
                err("Failed to resolve")
                return

            for vaddr in r:
                # A virtual address is always associated with one page.
                page = self.virt2page(vaddr)
                if page is None:
                    err("Failed to resolve")
                    return
                # The assumption is that there should be one, but just to be sure, all different values will be displayed.
                msg = "Phys: {:#x} -> Page: {:#x}".format(paddr, page)
                if msg not in out:
                    out.append(msg)

        gef_print("\n".join(out))
        return


@register_command
class Page2VirtCommand(GenericCommand):
    """Transfer from page to virtual address (shortcut for `page to-virt ...`)."""
    _cmdline_ = "page2virt"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("page", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="the page address to translate.")
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_64", "x86_32", "ARM64", "ARM32"))
    @only_if_in_kernel
    def do_invoke(self, args):
        rstr = "-r" if args.reparse else ""
        gdb.execute("page to-virt {:s} {:#x}".format(rstr, args.page))
        return


@register_command
class Virt2PageCommand(GenericCommand):
    """Transfer from virtual address to page (shortcut for `page from-virt ...`)."""
    _cmdline_ = "virt2page"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("virt", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="the virtual address to translate.")
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_64", "x86_32", "ARM64", "ARM32"))
    @only_if_in_kernel
    def do_invoke(self, args):
        rstr = "-r" if args.reparse else ""
        gdb.execute("page from-virt {:s} {:#x}".format(rstr, args.virt))
        return


@register_command
class Page2PhysCommand(GenericCommand):
    """Transfer from page to physical address (shortcut for `page to-phys ...`)."""
    _cmdline_ = "page2phys"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("page", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="the page address to translate.")
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_64", "x86_32", "ARM64", "ARM32"))
    @only_if_in_kernel
    def do_invoke(self, args):
        rstr = "-r" if args.reparse else ""
        gdb.execute("page to-phys {:s} {:#x}".format(rstr, args.page))
        return


@register_command
class Phys2PageCommand(GenericCommand):
    """Transfer from physical address to page (shortcut for `page from-phys ...`)."""
    _cmdline_ = "phys2page"
    _category_ = "08-d. Qemu-system Cooperation - Linux Advanced"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("phys", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="the physical address to translate.")
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_64", "x86_32", "ARM64", "ARM32"))
    @only_if_in_kernel
    def do_invoke(self, args):
        rstr = "-r" if args.reparse else ""
        gdb.execute("page from-phys {:s} {:#x}".format(rstr, args.phys))
        return


@register_command
class QemuDeviceInfoCommand(GenericCommand):
    """Dump device information for qemu-escape."""
    _cmdline_ = "qemu-device-info"
    _category_ = "08-a. Qemu-system Cooperation - General"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-d", "--device", help="device name.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    def do_invoke(self, args):
        # get device name
        if args.device:
            device_name = args.device
        else:
            cmdline = String.bytes2str(open("/proc/{:d}/cmdline".format(Pid.get_pid()), "rb").read()).split("\0")
            if cmdline.count("-device") == 0:
                err("Not found `-device` option in qemu-system cmdline")
                return
            if cmdline.count("-device") >= 2:
                devices = []
                for i in range(len(cmdline)):
                    if cmdline[i] == "-device":
                        devices.append(cmdline[i + 1])
                devices_str = Color.colorify(", ".join(devices), "bold")
                err("Multiple `-device` options are found in qemu-system cmdline: {:s}".format(devices_str))
                return
            device_name = cmdline[cmdline.index("-device") + 1]
        info("device name: {:s}".format(Color.colorify(device_name, "bold")))

        # get qdm
        res = gdb.execute("monitor info qdm", to_string=True)
        for line in res.splitlines():
            if device_name in line:
                info("qdev device model: {:s}".format(line))

        # get physmem map / IO map
        res = gdb.execute("monitor info mtree", to_string=True)
        info("Related memory address:")
        maps = [line.strip() for line in res.splitlines() if device_name in line and line.strip().startswith("0")]
        maps = sorted(set(maps)) # uniq
        for m in maps:
            info("  " + m)

        # get qemu-system path
        qemu_path = os.readlink("/proc/{:d}/exe".format(Pid.get_pid()))
        info("qemu path: {:s}".format(qemu_path))

        # get symbol related device
        try:
            nm = GefUtil.which("nm")
        except FileNotFoundError as e:
            err("{}".format(e))
            return

        try:
            result = GefUtil.gef_execute_external([nm, qemu_path], as_list=True)
        except subprocess.CalledProcessError:
            err("Executing `nm` error")
            return

        for line in result:
            if device_name not in line:
                continue
            if line.endswith(("read", "write")):
                index = line.rfind(" ")
                info("  {:s} {:s}".format(line[:index], Color.boldify(line[index + 1:])))
            else:
                info("  {:s}".format(line))

        if not args.device:
            info("use `-d` if less information.")
        return


@register_command
class XUntilCommand(GenericCommand):
    """Execute until specified address. It is slightly easier to use than the original until command."""
    _cmdline_ = "xuntil"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["exec-next", "stepover", "until-next"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("address", metavar="ADDRESS", nargs="?", type=AddressUtil.parse_address,
                        help="the address to stop.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if args.address is None:
            stop_addr = Disasm.gef_instruction_n(current_arch.pc, 1).address
        else:
            stop_addr = args.address
        # `until` command has a bug(?) because sometimes fail, so we should use `tbreak` and `continue` instead of `until`.
        SimpleInternalTemporaryBreakpoint(loc=stop_addr)
        gdb.execute("c") # use c wrapper
        return


@register_command
class ExecUntilCommand(GenericCommand):
    """The base command to execute until specific condition."""
    _cmdline_ = "exec-until"
    _category_ = "01-d. Debugging Support - Execution"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("call")
    subparsers.add_parser("jmp")
    subparsers.add_parser("syscall")
    subparsers.add_parser("ret")
    subparsers.add_parser("all-branch")
    subparsers.add_parser("indirect-branch")
    subparsers.add_parser("memaccess")
    subparsers.add_parser("keyword")
    subparsers.add_parser("cond")
    subparsers.add_parser("user-code")
    subparsers.add_parser("libc-code")
    subparsers.add_parser("secure-world")
    _syntax_ = parser.format_help()

    _example_ = "{:s} call                                # execute until call instruction\n".format(_cmdline_)
    _example_ += "{:s} jmp                                 # execute until jmp instruction\n".format(_cmdline_)
    _example_ += "{:s} syscall                             # execute until syscall instruction\n".format(_cmdline_)
    _example_ += "{:s} ret                                 # execute until ret instruction\n".format(_cmdline_)
    _example_ += "{:s} all-branch                          # execute until call/jmp/ret instruction\n".format(_cmdline_)
    _example_ += "{:s} indirect-branch                     # execute until indirect branch instruction (only x64/x86)\n".format(_cmdline_)
    _example_ += "{:s} memaccess                           # execute until '[' is included by the instruction\n".format(_cmdline_)
    _example_ += '{:s} keyword "call +r[ab]x"              # execute until specified keyword (regex)\n'.format(_cmdline_)
    _example_ += '{:s} cond "$rax==0xdead && $rbx==0xcafe" # execute until specified condition is filled\n'.format(_cmdline_)
    _example_ += "{:s} user-code                           # execute until user code\n".format(_cmdline_)
    _example_ += "{:s} libc-code                           # execute until libc code\n".format(_cmdline_)
    _example_ += "{:s} secure-world                        # execute until secure world (only ARM/ARM64)".format(_cmdline_)

    def __init__(self, *args, **kwargs):
        prefix = kwargs.get("prefix", True)
        super().__init__(prefix=prefix)
        self.mode = None
        return

    def close_stdout_stderr(self):
        self.stdout = 1
        self.stdout_bak = os.dup(self.stdout)
        f = open("/dev/null")
        os.dup2(f.fileno(), self.stdout)
        f.close()

        self.stderr = 2
        self.stderr_bak = os.dup(self.stderr)
        f = open("/dev/null")
        os.dup2(f.fileno(), self.stderr)
        f.close()
        return

    def revert_stdout_stderr(self):
        os.dup2(self.stdout_bak, self.stdout)
        os.close(self.stdout_bak)
        os.dup2(self.stderr_bak, self.stderr)
        os.close(self.stderr_bak)
        return

    def force_write_stdout(self, msg):
        open("/proc/self/fd/0", "wb").write(msg)
        return

    def check_jump_taken(self, insn):
        if not current_arch.is_jump(insn):
            return False

        if (self.only_taken, self.only_not_taken) == (False, False):
            return True
        elif (self.only_taken, self.only_not_taken) == (True, False):
            if current_arch.is_conditional_branch(insn):
                taken, _reason = current_arch.is_branch_taken(insn)
                return taken
            else:
                return True # non-conditional, so always jump
        elif (self.only_taken, self.only_not_taken) == (False, True):
            if current_arch.is_conditional_branch(insn):
                taken, _reason = current_arch.is_branch_taken(insn)
                return not taken
            else:
                return False # non-conditional, so always jump
        raise

    def is_target_insn(self, insn):
        if self.mode == "call":
            return current_arch.is_call(insn)
        elif self.mode == "jmp":
            return self.check_jump_taken(insn)
        elif self.mode == "indirect-branch":
            if current_arch.is_call(insn) or self.check_jump_taken(insn):
                if "[" in str(insn):
                    return True
                for reg in current_arch.gpr_registers:
                    if reg.replace("$", "") in str(insn):
                        return True
            return False
        elif self.mode == "syscall":
            if current_arch.is_syscall(insn):
                if not self.filter and not self.ignore:
                    return True
                _reg, nr = SyscallArgsCommand.get_nr()
                try:
                    name = get_syscall_table().table[nr].name
                except KeyError:
                    return True # for debug
                if self.ignore and name in self.ignore:
                    return False
                if self.filter:
                    return name in self.filter
                else:
                    return True
            return False
        elif self.mode == "ret":
            return current_arch.is_ret(insn)
        if self.mode == "all-branch":
            return current_arch.is_call(insn) or self.check_jump_taken(insn) or current_arch.is_ret(insn)
        elif self.mode == "memaccess":
            return "[" in str(insn)
        elif self.mode == "keyword":
            for re_pattern in self.keyword:
                if re_pattern.search(str(insn)):
                    return True
            return False
        elif self.mode == "cond":
            try:
                v = gdb.parse_and_eval(self.condition)
            except gdb.error:
                return False
            if v not in [0x0, 0x1]:
                self.err = "condition result should be True or False"
                return True
            if v:
                return True
        elif self.mode == "user-code":
            for p in self.code_addrs:
                if p.page_start <= insn.address <= p.page_end:
                    return True
            else:
                return False
        elif self.mode == "libc-code":
            for p in self.libc_addrs:
                if p.page_start <= insn.address <= p.page_end:
                    return True
            else:
                return False
        elif self.mode == "secure-world":
            scr = get_register("$SCR" if is_arm32() else "$SCR_EL3")
            if scr is None:
                return False
            return (scr & 0b1) == 0
        return False

    def get_breakpoint_list(self):
        lines = gdb.execute("info breakpoints", to_string=True).splitlines()
        if lines[0] == "No breakpoints or watchpoints.":
            return []
        if lines[0] == "No breakpoints, watchpoints, tracepoints, or catchpoints.": # gdb 15.x ~
            return []

        enable_idx = lines[0].index("Enb")
        addr_idx = lines[0].index("Address")

        bp_list = []
        for line in lines[1:]:
            try:
                if line[0] == "\t":
                    continue
                enable = line[enable_idx]
                addr = int(line[addr_idx:].split()[0], 16)
                if enable == "y":
                    bp_list.append(addr)
            except Exception:
                pass
        # breakpoint with condition is unsupported
        return bp_list

    def exec_next(self):
        bp_list = self.get_breakpoint_list()
        EventHooking.gef_on_stop_unhook(EventHandler.hook_stop_handler)
        self.close_stdout_stderr()
        self.err = None

        prev_addr = -1
        try:
            count = 0
            while True:
                # progress
                if not self.print_insn and count % 100 == 0:
                    self.force_write_stdout([b"\r|", b"\r/", b"\r-", b"\r\\"][count // 100 % 4])

                # backup
                prev_prev_addr = prev_addr
                prev_addr = current_arch.pc

                # execute 1 instruction
                insn = get_insn()
                if self.use_ni or (self.skip_lib and "@plt>" in str(insn)):
                    gdb.execute("ni") # use ni wrapper
                else:
                    gdb.execute("si") # use si wrapper

                # check breakpoint
                insn = get_insn()
                if current_arch.pc in bp_list:
                    break

                # $pc is not changed
                if prev_prev_addr == prev_addr == current_arch.pc: # for faster, repeat insn is skip
                    # infinity self loop
                    if current_arch.is_call(insn) or current_arch.is_jump(insn) or current_arch.is_ret(insn):
                        self.err = "Detected infinity loop prev_addr ({:#x})".format(prev_addr)
                        break
                    # maybe rep prefix
                    gdb.execute("xuntil")
                    # recheck
                    if prev_prev_addr == prev_addr == current_arch.pc:
                        self.err = "Detected infinity loop prev_addr ({:#x})".format(prev_addr)
                        break
                    insn = get_insn()

                if self.print_insn:
                    self.force_write_stdout((str(insn) + "\n").encode())

                # found and break
                if self.is_target_insn(insn) and current_arch.pc not in self.exclude:
                    if not self.print_insn:
                        self.force_write_stdout(b"\r \r")
                    break

                count += 1

        except KeyboardInterrupt:
            pass

        except Exception:
            if is_alive():
                exc_type, exc_value, exc_traceback = sys.exc_info()
                self.err = exc_value
            else:
                pass

        finally:
            self.revert_stdout_stderr() # anytime needed
            EventHooking.gef_on_stop_hook(EventHandler.hook_stop_handler) # anytime needed
            Cache.reset_gef_caches()
            if self.err:
                err(self.err)
            else:
                gdb.execute("context")
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        if self.mode is None:
            self.usage()
            return
        self.print_insn = args.print_insn
        self.use_ni = args.use_ni
        self.skip_lib = args.skip_lib
        self.exclude = args.exclude
        self.exec_next()
        return


@register_command
class ExecUntilCallCommand(ExecUntilCommand):
    """Execute until next call instruction."""
    _cmdline_ = "exec-until call"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-call"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    _syntax_ = parser.format_help()
    _example_ = None

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "call"
        return


@register_command
class ExecUntilJumpCommand(ExecUntilCommand):
    """Execute until next jmp instruction."""
    _cmdline_ = "exec-until jmp"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-jmp"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-t", "--only-taken", action="store_true", help="break only if jump will be taken.")
    group.add_argument("-T", "--only-not-taken", action="store_true", help="break only if jump will be not taken.")
    _syntax_ = parser.format_help()
    _example_ = None

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "jmp"
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        self.print_insn = args.print_insn
        self.use_ni = args.use_ni
        self.skip_lib = args.skip_lib
        self.exclude = args.exclude
        self.only_taken = args.only_taken
        self.only_not_taken = args.only_not_taken
        self.exec_next()
        return


@register_command
class ExecUntilIndirectBranchCommand(ExecUntilCommand):
    """Execute until next indirect call/jmp instruction (only x64/x86)."""
    _cmdline_ = "exec-until indirect-branch"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-indirect-branch"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-t", "--only-taken", action="store_true", help="break only if jump will be taken.")
    group.add_argument("-T", "--only-not-taken", action="store_true", help="break only if jump will be not taken.")
    _syntax_ = parser.format_help()
    _example_ = None

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "indirect-branch"
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        self.print_insn = args.print_insn
        self.use_ni = args.use_ni
        self.skip_lib = args.skip_lib
        self.exclude = args.exclude
        self.only_taken = args.only_taken
        self.only_not_taken = args.only_not_taken
        self.exec_next()
        return


@register_command
class ExecUntilAllBranchCommand(ExecUntilCommand):
    """Execute until next call/jump/ret instruction."""
    _cmdline_ = "exec-until all-branch"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-all-branch"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-t", "--only-taken", action="store_true", help="break only if jump will be taken.")
    group.add_argument("-T", "--only-not-taken", action="store_true", help="break only if jump will be not taken.")
    _syntax_ = parser.format_help()
    _example_ = None

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "all-branch"
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        self.print_insn = args.print_insn
        self.use_ni = args.use_ni
        self.skip_lib = args.skip_lib
        self.exclude = args.exclude
        self.only_taken = args.only_taken
        self.only_not_taken = args.only_not_taken
        self.exec_next()
        return


@register_command
class ExecUntilSyscallCommand(ExecUntilCommand):
    """Execute until next syscall instruction."""
    _cmdline_ = "exec-until syscall"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-syscall"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-f", "--filter", action="append", default=[], help="filter by specified syscall.")
    parser.add_argument("-i", "--ignore", action="append", default=[], help="ignore specified syscall.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    _syntax_ = parser.format_help()
    _example_ = None

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "syscall"
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("wine",))
    def do_invoke(self, args):
        self.print_insn = args.print_insn
        self.use_ni = args.use_ni
        self.skip_lib = args.skip_lib
        self.filter = args.filter
        self.ignore = args.ignore
        self.exclude = args.exclude
        self.exec_next()
        return


@register_command
class ExecUntilRetCommand(ExecUntilCommand):
    """Execute until next ret instruction."""
    _cmdline_ = "exec-until ret"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-ret"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    _syntax_ = parser.format_help()
    _example_ = None

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "ret"
        return


@register_command
class ExecUntilMemaccessCommand(ExecUntilCommand):
    """Execute until next mem-access instruction."""
    _cmdline_ = "exec-until memaccess"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-mem"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    _syntax_ = parser.format_help()
    _example_ = None

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "memaccess"
        return


@register_command
class ExecUntilKeywordReCommand(ExecUntilCommand):
    """Execute until specified keyword instruction."""
    _cmdline_ = "exec-until keyword"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-keyword"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    parser.add_argument("keyword", metavar="KEYWORD", type=re.compile, nargs="+",
                        help="filter by specified regex keyword.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} "call +r[ab]x"                        # execute until specified keyword\n'.format(_cmdline_)
    _example_ += '{:s} "(push|pop) +(r[a-d]x|r[ds]i|r[sb]p)" # another example\n'.format(_cmdline_)
    _example_ += '{:s} "mov +rax, QWORD PTR \\\\["             # another example (need double escape)'.format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "keyword"
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        self.print_insn = args.print_insn
        self.use_ni = args.use_ni
        self.skip_lib = args.skip_lib
        self.keyword = args.keyword
        self.exclude = args.exclude
        self.exec_next()
        return


@register_command
class ExecUntilCondCommand(ExecUntilCommand):
    """Execute until specified condition is filled."""
    _cmdline_ = "exec-until cond"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-cond"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    parser.add_argument("condition", metavar="CONDITION", help="filter by condition.")
    _syntax_ = parser.format_help()

    _example_ = '{:s} "$rax==0xdead && $rbx==0xcafe"    # execute until specified condition is filled\n'.format(_cmdline_)
    _example_ += '{:s} "$rax==0x12 && *(int*)$rbx==0x34" # multiple condition and memory access is supported\n'.format(_cmdline_)
    _example_ += '{:s} "$ALL_REG==0x1234"                # compare with all regs. e.g.: `($rax==0x1234 || $rbx==0x1234 || ...)`'.format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "cond"
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        self.print_insn = args.print_insn
        self.use_ni = args.use_ni
        self.skip_lib = args.skip_lib
        self.exclude = args.exclude

        condition = args.condition
        if re.search(r"[^><!=]=[^=]", condition):
            err("Should not use `=` since it will be replace register/memory value. Use `==`.")
            return

        match = re.search(r"\$ALL_REG==(\w+)", condition)
        if match:
            value = match.groups()[0]
            replace_cond = []
            if hasattr(current_arch, "gpr_registers"):
                regs = current_arch.gpr_registers
            else:
                regs = current_arch.all_registers
                if hasattr(current_arch, "flag_register"):
                    if current_arch.flag_register in regs:
                        regs.remove(current_arch.flag_register)
            for regname in regs:
                replace_cond.append("{:s}=={:s}".format(regname, value))
            replace_string = "(" + "||".join(replace_cond) + ")"
            condition = re.sub(r"\$ALL_REG==(\w+)", replace_string, condition)

        info("Condition: {:s}".format(condition))
        self.condition = condition
        self.exec_next()
        return


@register_command
class ExecUntilUserCodeCommand(ExecUntilCommand):
    """Execute until next user-code instruction."""
    _cmdline_ = "exec-until user-code"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-user-code"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    _syntax_ = parser.format_help()
    _example_ = None

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "user-code"
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        if self.mode is None:
            self.usage()
            return
        self.print_insn = args.print_insn
        self.use_ni = args.use_ni
        self.skip_lib = args.skip_lib
        self.exclude = args.exclude

        filepath = Path.get_filepath(append_proc_root_prefix=False)
        if not filepath and is_remote_debug():
            filepath = gdb.current_progspace().filename
            if filepath and filepath.startswith("target:"):
                filepath = filepath[7:]

        maps = ProcessMap.get_process_maps()
        self.code_addrs = [p for p in maps if p.permission.value & Permission.EXECUTE and p.path == filepath]
        if not self.code_addrs:
            err("Not found code address")
            return
        self.exec_next()
        return


@register_command
class ExecUntilLibcCodeCommand(ExecUntilCommand):
    """Execute until next libc instruction."""
    _cmdline_ = "exec-until libc-code"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-libc-code"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("--skip-lib", action="store_true",
                        help="use `ni` instead of `si` if instruction is `call xxx@plt`.")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    _syntax_ = parser.format_help()
    _example_ = None

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "libc-code"
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware", "wine"))
    def do_invoke(self, args):
        if self.mode is None:
            self.usage()
            return
        self.print_insn = args.print_insn
        self.use_ni = args.use_ni
        self.skip_lib = args.skip_lib
        self.exclude = args.exclude

        libc_targets = ("libc-2.", "libc.so.6", "libuClibc-")
        libc = ProcessMap.process_lookup_path(libc_targets)
        maps = ProcessMap.get_process_maps()
        self.libc_addrs = [p for p in maps if p.permission.value & Permission.EXECUTE and p.path == libc.path]
        if not self.libc_addrs:
            err("Not found libc address")
            return
        self.exec_next()
        return


@register_command
class ExecUntilSecureWorldCommand(ExecUntilCommand):
    """Execute until next secure-world instruction (only ARM/ARM64)."""
    _cmdline_ = "exec-until secure-world"
    _category_ = "01-d. Debugging Support - Execution"
    _repeat_ = True
    _aliases_ = ["next-secure-world"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("--print-insn", action="store_true", help="print each instruction during execution.")
    parser.add_argument("-n", "--use-ni", action="store_true", help="use `ni` instead of `si`")
    parser.add_argument("-e", "--exclude", action="append", type=AddressUtil.parse_address, default=[],
                        help="the address to exclude from breakpoints.")
    _syntax_ = parser.format_help()
    _example_ = None

    def __init__(self):
        super().__init__(prefix=False)
        self.mode = "secure-world"
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("ARM32", "ARM64"))
    def do_invoke(self, args):
        if self.mode is None:
            self.usage()
            return
        self.print_insn = args.print_insn
        self.use_ni = args.use_ni
        self.skip_lib = False
        self.exclude = args.exclude

        scr = get_register("$SCR" if is_arm32() else "$SCR_EL3")
        if scr is None:
            err("Not found {:s}".format("$SCR" if is_arm32() else "$SCR_EL3"))
            return

        self.exec_next()
        return


class CallUsermodehelperSetupBreakpoint(gdb.Breakpoint):
    """Create a breakpoint to print argv information at call_usermodehelper_setup."""
    def __init__(self, loc):
        super().__init__("*{:#x}".format(loc), gdb.BP_BREAKPOINT, internal=False)
        return

    def stop(self):
        ptr1, addr1 = current_arch.get_ith_parameter(0)
        ptr2, addr2 = current_arch.get_ith_parameter(1)
        path = read_cstring_from_memory(addr1)
        argv = []
        while True:
            string_addr = read_int_from_memory(addr2)
            if string_addr == 0:
                break
            string = read_cstring_from_memory(string_addr)
            argv.append("'{:s}'".format(string))
            addr2 += current_arch.ptrsize
        gef_print("{:s}: {:#x} -> '{:s}'".format(ptr1, addr1, path))
        gef_print("{:s}: {:#x} -> [{:s}]".format(ptr2, addr2, ",".join(argv)))
        return False # continue


@register_command
class UsermodehelperTracerCommand(GenericCommand):
    """Collect and display information that is executed by call_usermodehelper_setup."""
    _cmdline_ = "usermodehelper-tracer"
    _category_ = "08-f. Qemu-system Cooperation - Linux Dynamic Inspection"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel
    def do_invoke(self, args):
        info("Resolving the function addresses")
        addr = Symbol.get_ksymaddr("call_usermodehelper_setup")
        if addr is None:
            err("Not found call_usermodehelper_setup")
            return
        CallUsermodehelperSetupBreakpoint(addr)
        info("Setup is complete. Try `continue`.")
        return


class ThunkBreakpoint(gdb.Breakpoint):
    """Create a breakpoint to print caller address for thunk function."""
    def __init__(self, loc, sym, reg, maps):
        super().__init__("*{:#x}".format(loc), gdb.BP_BREAKPOINT, internal=False)
        self.loc = loc
        self.sym = sym
        self.reg = reg
        self.maps = maps
        self.seen = []
        return

    def search_perm(self, target):
        for m in self.maps:
            addr, size, perm = m
            if addr <= target < addr + size:
                return perm.lower()
        return "?"

    def stop(self):
        try:
            return_address = gdb.selected_frame().older().pc()
            caller_address = Disasm.gdb_get_nth_previous_instruction_address(return_address, 1)
            target_address = get_register(self.reg)
        except gdb.error:
            return False # continue

        # duplicate, check
        if (caller_address, target_address) in self.seen:
            return False # continue
        else:
            self.seen.append((caller_address, target_address))

        # get caller address, symbol
        caller_symbol = Symbol.get_symbol_string(caller_address, nosymbol_string=" <NO_SYMBOL>")

        # get callee address, symbol
        target_symbol = Symbol.get_symbol_string(target_address, nosymbol_string=" <NO_SYMBOL>")

        # print information
        if caller_address is None:
            fmt = "{:s}{:s} -> {:#x} <{:s}> -> {:#x}{:s}"
            msg = fmt.format("???(unknown)", caller_symbol, self.loc, self.sym, target_address, target_symbol)
        else:
            fmt = "{:#x}{:s} -> {:#x} <{:s}> -> {:#x}{:s}"
            msg = fmt.format(caller_address, caller_symbol, self.loc, self.sym, target_address, target_symbol)
        info(msg)

        # print preferred register condition
        pattern = [0] + [(x + 1) * y for x, y in itertools.product(range(0x100), [1, -1])] # [0, 1, -1, 2, -2, ...]
        for reg in current_arch.gpr_registers:
            reg_value = get_register(reg)
            for i in pattern:
                slide = current_arch.ptrsize * i
                reg_value_slided = reg_value + slide
                try:
                    mem_value = read_int_from_memory(reg_value_slided)
                except (gdb.MemoryError, OverflowError):
                    continue
                if mem_value == target_address:
                    perm = self.search_perm(reg_value_slided)
                    reg_value_slided_symbol = Symbol.get_symbol_string(reg_value_slided, nosymbol_string=" <NO_SYMBOL>")
                    mem_value_symbol = Symbol.get_symbol_string(mem_value, nosymbol_string=" <NO_SYMBOL>")
                    fmt = "    {:s}{:+#x}: {:#x}{:s} [{:s}]  ->  {:#x}{:s}"
                    info(fmt.format(reg, slide, reg_value_slided, reg_value_slided_symbol, perm, mem_value, mem_value_symbol))
                    break
        return False # continue


@register_command
class ThunkTracerCommand(GenericCommand):
    """Collect and display the thunk addresses that are called automatically (only x64/x86)."""
    _cmdline_ = "thunk-tracer"
    _category_ = "08-f. Qemu-system Cooperation - Linux Dynamic Inspection"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    @only_if_in_kernel
    def do_invoke(self, args):
        info("Wait for memory scan")
        maps = Kernel.get_maps() # [vaddr, size, perm]
        info("Resolving thunk function addresses")
        for reg in current_arch.gpr_registers:
            if reg in ["$esp", "$rsp", "$eip", "$rip"]:
                continue
            sym = "__x86_indirect_thunk_{}".format(reg.replace("$", ""))
            addr = Symbol.get_ksymaddr(sym)
            if addr is None:
                continue
            gef_print(sym + ": ", end="")
            ThunkBreakpoint(addr, sym, reg, maps)
        info("Setup is complete. Try `continue`.")
        return


class KmallocBreakpoint(gdb.Breakpoint):
    """Create a breakpoint to print information of kmalloc."""
    def __init__(self, loc, sym, index_of_size_arg, task, option, extra):
        super().__init__("*{:#x}".format(loc), gdb.BP_BREAKPOINT, internal=False)
        self.sym = sym
        self.index_of_size_arg = index_of_size_arg
        self.task_addr = task
        self.option = option
        self.extra = extra
        self.enabled = False
        return

    def stop(self):
        Cache.reset_gef_caches()

        task_addr, _ = KmallocTracerCommand.get_task()
        if self.task_addr and task_addr != self.task_addr:
            return False

        if self.index_of_size_arg >= 0:
            _, size = current_arch.get_ith_parameter(self.index_of_size_arg)
        else:
            _, kmem_cache = current_arch.get_ith_parameter(0)
            slab_cache_name_ptr = read_int_from_memory(kmem_cache + self.extra.kmem_cache_offset_name)
            slab_cache_name = read_cstring_from_memory(slab_cache_name_ptr)
            if not slab_cache_name.startswith("kmalloc-"):
                return False
            size = u32(read_memory(kmem_cache + self.extra.kmem_cache_offset_size, 4))

        KmallocRetBreakpoint(size, self.sym, self.option, self.extra)
        return False


class KmallocRetBreakpoint(gdb.FinishBreakpoint):
    """Create a breakpoint to print information of kmalloc."""
    def __init__(self, size, sym, option, extra):
        super().__init__(gdb.newest_frame(), internal=True)
        # gdb.FinishBreakpoint detects that it is desired task or not, from frame information
        self.size = size
        self.sym = sym
        self.option = option
        self.extra = extra
        return

    def stop(self):
        Cache.reset_gef_caches()

        task_addr, task_name = KmallocTracerCommand.get_task()
        task_prefix = Color.boldify("[task:{:#018x} {:16s}]".format(task_addr, task_name))

        if self.return_value:
            loc = int(self.return_value)
        else:
            loc = AddressUtil.parse_address(current_arch.return_register)
        loc_s = Color.colorify_hex(loc, Config.get_gef_setting("theme.heap_chunk_address_used"))

        if self.extra:
            ret = KmallocTracerCommand.virt2name_and_size(self.extra, loc)
            if ret:
                # print more info
                name, chunk_size = ret
                if not name.startswith("kmalloc-"):
                    return False
                if self.option.filter and name not in self.option.filter:
                    return False
                name_s = Color.colorify(name, Config.get_gef_setting("theme.heap_chunk_label"))
                chunk_size_s = Color.colorify("{:<#6x}".format(chunk_size), Config.get_gef_setting("theme.heap_chunk_size"))
                gef_print("{:s} {:30s}: {:s} (size: {:s} name: {:s})".format(task_prefix, self.sym, loc_s, chunk_size_s, name_s))
                KmallocTracerCommand.print_backtrace(self.option.backtrace)
                KmallocTracerCommand.dump_chunk(self.option.dump_chunk, loc)
                return False
            # fall through

        # print less info
        gef_print("{:s} {:30s}: {:s} (size: {:<#6x})".format(task_prefix, self.sym, loc_s, self.size))
        KmallocTracerCommand.print_backtrace(self.option.backtrace)
        KmallocTracerCommand.dump_chunk(self.option.dump_chunk, loc)
        return False


class KfreeBreakpoint(gdb.Breakpoint):
    """Create a breakpoint to print information of kfree."""
    def __init__(self, loc, sym, index_of_addr_arg, task, option, extra):
        super().__init__("*{:#x}".format(loc), gdb.BP_BREAKPOINT, internal=False)
        self.sym = sym
        self.index_of_addr_arg = index_of_addr_arg
        self.task_addr = task
        self.option = option
        self.extra = extra
        self.enabled = False
        return

    def stop(self):
        Cache.reset_gef_caches()

        _, loc = current_arch.get_ith_parameter(self.index_of_addr_arg)
        if not self.option.print_null and loc == 0:
            return False

        task_addr, task_name = KmallocTracerCommand.get_task()
        if self.task_addr and task_addr != self.task_addr:
            return False
        task_prefix = Color.boldify("[task:{:#018x} {:16s}]".format(task_addr, task_name))

        loc_s = Color.colorify_hex(loc, Config.get_gef_setting("theme.heap_chunk_address_freed"))

        if self.extra:
            ret = KmallocTracerCommand.virt2name_and_size(self.extra, loc)
            if ret:
                # print more info
                name, chunk_size = ret
                if not name.startswith("kmalloc-"):
                    return False
                if self.option.filter and name not in self.option.filter:
                    return False
                name_s = Color.colorify(name, Config.get_gef_setting("theme.heap_chunk_label"))
                chunk_size_s = Color.colorify("{:<#6x}".format(chunk_size), Config.get_gef_setting("theme.heap_chunk_size"))
                gef_print("{:s} {:30s}: {:s} (size: {:s} name: {:s})".format(task_prefix, self.sym, loc_s, chunk_size_s, name_s))
                KmallocTracerCommand.print_backtrace(self.option.backtrace)
                KmallocTracerCommand.dump_chunk(self.option.dump_chunk, loc)
                return False
            # fall through

        # print less info
        gef_print("{:s} {:30s}: {:s}".format(task_prefix, self.sym, loc_s))
        KmallocTracerCommand.print_backtrace(self.option.backtrace)
        KmallocTracerCommand.dump_chunk(self.option.dump_chunk, loc)
        return False


@register_command
class KmallocTracerCommand(GenericCommand):
    """Collect and display information when kmalloc/kfree."""
    _cmdline_ = "kmalloc-tracer"
    _category_ = "08-f. Qemu-system Cooperation - Linux Dynamic Inspection"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--filter", default=[], help="filter specified name (e.g.: kmalloc-XX)")
    parser.add_argument("--print-null", action="store_true", help="display free(NULL).")
    parser.add_argument("-t", "--backtrace", action="store_true", help="display backtrace.")
    parser.add_argument("-d", "--dump-chunk", action="store_true", help="dump the first 0x40 bytes of each chunk.")
    parser.add_argument("-v", "--verbose", action="store_true", help="print meta information.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}         # simple output\n".format(_cmdline_)
    _example_ += "{:s} -dtv    # useful output".format(_cmdline_)

    _note_ = "Disable `-enable-kvm` option for qemu-system (#PF may occur).\n"
    _note_ += "Append `tsc=unstable` option for kernel cmdline.\n"
    _note_ += "This command needs CONFIG_RANDSTRUCT=n."

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        return

    @staticmethod
    def create_option_info(args):
        dic = {
            "print_null": args.print_null,
            "backtrace": args.backtrace,
            "filter": args.filter,
            "dump_chunk": args.dump_chunk,
        }
        OptionInfo = collections.namedtuple("OptionInfo", dic.keys())
        option_info = OptionInfo(*dic.values())
        return option_info

    @staticmethod
    def initialize(allocator, verbose):
        if allocator != "SLUB":
            # Do nothing other than SLUB.
            extra_info = None
            return extra_info

        res = gdb.execute("slub-dump --meta", to_string=True)

        r = re.search(r"offsetof\(page, slab_cache\): (0x\S+)", res)
        if not r:
            return False
        page_offset_slab_cache = int(r.group(1), 16)
        if verbose:
            info("offsetof(page, slab_cache): {:#x}".format(page_offset_slab_cache))

        r = re.search(r"offsetof\(kmem_cache, name\): (0x\S+)", res)
        if not r:
            return False
        kmem_cache_offset_name = int(r.group(1), 16)
        if verbose:
            info("offsetof(kmem_cache, name): {:#x}".format(kmem_cache_offset_name))

        r = re.search(r"offsetof\(kmem_cache, size\): (0x\S+)", res)
        if not r:
            return False
        kmem_cache_offset_size = int(r.group(1), 16)
        if verbose:
            info("offsetof(kmem_cache, size): {:#x}".format(kmem_cache_offset_size))

        # create extra_info
        dic = {
            "kmem_cache_offset_name": kmem_cache_offset_name,
            "kmem_cache_offset_size": kmem_cache_offset_size,
            "page_offset_slab_cache": page_offset_slab_cache,
        }
        ExtraInfo = collections.namedtuple("ExtraInfo", dic.keys())
        extra_info = ExtraInfo(*dic.values())
        return extra_info

    @staticmethod
    def get_task():
        th_num = gdb.selected_thread().num
        res = gdb.execute("kcurrent --quiet", to_string=True)
        r = re.search(r"current \(cpu{:d}\): (0x\S+) (.*)".format(th_num - 1), res)
        if r:
            task = int(r.group(1), 16)
            name = r.group(2)
            return task, name
        return 0, ""

    @staticmethod
    def virt2name_and_size(extra, vaddr):
        ret = Kernel.get_slab_contains(vaddr)
        if not ret:
            return None
        r = re.search(r"name: (\S+)  size: (\S+)", ret)
        if not r:
            return None
        slab_cache_name = r.group(1)
        slab_cache_size = int(r.group(2), 16)
        return slab_cache_name, slab_cache_size

    @staticmethod
    def print_backtrace(backtrace):
        if not backtrace:
            return

        try:
            frame = gdb.newest_frame()
            while frame and frame.is_valid():
                addr = frame.pc()
                if not is_valid_addr(addr):
                    break
                sym = Symbol.get_symbol_string(addr, nosymbol_string=" <NO_SYMBOL>")
                gef_print("  {:#018x}{:s}".format(addr, sym))
                frame = frame.older()
        except gdb.error:
            return

    @staticmethod
    def dump_chunk(dump, loc):
        if not dump:
            return
        if not is_valid_addr(loc):
            err("Invalid address")
            return
        gdb.execute("dereference -n {:#x} 8".format(loc))
        return

    @staticmethod
    def set_bp_to_kmalloc_kfree(option_info, extra_info, task_addr=None):
        # Since `kmalloc` is always inlined and not exported, so the symbol cannot be determined.
        # So put a breakpoint in each non-inlined function called from kmalloc.
        """
        (1) static __always_inline void *kmalloc(size_t size, gfp_t flags)
            - [~v6.1]
                - static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
                    - [CONFIG_TRACING=n]
                        - static __always_inline void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
                            - void *kmalloc_order(size_t size, gfp_t flags, unsigned int order) <-- bp here
                    - [CONFIG_TRACING=y]
                        - void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
                            - void *kmalloc_order(size_t size, gfp_t flags, unsigned int order) <-- bp here
                - [CONFIG_TRACING=y]
                    - void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t flags, size_t size) <-- bp here
                - [CONFIG_TRACING=n]
                    - static __always_inline void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t flags, size_t size)
                        - void *kmem_cache_alloc(struct kmem_cache *s, gfp_t flags) <-- bp here

            - [v6.1~]
                - void *kmalloc_large(size_t size, gfp_t flags) <-- bp here
                - void *kmalloc_trace(struct kmem_cache *s, gfp_t flags, size_t size) <-- bp here

            - void *__kmalloc(size_t size, gfp_t flags) <-- bp here

        (2) static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
            - [~v6.1]
                - [CONFIG_NUMA=n]
                    - redirect to kmem_cache_alloc_trace
                - [CONFIG_TRACING=y]
                    - void *kmem_cache_alloc_node_trace(struct kmem_cache *s, gfp_t flags, int node, size_t size) <-- bp here
                - [CONFIG_TRACING=n && CONFIG_NUMA=n]
                    - redirect to kmem_cache_alloc
                - [CONFIG_TRACING=n && CONFIG_NUMA=y]
                    - static __always_inline void *kmem_cache_alloc_node_trace(struct kmem_cache *s, gfp_t gfpflags, int node, size_t size)
                        - void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t flags, int node) <-- bp here

            - [v6.1~]
                - void *kmalloc_node_trace(struct kmem_cache *s, gfp_t flags, int node, size_t size) <-- bp here

            - [CONFIG_NUMA=n]
                - redirect to __kmalloc
            - [CONFIG_NUMA=y]
                void *__kmalloc_node(size_t size, gfp_t flags, int node) <-- bp here

        (3) void *memdup_user(const void __user *src, size_t len), etc.
            - void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller) <-- bp here

        (4) void *krealloc(const void *p, size_t new_size, gfp_t flags) <-- bp here

        (5) void kfree(const void *object) <-- bp here

        (Other)
        * kmalloc_array -> kmalloc or __kmalloc
        * kmalloc_array_node -> kmalloc_node or __kmalloc_node
        * krealloc_array -> krealloc
        * kcalloc -> kmalloc_array
        * kcalloc_node -> kmalloc_array_node
        * kzalloc -> kmalloc
        * kzalloc_node -> kmalloc_node
        """

        kversion = Kernel.kernel_version()
        if kversion < "6.1":
            # number is the argument index of the size.
            # -1 means index 0 is `struct kmem_cache*`.
            kmalloc_syms = [
                # for kmalloc
                [0, "kmalloc_order"],
                [2, "kmem_cache_alloc_trace"],
                [-1, "kmem_cache_alloc"],
                [0, "__kmalloc"],
                # for kmalloc_node
                [3, "kmem_cache_alloc_node_trace"],
                [-1, "kmem_cache_alloc_node"],
                [0, "__kmalloc_node"],
                # for memdup_user, etc.
                [0, "__kmalloc_track_caller"],
                # for krealloc
                [1, "krealloc"],
            ]
        else:
            kmalloc_syms = [
                # for kmalloc
                [0, "kmalloc_large"],
                [2, "kmalloc_trace"],
                [0, "__kmalloc"],
                # for kmalloc_node
                [3, "kmalloc_node_trace"],
                [0, "__kmalloc_node"],
                # for memdup_user, etc.
                [0, "__kmalloc_track_caller"],
                # for krealloc
                [1, "krealloc"],
            ]

        kfree_syms = [
            # number is the argument index of the address.
            [0, "kfree"],
        ]

        breakpoints = []
        for index_of_size_arg, sym in kmalloc_syms:
            func_addr = Symbol.get_ksymaddr(sym)
            if func_addr:
                gef_print(sym + ": ", end="")
                bp = KmallocBreakpoint(func_addr, sym, index_of_size_arg, task_addr, option_info, extra_info)
                breakpoints.append(bp)
        for index_of_addr_arg, sym in kfree_syms:
            func_addr = Symbol.get_ksymaddr(sym)
            if func_addr:
                gef_print(sym + ": ", end="")
                bp = KfreeBreakpoint(func_addr, sym, index_of_addr_arg, task_addr, option_info, extra_info)
                breakpoints.append(bp)
        return breakpoints

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel
    @only_if_kvm_disabled
    def do_invoke(self, args):
        # create option_info
        option_info = KmallocTracerCommand.create_option_info(args)

        # initialize
        info("Wait for memory scan")
        allocator = KernelChecksecCommand.get_slab_type()
        if allocator != "SLUB":
            warn("Unsupported viewing detailed information for SLAB, SLOB, SLUB_TINY")
            # fall through

        if not self.initialized:
            ret = KmallocTracerCommand.initialize(allocator, args.verbose)
            if ret is False:
                err("Failed to initialize")
                return
            self.initialized = True
            self.extra_info = ret # allow None
        else:
            if args.verbose and self.extra_info:
                info("offsetof(page, slab_cache): {:#x}".format(self.extra_info.page_offset_slab_cache))
                info("offsetof(kmem_cache, name): {:#x}".format(self.extra_info.kmem_cache_offset_name))
                info("offsetof(kmem_cache, size): {:#x}".format(self.extra_info.kmem_cache_offset_size))

        # set kmalloc break points
        breakpoints = KmallocTracerCommand.set_bp_to_kmalloc_kfree(option_info, self.extra_info)
        for bp in breakpoints:
            bp.enabled = True

        # doit
        info("Setup is complete. continuing...")
        gdb.execute("continue")

        # clean up
        info("kmalloc-tracer is complete, cleaning up...")
        for bp in breakpoints:
            bp.delete()
        return


class KmallocAllocatedBy_UserlandHardwareBreakpoint(gdb.Breakpoint):
    """Breakpoint to userland `sleep` process for KmallocAllocatedByCommand."""
    def __init__(self, loc):
        super().__init__("*{:#x}".format(loc), gdb.BP_HARDWARE_BREAKPOINT, internal=False)
        self.silent = True
        return

    def stop(self):
        return True # stop


@register_command
class KmallocAllocatedByCommand(GenericCommand):
    """Call a predefined set of system calls and print structures allocated by kmalloc or freed by kfree (only x64)."""
    _cmdline_ = "kmalloc-allocated-by"
    _category_ = "08-f. Qemu-system Cooperation - Linux Dynamic Inspection"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--filter", default=[], help="filter specified name (e.g.: kmalloc-XX)")
    parser.add_argument("--print-null", action="store_true", help="display free(NULL).")
    parser.add_argument("-t", "--backtrace", action="store_true", help="display backtrace.")
    parser.add_argument("-d", "--dump-chunk", action="store_true", help="dump the first 0x40 bytes of each chunk.")
    parser.add_argument("-v", "--verbose", action="store_true", help="print meta information.")
    _syntax_ = parser.format_help()

    _example_ = "{:s}         # simple output\n".format(_cmdline_)
    _example_ += "{:s} -dtv    # useful output".format(_cmdline_)

    _note_ = "Disable `-enable-kvm` option for qemu-system (#PF may occur).\n"
    _note_ += "Append `tsc=unstable` option for kernel cmdline.\n"
    _note_ += "This command needs CONFIG_RANDSTRUCT=n."

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.initialized = False
        self.allocator = None
        return

    def setup_syscall(self, syscall_name, args):
        gdb.execute("set $pc-={:#x}".format(len(current_arch.syscall_insn)), to_string=True)
        nr = self.syscall_table[syscall_name]
        gdb.execute("set $rax={:#x}".format(nr), to_string=True)
        sp = current_arch.sp
        for reg, arg in zip(current_arch.syscall_parameters, args):
            if arg is None:
                break
            if isinstance(arg, str):
                arg = String.str2bytes(arg)
            if isinstance(arg, bytes):
                write_memory(sp, arg)
                gdb.execute("set {:s}={:#x}".format(reg, sp), to_string=True)
                sp = AddressUtil.align_address_to_size(sp + len(arg), current_arch.ptrsize * 2)
            else:
                gdb.execute("set {:s}={:#x}".format(reg, arg), to_string=True)
        self.tested_syscall.add(syscall_name)
        return

    def dump_untested_syscall(self):
        valid_syscall = []
        for line in self.syscall_table_view_ret.splitlines():
            tag, _, valid, name, *__ = Color.remove_color(line).split()
            if tag != "x86_64":
                continue
            if valid != "valid":
                continue
            valid_syscall.append(name)

        invalid_syscall = []
        tested_syscall = []
        untested_syscall = []
        skipped_syscall = []
        # sort by index and translate from set to list
        for name, _nr in self.syscall_table.items():
            if name not in valid_syscall:
                invalid_syscall.append(name)
            elif name in self.tested_syscall:
                tested_syscall.append(name)
            elif name in self.scheduled_syscall:
                skipped_syscall.append(name)
            elif name in self.skipped_syscall:
                skipped_syscall.append(name)
            else:
                untested_syscall.append(name)

        gef_print(titlify("Tested syscall"))
        gef_print(", ".join(tested_syscall))

        gef_print(titlify("Untested syscall"))
        gef_print(", ".join(untested_syscall))

        gef_print(titlify("Skipped syscall"))
        gef_print(", ".join(skipped_syscall))

        gef_print(titlify("Invalid (Unsupported) syscall"))
        gef_print(", ".join(invalid_syscall))
        return

    def test_syscall(self, breakpoints):

        def u2i(x):
            x = struct.pack("<Q", ret & 0xffffffffffffffff)
            return struct.unpack("<q", x)[0]

        def gen_testcase():
            # It is implemented with a generator because it requires delayed execution in order to use the previous result.

            nonlocal ret_history

            yield "msgget -> msgsnd -> msgrcv -> msgctl"
            yield ("msqid = msgget(IPC_PRIVATE, IPC_CREAT|0666)", "msgget", [0, 0o1000 | 0o666])
            msgsize = 0x100
            msg = p64(1) + b"A" * msgsize
            if u2i(ret_history[-1]) >= 0:
                msqid = ret_history[-1]
                yield ("msgsnd(msqid, &msg, msgsize, 0)", "msgsnd", [msqid, msg, msgsize, 0])
                yield ("msgrcv(msqid, &msg, msgsize, 0, 0)", "msgrcv", [msqid, msg, msgsize, 0, 0])
                yield ("msgctl(msqid, IPC_RMID, 0)", "msgctl", [msqid, 0, 0])

            yield "shmget -> shmat -> shmdt -> shmctl"
            yield ("shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT|0666)", "shmget", [0, 0x400, 0o1000 | 0o666])
            if u2i(ret_history[-1]) >= 0:
                shmid = ret_history[-1]
                yield ("addr = shmat(shmid, NULL, 0)", "shmat", [shmid, 0, 0])
                addr = ret_history[-1]
                yield ("shmdt(addr)", "shmdt", [addr])
                yield ("shmctl(shmid, IPC_RMID, 0)", "shmctl", [shmid, 0, 0])

            yield "semget -> semop -> semctl"
            yield ("semid = semget(IPC_PRIVATE, 1, IPC_CREAT|0666)", "semget", [0, 1, 0o1000 | 0o666])
            if u2i(ret_history[-1]) >= 0:
                semid = ret_history[-1]
                sembuf = p16(0)  # sem_num
                sembuf += p16(2) # sem_op
                sembuf += p16(0) # sem_flg
                yield ("semop(semid, &sembuf, 1)", "semop", [semid, sembuf, 1])
                self.skipped_syscall.add("semtimedop")
                yield ("semctl(semid, 0, IPC_RMID)", "semctl", [semid, 0, 0])

            yield "mq_open -> mq_timedsend -> mq_timedreceive -> mq_notify -> mq_getsetattr -> mq_unlink -> close"
            MQ_NAME = "mq_test\0"
            attr = p64(0o4000) # mq_flags: O_NONBLOCK
            attr += p64(10)    # mq_maxmsg
            attr += p64(0x100) # mq_msgsize
            attr += p64(0)     # mq_curmsgs
            attr += p64(0) * 4 # __reserved[4]
            yield ('fd = mq_open("mq_test", O_RDWR|O_CREAT, 0700, &attr)', "mq_open", [MQ_NAME, 0o2 | 0o100, 0o700, attr])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                msg = "A" * 0x100
                yield ("mq_timedsend(fd, &msg, sizeof(msg), 0, NULL)", "mq_timedsend", [fd, msg, len(msg), 0, 0])
                buf = "\0" * 0x100
                prio = p32(0)
                timeout = p64(0)  # tv_sec
                timeout += p64(0) # tv_nsec
                yield ("mq_timedreceive(fd, &buf, sizeof(buf), &prio, &timeout)", "mq_timedreceive", [fd, buf, len(buf), prio, timeout])
                sigevent = p32(0)   # sigev_notify: SIGEV_SIGNAL
                sigevent += p32(10) # sigev_signo: SIGUSR1
                sigevent += p64(0)  # sigev_value
                sigevent += p64(0)  # sigev_notify_function
                sigevent += p64(0)  # sigev_notify_attributes
                sigevent += p64(0)  # sigev_notify_thread_id
                yield ("mq_notify(fd, &sigevent)", "mq_notify", [fd, sigevent])
                attr = p64(0)      # mq_flags
                attr += p64(0)     # mq_maxmsg
                attr += p64(0)     # mq_msgsize
                attr += p64(0)     # mq_curmsgs
                attr += p64(0) * 4 # __reserved[4]
                yield ("mq_getsetattr(fd, NULL, &attr)", "mq_getsetattr", [fd, 0, attr])
                yield ('mq_unlink("mq_test")', "mq_unlink", [MQ_NAME])
                yield ("close(fd)", "close", [fd])

            yield "signalfd4 -> close"
            mask = "\0" * 8
            yield ("fd = signalfd4(-1, &mask, sizeof(mask), 0)", "signalfd4", [-1, mask, len(mask), 0])
            self.skipped_syscall.add("signalfd")
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                yield ("close(fd)", "close", [fd])

            yield "setitimer -> getitimer"
            new_value = p64(0)  # it_interval.tv_sec
            new_value += p64(0) # it_interval.tv_nsec
            new_value += p64(0) # it_value.tv_sec
            new_value += p64(0) # it_value.tv_nsec
            old_value = p64(0)  # it_interval.tv_sec
            old_value += p64(0) # it_interval.tv_nsec
            old_value += p64(0) # it_value.tv_sec
            old_value += p64(0) # it_value.tv_nsec
            yield ("setitimer(ITIMER_REAL, &new_value, &old_value)", "setitimer", [0, new_value, old_value])
            curr_value = p64(0)  # it_interval.tv_sec
            curr_value += p64(0) # it_interval.tv_nsec
            curr_value += p64(0) # it_value.tv_sec
            curr_value += p64(0) # it_value.tv_nsec
            yield ("getitimer(ITIMER_REAL, &curr_value)", "getitimer", [0, curr_value])

            yield "timerfd_create -> timerfd_settime -> timerfd_gettime -> close"
            yield ("fd = timerfd_create(CLOCK_MONOTONIC, 0)", "timerfd_create", [1, 0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                new_value = p64(0)  # it_interval.tv_sec
                new_value += p64(0) # it_interval.tv_nsec
                new_value += p64(0) # it_value.tv_sec
                new_value += p64(0) # it_value.tv_nsec
                old_value = p64(0)  # it_interval.tv_sec
                old_value += p64(0) # it_interval.tv_nsec
                old_value += p64(0) # it_value.tv_sec
                old_value += p64(0) # it_value.tv_nsec
                yield ("timerfd_settime(fd, 0, &new_value, &old_value)", "timerfd_settime", [fd, 0, new_value, old_value])
                curr_value = p64(0)  # it_interval.tv_sec
                curr_value += p64(0) # it_interval.tv_nsec
                curr_value += p64(0) # it_value.tv_sec
                curr_value += p64(0) # it_value.tv_nsec
                yield ("timerfd_gettime(fd, &curr_value)", "timerfd_gettime", [fd, curr_value])
                yield ("close(fd)", "close", [fd])

            yield "timer_create -> timer_settime -> timier_gettime -> timer_getoverrun -> timer_delete"
            timerid = p64(0)
            yield ("timer_create(CLOCK_MONOTONIC, NULL, &timerid)", "timer_create", [1, 0, timerid])
            if u2i(ret_history[-1]) == 0:
                timerid = read_int_from_memory(current_arch.sp)
                new_value = p64(0)  # it_interval.tv_sec
                new_value += p64(0) # it_interval.tv_nsec
                new_value += p64(0) # it_value.tv_sec
                new_value += p64(0) # it_value.tv_nsec
                old_value = p64(0)  # it_interval.tv_sec
                old_value += p64(0) # it_interval.tv_nsec
                old_value += p64(0) # it_value.tv_sec
                old_value += p64(0) # it_value.tv_nsec
                yield ("timer_settime(timerid, 0, &new_value, &old_value)", "timer_settime", [timerid, 0, new_value, old_value])
                curr_value = p64(0)  # it_interval.tv_sec
                curr_value += p64(0) # it_interval.tv_nsec
                curr_value += p64(0) # it_value.tv_sec
                curr_value += p64(0) # it_value.tv_nsec
                yield ("timer_gettime(timerid, &curr_value)", "timer_gettime", [timerid, curr_value])
                yield ("timer_getoverrun(timerid)", "timer_getoverrun", [timerid])
                yield ("timer_delete(timerid)", "timer_delete", [timerid])

            yield "epoll_create1 -> epoll_ctl -> epoll_wait -> close"
            yield ("epfd = epoll_create1(0)", "epoll_create1", [0])
            self.skipped_syscall.add("epoll_create")
            if u2i(ret_history[-1]) >= 0:
                epfd = ret_history[-1]
                event = p32(1)  # events: EPOLLIN
                event += p64(0) # data
                yield ("epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event)", "epoll_ctl", [epfd, 1, 0, event])
                yield ("epoll_wait(epfd, &events, 1, 0)", "epoll_wait", [epfd, event, 1, 0])
                self.skipped_syscall.add("epoll_pwait")
                self.skipped_syscall.add("epoll_pwait2")
                yield ("close(epfd)", "close", [epfd])

            yield "eventfd2 -> close"
            yield ("fd = eventfd2(0, 0)", "eventfd2", [0, 0])
            self.skipped_syscall.add("eventfd")
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                yield ("close(fd)", "close", [fd])

            yield "perf_event_open (need kernel.perf_event_paranoid <= 2) -> close"
            attr = p32(1)      # type: PERF_TYPE_SOFTWARE
            attr += p32(0x80)  # size: sizeof(attr)
            attr += p64(9)     # config: PERF_COUNT_SW_DUMMY
            attr += p64(0)     # sample_period or sample_freq
            attr += p64(0)     # sample_type
            attr += p64(0)     # read_format
            flags = 1 << 5     # execlude_kernel=1
            flags |= 1 << 6    # execlude_hv=1
            flags |= 1 << 8    # mmap=1
            flags |= 1 << 17   # mmap_data=1
            attr += p64(flags) # flags
            attr += p32(0)     # wakeup_events or wakeup_watermalk
            attr += p32(0)     # bp_type
            attr += p64(0)     # bp_addr or kprobe_func or uprobe_path or config1
            attr += p64(0)     # bp_len or kprobe_addr or probe_offset or config2
            attr += p64(0)     # branch_sample_type
            attr += p64(0)     # sample_regs_user
            attr += p32(0)     # sample_stack_user
            attr += p32(0)     # clockid
            attr += p64(0)     # sample_regs_intr
            attr += p32(0)     # aux_watermark
            attr += p16(0)     # sample_max_stack
            attr += p16(0)     # __reserved_2
            attr += p32(0)     # aux_sample_size
            attr += p32(0)     # __reserved_3
            attr += p64(0)     # sig_data
            attr += p64(0)     # config3
            yield ("fd = perf_event_open(&attr, 0, -1, -1, 0)", "perf_event_open", [attr, 0, -1, -1, 0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                yield ("close(fd)", "close", [fd])

            yield "bpf (need kernel.unprivileged_bpf_disabled == 0) -> close"
            attr = p32(2)     # map_type: BPF_MAP_TYPE_ARRAY
            attr += p32(4)    # key_size
            attr += p32(0x10) # value_size
            attr += p32(0x10) # max_entries
            yield ("bpf(BPF_MAP_CREATE, &attr, sizeof(attr))", "bpf", [0, attr, len(attr)])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                yield ("close(fd)", "close", [fd])

            yield "mmap -> mprotect -> mremap -> msync -> madvise -> munmap"
            size = gef_getpagesize()
            yield ("addr = mmap(NULL, 0x1000, RWX, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)", "mmap", [0, size, 7, 0x20 | 0x2, -1, 0])
            if u2i(ret_history[-1]) >= 0:
                addr = ret_history[-1]
                yield ("mprotect(addr, 0x1000, R--)", "mprotect", [addr, size, 1])
                size2 = size * 2
                yield ("addr2 = mremap(addr, 0x1000, 0x2000, MREMAP_MAYMOVE)", "mremap", [addr, size, size2, 1])
                if u2i(ret_history[-1]) >= 0:
                    addr2 = ret_history[-1]
                    yield ("msync(addr2, 0x2000, MS_SYNC)", "msync", [addr2, size2, 4])
                    yield ("madvise(addr2, 0x2000, MADV_DONTNEED)", "madvise", [addr2, size2, 4])
                    self.skipped_syscall.add("process_madvise")
                    yield ("munmap(addr2, 0x2000)", "munmap", [addr2, size2])

            yield "mmap -> mincore -> mbind -> move_pages -> migrate_pages -> munmap"
            size = gef_getpagesize()
            yield ("addr = mmap(NULL, 0x1000, RWX, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)", "mmap", [0, size, 7, 0x20 | 0x2, -1, 0])
            if u2i(ret_history[-1]) >= 0:
                addr = ret_history[-1]
                vec = "\0" * 0x100
                yield ("mincore(addr, 0x1000, &vec)", "mincore", [addr, size, vec])
                yield ("mbind(addr, 0x1000, MPOL_DEFAULT, NULL, 0, 0)", "mbind", [addr, size, 0, 0, 0, 0])
                pages = p64(addr)
                status = p64(0)
                yield ("move_pages(0, 1, &pages, NULL, &status, 0)", "move_pages", [0, 1, pages, 0, status, 0])
                maxnode = 8
                old_nodes = "\x02"
                new_nodes = "\x01"
                yield ("migrate_pages(0, 8, old_nodes, new_nodes)", "migrate_pages", [0, maxnode, old_nodes, new_nodes])
                yield ("munmap(addr, 0x1000)", "munmap", [addr, size])

            yield "brk -> userfaultfd -> ioctl -> close"
            yield ("addr = brk(0)", "brk", [0])
            last_page = ret_history[-1] - gef_getpagesize()
            yield ("fd = userfaultfd(O_CLOEXEC|O_NONBLOCK)", "userfaultfd", [0o2000000 | 0o4000])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                uffdio_api = p64(0xAA) # api: UFFD_API
                uffdio_api += p64(0)   # features
                uffdio_api += p64(0)   # ioctls
                yield ("ioctl(fd, UFFDIO_API, &uffdio_api)", "ioctl", [fd, 0xc018aa3f, uffdio_api])
                uffdio_register = p64(last_page)          # range.start
                uffdio_register += p64(gef_getpagesize()) # range.len
                uffdio_register += p64(1)                 # mode: UFFDIO_REGISTER_MODE_MISSING
                uffdio_register += p64(0)                 # ioctls
                yield ("ioctl(fd, UFFDIO_REGISTER, &uffdio_register)", "ioctl", [fd, 0xc020aa00, uffdio_register])
                yield ("ioctl(fd, UFFDIO_UNREGISTER, &uffdio_register)", "ioctl", [fd, 0x8010aa01, uffdio_register])
                yield ("close(fd)", "close", [fd])

            yield "mlockall -> munlockall"
            yield ("mlockall(MCL_CURRENT)", "mlockall", [1])
            self.skipped_syscall.add("mlock")
            self.skipped_syscall.add("mlock2")
            yield ("munlockall()", "munlockall", [])
            self.skipped_syscall.add("munlock")

            yield "get_robust_list -> set_robust_list"
            head_ptr = p64(0)
            len_ptr = p64(0)
            yield ("get_robust_list(0, &head_ptr, &len_ptr)", "get_robust_list", [0, head_ptr, len_ptr])
            if u2i(ret_history[-1]) >= 0:
                head = read_int_from_memory(current_arch.sp)
                len_ = read_int_from_memory(current_arch.sp + 0x10)
                yield ("set_robust_list(head, len)", "set_robust_list", [head, len_])

            yield "prctl -> arch_prctl -> set_tid_address"
            buf = p32(0)
            yield ("prctl(PR_GET_PDEATHSIG, &buf)", "prctl", [2, buf])
            yield ("prctl(PR_GET_DUMPABLE)", "prctl", [3])
            yield ("prctl(PR_GET_KEEPCAPS)", "prctl", [7])
            yield ("prctl(PR_GET_TIMING)", "prctl", [13])
            buf = "\0" * 16
            yield ("prctl(PR_GET_NAME, &buf)", "prctl", [16, buf])
            yield ("prctl(PR_GET_SECCOMP)", "prctl", [21])
            yield ("prctl(PR_CAPBSET_READ, CAP_CHOWN)", "prctl", [23, 0])
            buf = p32(0)
            yield ("prctl(PR_GET_TSC, &buf)", "prctl", [25, buf])
            yield ("prctl(PR_GET_SECUREBITS)", "prctl", [27])
            yield ("prctl(PR_GET_TIMERSLACK)", "prctl", [30])
            yield ("prctl(PR_TASK_PERF_EVENTS_DISABLE)", "prctl", [31])
            yield ("prctl(PR_MCE_KILL_GET, 0, 0, 0, 0)", "prctl", [34, 0, 0, 0, 0])
            buf = p32(0)
            yield ("prctl(PR_GET_CHILD_SUBREAPER, &buf)", "prctl", [37, buf])
            yield ("prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0)", "prctl", [39, 0, 0, 0, 0])
            yield ("prctl(PR_GET_TID_ADDRESS)", "prctl", [40, buf])
            yield ("prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0)", "prctl", [42, 0, 0, 0, 0])
            yield ("arch_prctl(ARCH_GET_CPUID)", "arch_prctl", [0x1011])
            buf = p64(0)
            yield ("arch_prctl(ARCH_GET_GS, &buf)", "arch_prctl", [0x1001, buf])
            buf = p64(0)
            yield ("arch_prctl(ARCH_GET_FS, &buf)", "arch_prctl", [0x1003, buf])
            fsbase = ret_history[-1]
            yield ("set_tid_address(fsbase)", "set_tid_address", [fsbase])

            yield "futex"
            uaddr = p64(0)
            yield ("futex(&uaddr, FUTEX_WAKE, 1, &timeout, 0, 0)", "futex", [uaddr, 1, 1, 0, 0, 0])

            yield "time"
            yield ("time(NULL)", "time", [0])

            yield "times"
            buf = p64(0)  # tms_utime
            buf += p64(0) # tms_stime
            buf += p64(0) # tms_cutime
            buf += p64(0) # tms_cstime
            yield ("times(&buf)", "times", [buf])

            yield "gettimeofday"
            tv = p64(0)  # tv_sec
            tv += p64(0) # tv_usec
            tz = p32(0)  # tz_minuteswest
            tz += p32(0) # tz_dsttime
            yield ("gettimeofday(&tv, &tz)", "gettimeofday", [tv, tz])

            yield "nanosleep"
            req = p64(0)     # tv_sec
            req += p64(1000) # tv_nsec
            rem = p64(0)     # tv_sec
            rem += p64(0)    # tv_nsec
            yield ("nanosleep(&req, &rem)", "nanosleep", [req, rem])
            self.skipped_syscall.add("clock_nanosleep")

            yield "clock_getres -> clock_gettime"
            res = p64(0)  # tv_sec
            res += p64(0) # tv_nsec
            yield ("clock_getres(CLOCK_PROCESS_CPUTIME_ID, &res)", "clock_getres", [2, res])
            tp = p64(0)  # tv_sec
            tp += p64(0) # tv_nsec
            yield ("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp)", "clock_gettime", [2, tp])

            yield "adjtimex"
            buf = p64(0)  # modes
            buf += p64(0) # offset
            buf += p64(0) # freq
            buf += p64(0) # maxerror
            buf += p64(0) # esterror
            buf += p64(0) # status
            buf += p64(0) # constant
            buf += p64(0) # precision
            buf += p64(0) # tolerance
            buf += p64(0) # time.tv_sec
            buf += p64(0) # time.tv_usec
            buf += p64(0) # tick
            buf += p64(0) # ppsfreq
            buf += p64(0) # jitter
            buf += p64(0) # shift
            buf += p64(0) # stabil
            buf += p64(0) # jitcnt
            buf += p64(0) # calcnt
            buf += p64(0) # errcnt
            buf += p64(0) # stbcnt
            buf += p64(0) # tai
            yield ("adjtimex(&buf)", "adjtimex", [buf])
            self.skipped_syscall.add("clock_adjtime")

            yield "membarrier"
            yield ("membarrier(MEMBARRIER_CMD_QUERY, 0, 0)", "membarrier", [0, 0, 0])

            yield "getcwd"
            buf = "\0" * 0x100
            yield ("getcwd(&buf, sizeof(buf))", "getcwd", [buf, len(buf)])

            yield "uname"
            buf = "\0" * 0x400
            yield ("uname(&buf)", "uname", [buf])

            yield "getrandom"
            buf = "\0" * 0x100
            yield ("getrandom(&buf, sizeof(buf), 0)", "getrandom", [buf, len(buf), 0])

            yield "getrlimit -> setrlimit"
            rlim = p64(0)  # rlim_cur
            rlim += p64(0) # rlim_max
            yield ("getrlimit(RLIMIT_STACK, &rlim, sizeof(rlim))", "getrlimit", [3, rlim, len(rlim)])
            rlim = read_memory(current_arch.sp, 16)
            yield ("setrlimit(RLIMIT_STACK, &rlim, sizeof(rlim))", "setrlimit", [3, rlim, len(rlim)])
            self.skipped_syscall.add("prlimit64")

            yield "sched_yield"
            yield ("sched_yield()", "sched_yield", [])

            yield "sched_getscheduler -> sched_setscheduler"
            yield ("sched_getscheduler(0)", "sched_getscheduler", [0])
            param = p32(0)
            yield ("sched_setscheduler(0, SCHED_OTHER, &param)", "sched_setscheduler", [0, 0, param])

            yield "sched_getparam -> sched_setparam"
            param = p32(0)
            yield ("sched_getparam(0, &param)", "sched_getparam", [0, param])
            yield ("sched_setparam(0, &param)", "sched_setparam", [0, param])

            yield "sched_getaffinity -> sched_setaffinity"
            mask = "\0" * 0x80
            yield ("sched_getaffinity(0, sizeof(mask), &mask)", "sched_getaffinity", [0, len(mask), mask])
            mask = read_memory(current_arch.sp, 0x80)
            yield ("sched_setaffinity(0, sizeof(mask), &mask)", "sched_setaffinity", [0, len(mask), mask])

            yield "sched_get_priority_max -> sched_get_priority_min"
            yield ("sched_get_priority_max(SCHED_OTHER)", "sched_get_priority_max", [0])
            yield ("sched_get_priority_min(SCHED_OTHER)", "sched_get_priority_min", [0])

            yield "sched_rr_get_interval"
            tp = p64(0)  # tv_sec
            tp += p64(0) # tv_nsec
            yield ("sched_rr_get_interval(0, &tp)", "sched_rr_get_interval", [0, tp])

            yield "sched_getattr -> sched_setattr"
            attr = p32(8 * 6) # size
            attr += p32(0) # sched_policy: SCHED_OTHER
            attr += p64(0) # sched_flags
            attr += p32(0) # sched_nice
            attr += p32(0) # sched_priority
            attr += p64(0) # sched_runtime
            attr += p64(0) # sched_deadline
            attr += p64(0) # sched_period
            yield ("sched_getattr(0, &attr, sizeof(attr), 0)", "sched_getattr", [0, attr, len(attr), 0])
            # sched_setattr must be called before setpriority, or failed.
            yield ("sched_setattr(0, &attr, 0)", "sched_setattr", [0, attr, 0])

            yield "getpriority -> setpriority"
            yield ("getpriority(PRIO_PROCESS, 0)", "getpriority", [0, 0])
            yield ("setpriority(PRIO_PROCESS, 0, 1)", "setpriority", [0, 0, 1])

            yield "ioprio_get -> ioprio_set"
            yield ("ioprio_get(IOPRIO_WHO_PROCESS, 0)", "ioprio_get", [1, 0])
            yield ("ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(2, 0))", "ioprio_set", [1, 0, 0x4000])

            yield "getrusage"
            buf = p64(0)  # ru_utime.tv_sec
            buf += p64(0) # ru_utime.tv_usec
            buf += p64(0) # ru_stime.tv_sec
            buf += p64(0) # ru_stime.tv_usec
            buf += p64(0) # ru_maxrss
            buf += p64(0) # ru_ixrss
            buf += p64(0) # ru_idrss
            buf += p64(0) # ru_isrss
            buf += p64(0) # ru_minflt
            buf += p64(0) # ru_majflt
            buf += p64(0) # ru_nswap
            buf += p64(0) # ru_inblock
            buf += p64(0) # ru_oublock
            buf += p64(0) # ru_msgsnd
            buf += p64(0) # ru_msgrcv
            buf += p64(0) # ru_nsignals
            buf += p64(0) # ru_nvcsw
            buf += p64(0) # ru*nivcsw
            yield ("getrusage(RUSAGE_SELF, &buf)", "getrusage", [0, buf])

            yield "personality"
            yield ("personality(0xffffffff)", "personality", [0xffffffff])

            yield "get_mempolicy -> set_mempolicy"
            nodemask = p64(0)
            yield ("get_mempolicy(0, &nodemask, 8, 0, MPOL_F_MEMS_ALLOWED)", "get_mempolicy", [0, nodemask, 8, 0, 4])
            yield ("set_mempolicy(MPOL_DEFAULT, NULL, 8)", "set_mempolicy", [0, 0, 8])

            yield "getcpu"
            cpu = p32(0)
            node = p32(0)
            yield ("getcpu(&cpu, &node, NULL)", "getcpu", [cpu, node, 0])

            yield "sysinfo"
            buf = p64(0)      # uptime
            buf += p64(0) * 3 # loads[3]
            buf += p64(0)     # totalram
            buf += p64(0)     # freeram
            buf += p64(0)     # sharedram
            buf += p64(0)     # bufferram
            buf += p64(0)     # totalswap
            buf += p64(0)     # freeswap
            buf += p16(0)     # procs
            buf += p8(0) * 22 # padding
            yield ("sysinfo(&buf)", "sysinfo", [buf])

            yield "sysfs"
            buf = "\0" * 0x100
            yield ("sysfs(2, 0, &buf)", "sysfs", [2, 0, buf])

            yield "sigaltstack"
            oss = p64(0)  # ss_sp
            oss += p32(0) # ss_flags
            oss += p32(0) # padding
            oss += p64(0) # ss_size
            yield ("sigaltstack(NULL, &oss)", "sigaltstack", [0, oss])

            yield "rt_sigprocmask -> rt_sigpending"
            oldset = "\0" * 0x100
            sigsetsize = 8
            yield ("rt_sigprocmask(0, NULL, &oldset, sigsetsize)", "rt_sigprocmask", [0, 0, oldset, sigsetsize])
            set_ = "\0" * 0x100
            yield ("rt_sigpending(&set)", "rt_sigpending", [set_])

            yield "getpid -> getppid -> getsid -> gettid -> getpgid -> setpgid -> getpgrp -> kcmp"
            yield ("pid = getpid()", "getpid", [])
            pid = ret_history[-1]
            yield ("getppid()", "getppid", [])
            yield ("getsid(pid)", "getsid", [pid])
            yield ("gettid()", "gettid", [])
            tid = ret_history[-1]
            yield ("pgid = getpgid(pid)", "getpgid", [pid])
            pgid = ret_history[-1]
            yield ("setpgid(pid, pgid)", "setpgid", [pid, pgid])
            yield ("getpgrp()", "getpgrp", [])
            yield ("kcmp(pid, pid, KCMP_FS, 0, 0)", "kcmp", [pid, pid, 3, 0, 0])

            yield "getuid -> setuid -> setreuid -> setfsuid -> geteuid -> getresuid -> setresuid"
            yield ("uid = getuid()", "getuid", [])
            uid = ret_history[-1]
            yield ("setuid(uid)", "setuid", [uid])
            yield ("setreuid(uid, uid)", "setreuid", [uid, uid])
            yield ("setfsuid(uid)", "setfsuid", [uid])
            yield ("geteuid()", "geteuid", [])
            ruid = euid = suid = p32(0)
            yield ("getresuid(&ruid, &euid, &suid)", "getresuid", [ruid, euid, suid])
            yield ("setresuid(uid, uid, uid)", "setresuid", [uid, uid, uid])

            yield "getgid -> setgid -> setregid -> setfsgid -> getegid -> getresgid -> setresgid -> getgroups"
            yield ("gid = getgid()", "getgid", [])
            gid = ret_history[-1]
            yield ("setgid(gid)", "setgid", [gid])
            yield ("setregid(gid, gid)", "setregid", [gid, gid])
            yield ("setfsgid(uid)", "setfsgid", [gid])
            yield ("getegid()", "getegid", [])
            rgid = egid = sgid = p32(0)
            yield ("getresgid(&rgid, &egid, &sgid)", "getresgid", [rgid, egid, sgid])
            yield ("setresgid(gid, gid, gid)", "setresgid", [gid, gid, gid])
            yield ("getgroups(0, NULL)", "getgroups", [0, 0])

            yield "rt_sigaction -> alarm -> kill -> tkill -> rt_sigtimedwait"
            act = p64(1)    # sa_handler: SIG_IGN
            act += p64(0)   # sa_flags
            act += p64(0)   # sa_restorer
            act += p64(0xe) # sa_mask: SIGALRM
            oldact = p64(0)  # sa_handler
            oldact += p64(0) # sa_flags
            oldact += p64(0) # sa_restorer
            oldact += p64(0) # sa_mask: SIGALRM
            sigsetsize = 8
            yield ("rt_sigaction(SIGALRM, &act, &oldact, sigsetsize)", "rt_sigaction", [14, act, oldact, sigsetsize])
            yield ("alarm(1000)", "alarm", [1000])
            yield ("kill(pid, SIGALRM)", "kill", [pid, 14])
            yield ("tkill(tid, SIGALRM)", "kill", [tid, 14])
            self.skipped_syscall.add("tgkill")
            self.skipped_syscall.add("rt_sigqueueinfo")
            self.skipped_syscall.add("rt_tgsigqueueinfo")
            set_ = "\0" * 0x100
            info = p32(0)  # si_signo
            info += p32(0) # si_code
            info += p64(0) # si_value
            info += p32(0) # si_errno
            info += p32(0) # si_pid
            info += p32(0) # si_uid
            info += p32(0) # padding
            info += p64(0) # si_addr
            info += p32(0) # si_status
            info += p32(0) # si_band
            timeout = p64(0)  # tv_sec
            timeout += p64(0) # tv_nsec
            sigsetsize = 8
            yield ("rt_sigtimedwait(&set, &info, &timeout, sigsetsize)", "rt_sigtimedwait", [set_, info, timeout, sigsetsize])

            yield "pidfd_open -> pidfd_getfd -> pidfd_send_signal -> close"
            yield ("pfdfd = pidfd_open(pid, 0)", "pidfd_open", [pid, 0])
            if u2i(ret_history[-1]) >= 0:
                pidfd = ret_history[-1]
                yield ("fd = pidfd_getfd(pidfd, STDIN_FILENO, 0)", "pidfd_getfd", [pidfd, 0, 0])
                if u2i(ret_history[-1]) >= 0:
                    fd = ret_history[-1]
                    yield ("close(fd)", "close", [fd])
                yield ("pidfd_send_signal(pidfd, SIGALRM, NULL, 0)", "pidfd_send_signal", [pidfd, 14, 0, 0])
                yield ("close(pidfd)", "close", [pidfd])

            yield "capget -> capset"
            hdrp = p32(0x20080522) # version
            hdrp += p32(pid)       # pid
            datap = p32(0)  # effective
            datap += p32(0) # permitted
            datap += p32(0) # inheritable
            yield ("capget(&hdrp, &datap)", "capget", [hdrp, datap])
            datap = read_memory(current_arch.sp + 0x10, 4 * 3)
            yield ("capset(&hdrp, &datap)", "capset", [hdrp, datap])

            yield "umask"
            yield ("umask(022)", "umask", [0o022])

            yield "open -> fallocate -> write -> fdatasync -> fsync -> syncfs -> fadvise64 -> close"
            TMP_XXX = "/tmp/xxx\0"
            yield ('fd = open("/tmp/xxx", 0_WRONLY|O_CREAT, 0666)', "open", [TMP_XXX, 0o1 | 0o100, 0o666])
            self.skipped_syscall.add("creat")
            self.skipped_syscall.add("openat")
            self.skipped_syscall.add("openat2")
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                yield ("fallocate(fd, 0, 0, 0x100)", "fallocate", [fd, 0, 0, 0x100])
                buf = "A" * 4
                yield ('write(fd, "AAAA", 4)', "write", [fd, buf, len(buf)])
                self.skipped_syscall.add("writev")
                self.skipped_syscall.add("pwrite64")
                self.skipped_syscall.add("pwritev")
                self.skipped_syscall.add("pwritev2")
                self.skipped_syscall.add("process_vm_writev")
                yield ("fdatasync(fd)", "fdatasync", [fd])
                yield ("fsync(fd)", "fsync", [fd])
                yield ("syncfs(fd)", "syncfs", [fd])
                self.skipped_syscall.add("sync")
                yield ("fadvise64(fd, 0, 0x100, POSIX_FADV_DONTNEED)", "fadvise64", [fd, 0, 0x100, 4])
                yield ("close(fd)", "close", [fd])

            yield "open -> flock -> lseek -> readahead -> poll -> read -> dup -> close_range"
            yield ('fd = open("/tmp/xxx", 0_RDONLY)', "open", [TMP_XXX, 0o0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                yield ("flock(fd, LOCK_SH|LOCK_NB)", "flock", [fd, 1 | 4])
                yield ("lseek(fd, SEEK_SET, 0)", "lseek", [fd, 0, 0])
                yield ("readahead(fd, 0, 0x1000)", "readahead", [fd, 0, 0x1000])
                fds = p32(fd) # fd
                fds += p16(0) # events
                fds += p16(0) # revents
                yield ("poll(&fds, 1, 0)", "poll", [fds, 1, 0])
                self.skipped_syscall.add("ppoll")
                buf = "\0" * 4
                yield ("read(fd, &buf, 4)", "read", [fd, buf, len(buf)])
                self.skipped_syscall.add("readv")
                self.skipped_syscall.add("pread64")
                self.skipped_syscall.add("preadv")
                self.skipped_syscall.add("preadv2")
                self.skipped_syscall.add("process_vm_readv")
                yield ("fd2 = dup(fd)", "dup", [fd])
                self.skipped_syscall.add("dup2")
                self.skipped_syscall.add("dup3")
                fd2 = ret_history[-1]
                yield ("close_range(fd, fd2, 0)", "close_range", [fd, fd2, 0])

            yield "open -> mmap -> remap_file_pages -> munmap -> close"
            yield ('fd = open("/tmp/xxx", 0_RDONLY)', "open", [TMP_XXX, 0o0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                size = gef_getpagesize()
                yield ("addr = mmap(NULL, 0x1000, R--, MAP_ANONYMOUS|MAP_SHARED, -1, 0)", "mmap", [0, size, 1, 0x20 | 0x1, fd, 0])
                if u2i(ret_history[-1]) >= 0:
                    addr = ret_history[-1]
                    yield ("remap_file_pages(addr, 0x1000, 0, 0, 0)", "remap_file_pages", [addr, size, 0, 0, 0])
                    yield ("munmap(addr, 0x1000)", "munmap", [addr, size])
                yield ("close(fd)", "close", [fd])

            yield "chmod -> chown"
            yield ('chmod("/tmp/xxx", 0o664)', "chmod", [TMP_XXX, 0o664])
            self.skipped_syscall.add("fchmod")
            self.skipped_syscall.add("fchmodat")
            yield ('chown("/tmp/xxx", -1, -1)', "chown", [TMP_XXX, -1, -1])
            self.skipped_syscall.add("fchown")
            self.skipped_syscall.add("lchown")
            self.skipped_syscall.add("fchownat")

            yield "open -> pipe -> sendfile -> splice -> select -> vmsplice -> close_range -> close"
            yield ('fd = open("/tmp/xxx", 0_RDONLY)', "open", [TMP_XXX, 0o0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                pipefd_array = p32(0) * 2 # pipefd[2]
                yield ("pipe(&pipefd[])", "pipe", [pipefd_array])
                self.skipped_syscall.add("pipe2")
                if u2i(ret_history[-1]) >= 0:
                    pipefd0 = u32(read_memory(current_arch.sp, 4))
                    pipefd1 = u32(read_memory(current_arch.sp + 4, 4))
                    offset = p64(0)
                    yield ("sendfile(pipefd[1], fd, &offset, 4)", "sendfile", [pipefd1, fd, offset, 4])
                    off_in = p64(0)
                    yield ("splice(fd, &off_in, pipefd[1], NULL, 4, 0)", "splice", [fd, off_in, pipefd1, 0, 4, 0])
                    readfds = [0] * 1024
                    readfds[pipefd0] = 1
                    readfds = slicer("".join([str(x) for x in readfds]), 64)
                    readfds = b"".join([p64(int(x[::-1], 2)) for x in readfds])
                    nfds = pipefd0 + 1
                    yield ("select(nfds, readfds, NULL, NULL, NULL)", "select", [nfds, readfds, 0, 0, 0])
                    self.skipped_syscall.add("pselect6")
                    iov = p64(current_arch.sp + 0x10) # iov_base
                    iov += p64(0x100)                 # iov_len
                    yield ("vmsplice(pipefd[0], &iov, 1, 0)", "vmsplice", [pipefd0, iov, 1, 0])
                    yield ("close_range(pipefd[0], pipefd[1], 0)", "close_range", [pipefd0, pipefd1, 0])
                yield ("close(fd)", "close", [fd])

            yield "pipe -> pipe -> tee -> close_range"
            pipefd_array = p32(0) * 2 # pipefd[2]
            yield ("pipe(&pipefd[])", "pipe", [pipefd_array])
            pipefd0 = u32(read_memory(current_arch.sp, 4))
            _pipefd1 = u32(read_memory(current_arch.sp + 4, 4))
            yield ("pipe(&pipefd[])", "pipe", [pipefd_array])
            _pipefd2 = u32(read_memory(current_arch.sp, 4))
            pipefd3 = u32(read_memory(current_arch.sp + 4, 4))
            yield ("tee(pipefd[0], pipefd[3], 0", "tee", [pipefd0, pipefd3])
            yield ("close_range(pipefd[0], pipefd[3], 0)", "close_range", [pipefd0, pipefd3, 0])

            yield "mknod -> unlink"
            TMP_PIPE = "/tmp/pipe\0"
            yield ('mknod("/tmp/pipe", S_IFIFO|0644, 0)', "mknod", [TMP_PIPE, 0o10000 | 0o644, 0])
            self.skipped_syscall.add("mknodat")
            if u2i(ret_history[-1]) >= 0:
                yield ('unlink("/tmp/pipe")', "unlink", [TMP_PIPE])

            yield "open -> sync_file_range -> copy_file_range -> close -> unlink -> close"
            TMP_XXX2 = "/tmp/xxx2\0"
            yield ('fd_in = open("/tmp/xxx", 0_RDONLY)', "open", [TMP_XXX, 0o0])
            if u2i(ret_history[-1]) >= 0:
                fd_in = ret_history[-1]
                yield ('fd_out = open("/tmp/xxx2", 0_WRONLY|O_CREAT, 0666)', "open", [TMP_XXX2, 0o1 | 0o100, 0o666])
                if u2i(ret_history[-1]) >= 0:
                    fd_out = ret_history[-1]
                    yield ("sync_file_range(fd_out, 0, 4, SYNC_FILE_RANGE_WAIT_AFTER)", "sync_file_range", [fd_out, 0, 4, 4])
                    yield ("copy_file_range(fd_in, 0, fd_out, 0, 4, 0)", "copy_file_range", [fd_in, 0, fd_out, 0, 4, 0])
                    yield ("close(fd_out)", "close", [fd_out])
                    yield ('unlink("/tmp/xxx2")', "unlink", [TMP_XXX2])
                yield ("close(fd_in)", "close", [fd_in])

            yield "access -> utime -> stat -> statx -> truncate"
            yield ('access("/tmp/xxx", F_OK)', "access", [TMP_XXX, 0])
            self.skipped_syscall.add("faccessat")
            self.skipped_syscall.add("faccessat2")
            if u2i(ret_history[-1]) >= 0:
                yield ('utime("/tmp/xxx", NULL)', "utime", [TMP_XXX, 0])
                self.skipped_syscall.add("utimes")
                self.skipped_syscall.add("futimesat")
                self.skipped_syscall.add("utimensat")
                buf = p64(0)      # st_dev
                buf += p64(0)     # st_ino
                buf += p64(0)     # st_nlink
                buf += p32(0)     # st_mode
                buf += p32(0)     # st_uid
                buf += p32(0)     # st_gid
                buf += p32(0)     # __pad0
                buf += p64(0)     # st_rdev
                buf += p64(0)     # st_size
                buf += p64(0)     # st_blksize
                buf += p64(0)     # st_blocks
                buf += p64(0)     # st_atim.tv_sec
                buf += p64(0)     # st_atim.tv_nsec
                buf += p64(0)     # st_mtim.tv_sec
                buf += p64(0)     # st_mtim.tv_nsec
                buf += p64(0)     # st_ctim.tv_sec
                buf += p64(0)     # st_ctim.tv_nsec
                buf += p64(0) * 3 # __glibc_reserved[3]
                yield ('stat("/tmp/xxx", &buf)', "stat", [TMP_XXX, buf])
                self.skipped_syscall.add("fstat")
                self.skipped_syscall.add("lstat")
                self.skipped_syscall.add("newfstatat")
                statxbuf = p32(0)  # stx_mask
                statxbuf += p32(0) # stx_blksize
                statxbuf += p64(0) # stx_attributes
                statxbuf += p32(0) # stx_nlink
                statxbuf += p32(0) # stx_uid
                statxbuf += p32(0) # stx_gid
                statxbuf += p16(0) # stx_mode
                statxbuf += p16(0) # padding
                statxbuf += p64(0) # stx_ino
                statxbuf += p64(0) # stx_size
                statxbuf += p64(0) # stx_blocks
                statxbuf += p64(0) # stx_attributes_mask
                statxbuf += p64(0) # stx_atime.tv_sec
                statxbuf += p32(0) # stx_atime.tv_nsec
                statxbuf += p32(0) # stx_atime.padding
                statxbuf += p64(0) # stx_btime.tv_sec
                statxbuf += p32(0) # stx_btime.tv_nsec
                statxbuf += p32(0) # stx_btime.padding
                statxbuf += p64(0) # stx_ctime.tv_sec
                statxbuf += p32(0) # stx_ctime.tv_nsec
                statxbuf += p32(0) # stx_ctime.padding
                statxbuf += p64(0) # stx_mtime.tv_sec
                statxbuf += p32(0) # stx_mtime.tv_nsec
                statxbuf += p32(0) # stx_mtime.padding
                statxbuf += p32(0) # stx_rdev_major
                statxbuf += p32(0) # stx_rdev_minor
                statxbuf += p32(0) # stx_dev_major
                statxbuf += p32(0) # stx_dev_minor
                statxbuf += p64(0) # stx_mnt_id
                statxbuf += p32(0) # stx_dio_mem_align
                statxbuf += p32(0) # stx_dio_offset_align
                yield ('statx(0, "/tmp/xxx", 0, 0, &statxbuf)', "statx", [0, TMP_XXX, 0, 0, statxbuf])
                yield ('truncate("/tmp/xxx", 10)', "truncate", [TMP_XXX, 10])
                self.skipped_syscall.add("ftruncate")

            yield "access -> setxattr -> getxattr -> listxattr -> removexattr"
            yield ('access("/tmp/xxx", F_OK)', "access", [TMP_XXX, 0])
            if u2i(ret_history[-1]) >= 0:
                buf = "A" * 0xff + "\0"
                userx = "user.x\0"
                yield ('setxattr("/tmp/xxx", "user.x", &buf, sizeof(buf), 0)', "setxattr", [TMP_XXX, userx, buf, len(buf), 0])
                self.skipped_syscall.add("lsetxattr")
                self.skipped_syscall.add("fsetxattr")
                if u2i(ret_history[-1]) >= 0:
                    buf= "\0" * 0x100
                    yield ('getxattr("/tmp/xxx", "user.x", &buf, sizeof(buf))', "getxattr", [TMP_XXX, userx, buf, len(buf)])
                    self.skipped_syscall.add("lgetxattr")
                    self.skipped_syscall.add("fgetxattr")
                    buf = "\0" * 0x100
                    yield ('listxattr("/tmp/xxx", &buf, sizeof(buf))', "listxattr", [TMP_XXX, buf, len(buf)])
                    self.skipped_syscall.add("llistxattr")
                    self.skipped_syscall.add("flistxattr")
                    yield ('removexattr("/tmp/xxx", "user.x")', "removexattr", [TMP_XXX, userx])
                    self.skipped_syscall.add("lremovexattr")
                    self.skipped_syscall.add("fremovexattr")

            yield "link -> unlink"
            TMP_XXX3 = "/tmp/xxx3\0"
            yield ('link("/tmp/xxx", "/tmp/xxx3")', "link", [TMP_XXX, TMP_XXX3])
            self.skipped_syscall.add("linkat")
            if u2i(ret_history[-1]) >= 0:
                yield ('unlink("/tmp/xxx3")', "unlink", [TMP_XXX3])
                self.skipped_syscall.add("unlinkat")

            yield "symlink -> readlink -> rename -> unlink"
            TMP_XXX4 = "/tmp/xxx4\0"
            yield ('symlink("/tmp/xxx", "/tmp/xxx4")', "symlink", [TMP_XXX, TMP_XXX4])
            self.skipped_syscall.add("symlinkat")
            if u2i(ret_history[-1]) >= 0:
                buf = "\0" * 0x100
                yield ('readlink("/tmp/xxx4", &buf, sizeof(buf))', "readlink", [TMP_XXX4, buf, len(buf)])
                self.skipped_syscall.add("readlinkat")
                TMP_XXX5 = "/tmp/xxx5\0"
                yield ('rename("/tmp/xxx4", "/tmp/xxx5")', "rename", [TMP_XXX4, TMP_XXX5])
                self.skipped_syscall.add("renameat")
                self.skipped_syscall.add("renameat2")
                if u2i(ret_history[-1]) >= 0:
                    yield ('unlink("/tmp/xxx5")', "unlink", [TMP_XXX5])
                    self.skipped_syscall.add("unlinkat")

            yield "inotify_init1 -> inotify_add_watch -> inotify_rm_watch -> close"
            yield ("fd = inotify_init1(0)", "inotify_init1", [0])
            self.skipped_syscall.add("inotify_init")
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                yield ('wd = inotify_add_watch(fd, "/tmp/xxx", IN_MOVE_SELF)', "inotify_add_watch", [fd, TMP_XXX, 0x800])
                if u2i(ret_history[-1]) >= 0:
                    wd = ret_history[-1]
                    yield ("inotify_rm_watch(fd, wd)", "inotify_rm_watch", [fd, wd])
                yield ("close(fd)", "close", [fd])

            yield "open -> io_setup -> io_submit -> io_getevents -> close -> io_destroy"
            yield ('fd = open("/tmp/xxx", 0_RDONLY)', "open", [TMP_XXX, 0o0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                ctx_idp = p64(0)
                yield ("io_setup(1, &ctx_idp)", "io_setup", [1, ctx_idp])
                ctx_id = read_int_from_memory(current_arch.sp)
                iocb = p64(0)                       # aio_data
                iocb += p32(0)                      # aio_key
                iocb += p32(0)                      # aio_rw_flags
                iocb += p16(0)                      # aio_lio_opcode: IOCB_CMD_PREAD
                iocb += p16(0)                      # aio_reqprio
                iocb += p32(fd)                     # aio_fildes
                iocb += p64(current_arch.sp + 0x70) # aio_buf
                iocb += p64(0x100)                  # aio_nbytes
                iocb += p64(0)                      # aio_offset
                iocb += p64(0)                      # aio_reserved2
                iocb += p32(0)                      # aio_flags
                iocb += p32(0)                      # aio_resfd
                iocb += b"\0" * 0x100               # data buffer <-- aio_buf
                iocbp = p64(current_arch.sp + 0x30) # iocb
                iocbp += p64(0) * 5                 # padding
                iocbp += iocb
                yield ("io_submit(ctx_id, 1, &iocbp)", "io_submit", [ctx_id, 1, iocbp])
                events = p64(0)  # data
                events += p64(0) # obj
                events += p64(0) # res
                events += p64(0) # res2
                timeout = p64(0)  # tv_sec
                timeout += p64(0) # tv_nsec
                yield ("io_getevents(ctx_id, 1, 1, &events, &timeout)", "io_getevents", [ctx_id, 1, 1, events, timeout])
                self.tested_syscall.add("io_pgetevents")
                yield ("clode(fd)", "close", [fd])
                yield ("io_destroy(ctx_id)", "io_destroy", [ctx_id])

            yield "io_uring_setup -> mmap -> io_uring_enter -> io_uring_register -> munmap"
            params = p32(0)      # sq_entries
            params += p32(0)     # cq_entries
            params += p32(0)     # flags
            params += p32(0)     # sq_thread_cpu
            params += p32(0)     # sq_thread_idle
            params += p32(0)     # features
            params += p32(0)     # wq_fd
            params += p32(0) * 3 # resv[3]
            params += p32(0)     # sq_off.head
            params += p32(0)     # sq_off.tail
            params += p32(0)     # sq_off.ring_mask
            params += p32(0)     # sq_off.ring_entries
            params += p32(0)     # sq_off.flags
            params += p32(0)     # sq_off.dropped
            params += p32(0)     # sq_off.array
            params += p32(0) * 3 # sq_off.resv[3]
            params += p32(0)     # cq_off.head
            params += p32(0)     # cq_off.tail
            params += p32(0)     # cq_off.ring_mask
            params += p32(0)     # cq_off.ring_entries
            params += p32(0)     # cq_off.overflow
            params += p32(0)     # cq_off.cqes
            params += p32(0)     # cq_off.flags
            params += p32(0) * 3 # cq_off.resv[3]
            yield ("ring_fd = io_uring_setup(1, &params)", "io_uring_setup", [1, params])
            params = slice_unpack(read_memory(current_arch.sp, len(params)), 4)
            if u2i(ret_history[-1]) >= 0 and params[5] & 1: # IORING_FEAT_SINGLE_MMAP (available linux v5.4~)
                ring_fd = ret_history[-1]
                sring_sz = params[16] + params[0] * 4    # sq_off.array + sq_entries * sizeof(uint)
                cring_sz = params[25] + params[1] * 0x10 # cq_off.cqes + cq_entries * sizeof(struct io_uring_cqe)
                sring_sz = max(sring_sz, cring_sz)
                yield ("mmap(0, sring_sz, RW-, MAP_SHARED|MAP_POPULATE, ring_fd, IORING_OFF_SQ_RING)", "mmap", [0, sring_sz, 3, 0x1 | 0x8000, ring_fd, 0])
                if u2i(ret_history[-1]) >= 0:
                    sq_ptr = ret_history[-1]
                    yield ("io_uring_enter(ring_fd, 0, 0, 0, NULL, 8)", "io_uring_enter", [ring_fd, 0, 0, 0, 0, 8])
                    arg = p32(0)
                    yield ("io_uring_register(ring_fd, IORING_REGISTER_FILES, &arg, 1)", "io_uring_register", [ring_fd, 2, arg, 1])
                    yield ("io_uring_register(ring_fd, IORING_UNREGISTER_FILES, NULL, 0)", "io_uring_register", [ring_fd, 3, 0, 0])
                    yield ("munmap(sq_ptr, sring_sz)", "munmap", [sq_ptr, sring_sz])
                yield ("close(ring_fd)", "close", [ring_fd])

            yield "unshare"
            yield ("unshare(CLONE_FS|CLONE_FILES)", "unshare", [0x200 | 0x400])

            yield "name_to_handle_at -> unlink"
            handle = p32(0x80)     # handle_bytes: MAX_HANDLE_SZ
            handle += p32(0)       # handle_type
            handle += b"\0" * 0x80 # f_handle
            mntid = p32(0)
            yield ('name_to_handle_at(0, "/tmp/xxx", &handle, &mntid, 0)', "name_to_handle_at", [0, TMP_XXX, handle, mntid, 0])
            yield ('unlink("/tmp/xxx")', "unlink", [TMP_XXX])

            yield "mkdir -> open_tree -> close -> chdir -> rmdir"
            TMP_YYY = "/tmp/yyy\0"
            yield ('mkdir("/tmp/yyy", 0777)', "mkdir", [TMP_YYY, 0o777])
            self.tested_syscall.add("mkdirat")
            if u2i(ret_history[-1]) >= 0:
                yield ('fd = open_tree(-1, "/tmp/yyy", 0)', "open_tree", [-1, TMP_YYY, 0])
                if u2i(ret_history[-1]) >= 0:
                    fd = ret_history[-1]
                    yield ("close(fd)", "close", [fd])
                yield ('chdir("/tmp/yyy")', "chdir", [TMP_YYY])
                self.skipped_syscall.add("fchdir")
                yield ('chdir("..")', "chdir", ["..\0"])
                yield ('rmdir("/tmp/yyy")', "rmdir", [TMP_YYY])

            yield "statfs"
            buf = p64(0)      # f_type
            buf += p64(0)     # f_bsize
            buf += p64(0)     # f_blocks
            buf += p64(0)     # f_bfree
            buf += p64(0)     # f_bavail
            buf += p64(0)     # f_files
            buf += p64(0)     # f_ffree
            buf += p64(0)     # f_fsid
            buf += p64(0)     # f_namelen
            buf += p64(0)     # f_frsize
            buf += p64(0)     # f_flags
            buf += p64(0) * 4 # f_spare[4]
            yield ('statfs("/", &buf)', "statfs", ["/\0", buf])
            self.skipped_syscall.add("fstatfs")
            self.skipped_syscall.add("ustat")

            yield "open -> getdents -> fcntl -> close"
            yield ('fd = open("/", 0_RDONLY)', "open", ["/\0", 0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                buf = "\0" * 0x200
                yield ("getdents(fd, &buf, sizeof(buf))", "getdents", [fd, buf, len(buf)])
                self.skipped_syscall.add("getdents64")
                yield ("fcntl(fd, F_GETFD)", "fcntl", [fd, 1])
                yield ("fcntl(fd, F_GETFL)", "fcntl", [fd, 3])
                flock = "\0" * 0x200
                yield ("fcntl(fd, F_GETLK, &flock)", "fcntl", [fd, 5, flock])
                yield ("fcntl(fd, F_OFD_GETLK, &flock)", "fcntl", [fd, 36, flock])
                yield ("close(fd)", "close", [fd])

            yield "invalid socket -> close"
            yield ("socket(22, SOCK_STREAM, 0)", "socket", [22, 1, 0])

            yield "socket AF_INET/TCP -> bind -> listen -> setsockopt -> getsockopt -> close"
            yield ("fd = socket(AF_INET, SOCK_STREAM, 0)", "socket", [2, 1, 0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                import socket
                sockaddr = p16(socket.AF_INET)          # sin_len, sin_family
                sockaddr += p16(socket.htons(13337))    # sin_port
                sockaddr += socket.inet_aton("0.0.0.0") # sin_addr.s_addr
                sockaddr += b"\0" * 8                   # sin_zero[8]
                yield ("bind(fd, &sockaddr, sizeof(sockaddr))", "bind", [fd, sockaddr, len(sockaddr)])
                yield ("listen(fd, 16)", "listen", [fd, 16])
                opt = p32(0)
                yield ("setsockopt(fd, SOL_SOCKET, SO_DEBUG, &opt, sizeof(opt))", "setsockopt", [fd, 1, 1, opt, len(opt)])
                optlen = p32(len(opt))
                yield ("getsockopt(fd, SOL_SOCKET, SO_DEBUG, &opt, &optlen)", "getsockopt", [fd, 1, 1, opt, optlen])
                yield ("close(fd)", "close", [fd])

            yield "socket AF_INET/UDP -> connect -> getsockname -> getpeername -> close"
            yield ("fd = socket(AF_INET, SOCK_DGRAM , 0)", "socket", [2, 2, 0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                import socket
                sockaddr = p16(socket.AF_INET)          # sin_len, sin_family
                sockaddr += p16(socket.htons(13337))    # sin_port
                sockaddr += socket.inet_aton("0.0.0.0") # sin_addr.s_addr
                sockaddr += b"\0" * 8                   # sin_zero[8]
                yield ("connect(fd, &sockaddr, sizeof(sockaddr))", "connect", [fd, sockaddr, len(sockaddr)])
                sockaddr = p16(0)     # sin_len, sin_family
                sockaddr += p16(0)    # sin_port
                sockaddr += p32(0)    # sin_addr.s_addr
                sockaddr += b"\0" * 8 # sin_zero[8]
                addr_len = p64(len(sockaddr))
                yield ("getsockname(fd, &sockaddr, &addrlen)", "getsockname", [fd, sockaddr, addr_len])
                yield ("getpeername(fd, &sockaddr, &addrlen)", "getpeername", [fd, sockaddr, addr_len])
                yield ("close(fd)", "close", [fd])

            yield "socketpair AF_UNIX -> sendto -> recvfrom -> sendmsg -> recvmsg -> shutdown -> close"
            sv_array = p32(0) * 2 # sv[2]
            yield ("socketpair(AF_UNIX, SOCK_STREAM, 0, &sv[])", "socketpair", [1, 1, 0, sv_array])
            if u2i(ret_history[-1]) >= 0:
                sv0 = u32(read_memory(current_arch.sp, 4))
                sv1 = u32(read_memory(current_arch.sp + 4, 4))
                buf = "A" * 4
                yield ('sendto(sv[0], "AAAA", 4, 0, NULL, 0)', "sendto", [sv0, buf, len(buf), 0, 0, 0])
                buf = "\0" * 4
                yield ("recvfrom(sv[1], buf, 4, 0, NULL, NULL)", "recvfrom", [sv1, buf, len(buf), 0, 0, 0])
                msg = p64(0)                       # msg_name
                msg += p64(0)                      # msg_melen
                msg += p64(current_arch.sp + 0x40) # msg_iov
                msg += p64(1)                      # msg_iov_len
                msg += p64(0)                      # msg_control
                msg += p64(0)                      # msg_controllen
                msg += p64(0)                      # msg_flags
                msg += p64(0)                      # padding
                msg += p64(current_arch.sp + 0x50) # iov_base
                msg += p64(4)                      # iov_len
                msg += b"AAAA"                     # data
                yield ("sendmsg(sv[0], &msg, 0)", "sendmsg", [sv0, msg, 0])
                self.skipped_syscall.add("sendmmsg")
                yield ("recvmsg(sv[1], &msg, 0)", "sendmsg", [sv1, msg, 0])
                self.skipped_syscall.add("recvmmsg")
                yield ("shutdown(sv[0], SHUT_RDWR)", "shutdown", [sv0, 2])
                yield ("close(sv[0])", "close", [sv0])
                yield ("close(sv[1])", "close", [sv1])

            yield "memfd_create -> close"
            yield ('fd = memfd_create("test", 0)', "memfd_create", ["test\0", 0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                yield ("close(fd)", "close", [fd])

            yield "add_key -> request_key -> keyctl"
            user = "user\0"
            tkey = "test:testkey\0"
            payload = "payload\0"
            yield ('add_key("user", "test:testkey", "payload", plen, KEY_SPEC_PROCESS_KEYRING)',
                   "add_key", [user, tkey, payload, len(payload) - 1, 0xfffffffe])
            callout_info = "\0" * 0x100
            yield ('request_key("user", "test:testkey", &callout_info, KEY_SPEC_PROCESS_KEYRING)',
                   "request_key", [user, tkey, callout_info, 0xfffffffe])
            if u2i(ret_history[-1]) >= 0:
                key_serial = ret_history[-1]
                yield ("keyctl(KEYCTL_REVOKE, key_serial)", "keyctl", [3, key_serial])

            yield "invalid add_key"
            tkey = "A" * 0x100
            yield ('add_key("user", "AAAAAAAA...", NULL, 0, KEY_SPEC_PROCESS_KEYRING)',
                   "add_key", [user, tkey, 0, 0, 0xfffffffe])

            yield "open /dev/ptmx -> close"
            yield ('fd = open("/dev/ptmx", O_RDWR|O_NOCTTY)', "open", ["/dev/ptmx\0", 0o2 | 0o400])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                yield ("close(fd)", "close", [fd])

            yield "open /proc/self/stat -> close"
            yield ('fd = open("/proc/self/stat", O_RDONLY)', "open", ["/proc/self/stat\0", 0])
            if u2i(ret_history[-1]) >= 0:
                fd = ret_history[-1]
                yield ("close(fd)", "close", [fd])

            self.skipped_syscall.add("restart_syscall")   # difficult to implement generically
            self.skipped_syscall.add("pause")             # difficult to implement generically
            self.skipped_syscall.add("rt_sigreturn")      # difficult to implement generically
            self.skipped_syscall.add("rt_sigsuspend")     # difficult to implement generically
            self.skipped_syscall.add("clone")             # difficult to implement generically
            self.skipped_syscall.add("clone3")            # difficult to implement generically
            self.skipped_syscall.add("execve")            # difficult to implement generically
            self.skipped_syscall.add("execveat")          # difficult to implement generically
            self.skipped_syscall.add("fork")              # difficult to implement generically
            self.skipped_syscall.add("vfork")             # difficult to implement generically
            self.skipped_syscall.add("exit")              # difficult to implement generically
            self.skipped_syscall.add("exit_group")        # difficult to implement generically
            self.skipped_syscall.add("wait4")             # difficult to implement generically
            self.skipped_syscall.add("waitid")            # difficult to implement generically
            self.skipped_syscall.add("accept")            # difficult to implement generically
            self.skipped_syscall.add("accept4")           # difficult to implement generically
            self.skipped_syscall.add("setsid")            # difficult to implement generically
            self.skipped_syscall.add("io_cancel")         # difficult to implement generically
            self.skipped_syscall.add("seccomp")           # affect subsequent system calls
            self.skipped_syscall.add("rseq")              # affect subsequent system calls
            self.skipped_syscall.add("pkey_alloc")        # maybe unsupported by qemu HW
            self.skipped_syscall.add("pkey_mprotect")     # maybe unsupported by qemu HW
            self.skipped_syscall.add("pkey_free")         # maybe unsupported by qemu HW
            self.skipped_syscall.add("modify_ldt")        # supported only i386
            self.skipped_syscall.add("lookup_dcookie")    # deprecated
            self.skipped_syscall.add("quotactl")          # supported only ufs
            self.skipped_syscall.add("setgroups")         # need CAP_SETGID
            self.skipped_syscall.add("chroot")            # need CAP_SYS_CHROOT
            self.skipped_syscall.add("acct")              # need CAP_SYS_PACCT
            self.skipped_syscall.add("ptrace")            # need CAP_SYS_PTRACE
            self.skipped_syscall.add("iopl")              # need CAP_SYS_RAWIO
            self.skipped_syscall.add("ioperm")            # need CAP_SYS_RAWIO
            self.skipped_syscall.add("vhangup")           # need CAP_SYS_TTY_CONFIG
            self.skipped_syscall.add("reboot")            # need CAP_SYS_BOOT
            self.skipped_syscall.add("kexec_load")        # need CAP_SYS_BOOT
            self.skipped_syscall.add("kexec_file_load")   # need CAP_SYS_BOOT
            self.skipped_syscall.add("init_module")       # need CAP_SYS_MODULE
            self.skipped_syscall.add("finit_module")      # need CAP_SYS_MODULE
            self.skipped_syscall.add("delete_module")     # need CAP_SYS_MODULE
            self.skipped_syscall.add("syslog")            # need CAP_SYS_ADMIN
            self.skipped_syscall.add("pivot_root")        # need CAP_SYS_ADMIN
            self.skipped_syscall.add("mount")             # need CAP_SYS_ADMIN
            self.skipped_syscall.add("umount2")           # need CAP_SYS_ADMIN
            self.skipped_syscall.add("swapon")            # need CAP_SYS_ADMIN
            self.skipped_syscall.add("swapoff")           # need CAP_SYS_ADMIN
            self.skipped_syscall.add("sethostname")       # need CAP_SYS_ADMIN
            self.skipped_syscall.add("setdomainname")     # need CAP_SYS_ADMIN
            self.skipped_syscall.add("setns")             # need CAP_SYS_ADMIN
            self.skipped_syscall.add("move_mount")        # need CAP_SYS_ADMIN
            self.skipped_syscall.add("fsopen")            # need CAP_SYS_ADMIN
            self.skipped_syscall.add("fspick")            # need CAP_SYS_ADMIN
            self.skipped_syscall.add("fsconfig")          # need CAP_SYS_ADMIN
            self.skipped_syscall.add("fsmount")           # need CAP_SYS_ADMIN
            self.skipped_syscall.add("fanotify_init")     # need CAP_SYS_ADMIN
            self.skipped_syscall.add("fanotify_mark")     # need CAP_SYS_ADMIN
            self.skipped_syscall.add("clock_settime")     # need CAP_SYS_TIME
            self.skipped_syscall.add("settimeofday")      # need CAP_SYS_TIME
            self.skipped_syscall.add("open_by_handle_at") # need CAP_DAC_READ_SEARCH
            return None

        self.scheduled_syscall = set()
        self.tested_syscall = set()
        self.skipped_syscall = set()

        ret_history = []
        for testcase in gen_testcase():
            if isinstance(testcase, str):
                gef_print(titlify(testcase, msg_color="bold"))
                self.scheduled_syscall |= set(testcase.split(" -> "))
                continue

            desc, syscall_name, args = testcase
            gef_print(titlify("{:s};".format(desc)))
            self.setup_syscall(syscall_name, args)
            for bp in breakpoints:
                bp.enabled = True
            gdb.execute("continue")

            # here, stop at hw breakpoint
            ret = get_register(current_arch.return_register)
            gef_print("ret: {:#x}".format(ret))
            if u2i(ret) < 0:
                gef_print(Color.colorify("WARNING: r < 0", "bold red underline"))
                gdb.execute("errno {:#x}".format(ret))
            ret_history.append(ret)

            for bp in breakpoints:
                bp.enabled = False

        self.dump_untested_syscall()

        self.setup_syscall("exit", [0])
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("x86_64",))
    @only_if_in_kernel
    @only_if_kvm_disabled
    def do_invoke(self, args):
        # create option_info
        option_info = KmallocTracerCommand.create_option_info(args)

        # initialize
        info("Wait for memory scan")
        allocator = KernelChecksecCommand.get_slab_type()
        if allocator != "SLUB":
            warn("Unsupported viewing detailed information for SLAB, SLOB, SLUB_TINY")
            # fall through

        if not self.initialized:
            ret = KmallocTracerCommand.initialize(allocator, args.verbose)
            if ret is False:
                err("Failed to initialize")
                return
            self.initialized = True
            self.extra_info = ret # allow None
        else:
            if args.verbose and self.extra_info:
                info("offsetof(page, slab_cache): {:#x}".format(self.extra_info.page_offset_slab_cache))
                info("offsetof(kmem_cache, name): {:#x}".format(self.extra_info.kmem_cache_offset_name))
                info("offsetof(kmem_cache, size): {:#x}".format(self.extra_info.kmem_cache_offset_size))

        # get syscall table
        self.syscall_table = {e.name: n for n, e in get_syscall_table().table.items() if n < 0x1000}
        self.syscall_table_view_ret = gdb.execute("syscall-table-view --no-pager --quiet", to_string=True)

        # get task
        res = gdb.execute("ktask --print-regs --no-pager --quiet --filter sleep", to_string=True)
        r = re.findall(r"(?:^|\n)(0x\S+)", res)
        if not r:
            err("`sleep` process is not found. Unable to continue.")
            info("Do `/bin/sleep 5` in the guest (use full path), then `{:s}` again.".format(
                self._cmdline_,
            ))
            return
        if len(r) != 1:
            err("Multiple sleep processes are found. Unable to continue.")
            return
        target_task = int(r[0], 16)
        info("task of `sleep`: {:#x}".format(target_task))

        # get rip for breakpoint
        # get rsp for checking process
        r1 = re.search(r"rip\s*: (0x\S+)", res)
        r2 = re.search(r"rsp\s*: (0x\S+)", res)
        if not r or not r2:
            err("Failed to get rip and rsp.")
            return
        rip_of_sleep = int(r1.group(1), 16)
        rsp_of_sleep = int(r2.group(1), 16)
        info("sleep's rip: {:#x}, rsp: {:#x} (after return from nanosleep syscall)".format(rip_of_sleep, rsp_of_sleep))

        # set a hw breakpoints
        hwbp = KmallocAllocatedBy_UserlandHardwareBreakpoint(rip_of_sleep)

        # set kmalloc breakpoints (but disabled)
        breakpoints = KmallocTracerCommand.set_bp_to_kmalloc_kfree(option_info, self.extra_info, target_task)

        # wait to stop at userland `sleep` process
        gdb.execute("context off")
        info("Setup is complete. continuing...")
        gdb.execute("continue")

        # here, stop in userland `sleep` process
        if current_arch.sp != rsp_of_sleep:
            err("Stack pointer is different from expected. Unable to continue.")
            return
        # rsp align
        gdb.execute("set $rsp = {:#x}".format(rsp_of_sleep & ~0xf))

        # do test
        self.test_syscall(breakpoints)

        # clean up
        info("Syscall test is complete, cleaning up...")
        hwbp.delete()
        for bp in breakpoints:
            bp.delete()
        gdb.execute("context on")
        info("Exiting `sleep` process... (Please issue Ctrl+C)")
        gdb.execute("continue")
        return


@register_command
class UefiOvmfInfoCommand(GenericCommand):
    """Print UEFI OVMF info."""
    # https://github.com/tianocore/tianocore.github.io/wiki/OVMF-Boot-Overview
    # https://github.com/tianocore/edk2/blob/master/OvmfPkg/Sec/SecMain.c
    # https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
    # https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
    # https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/BdsDxe/BdsEntry.c
    # https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf
    _cmdline_ = "uefi-ovmf-info"
    _category_ = "08-h. Qemu-system Cooperation - Bootloader"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    def check_crc32(self, addr):
        try:
            crccheck = __import__("crccheck")
        except ImportError as err:
            msg = "Missing `crccheck` package for Python, install with: `pip install crccheck`."
            raise ImportWarning(msg) from err

        size = u32(read_physmem(addr + 0xc, 0x4))
        if size <= 0 or size > 0x1000:
            return False
        crc = u64(read_physmem(addr + 0x10, 0x8))
        if crc == 0:
            return False
        data = read_physmem(addr, 0x10)
        data += p64(0x0) # crc is zero when calculate
        data += read_physmem(addr + 0x18, size - 0x18)
        calculated_crc = crccheck.crc.Crc32().calc(data)
        return calculated_crc == crc

    def read_structure(self, addr, structure):
        d = {}
        d["__addr"] = addr
        for size, name in structure:
            unpack = u32 if size == 4 else u64
            d[name] = unpack(read_physmem(addr, size))
            addr += size
        return d

    def search_mem_backward_iter(self, keyword):
        # search from higher address (0x800_0000), it is more likely
        START_ADDR = 0x800_0000
        END_ADDR = 0x700_0000
        current = START_ADDR - gef_getpagesize()
        data = read_physmem(current, gef_getpagesize())
        end = len(data)

        while True:
            pos = data.rfind(keyword, 0, end)
            if pos == -1:
                current -= gef_getpagesize()
                if current < END_ADDR:
                    return None

                if len(data) > len(keyword):
                    size_of_cut = len(data) - len(keyword)
                    data = read_physmem(current, gef_getpagesize()) + data[:len(keyword)]
                    end += gef_getpagesize() - size_of_cut
                else:
                    data = read_physmem(current, gef_getpagesize()) + data
                    end += gef_getpagesize()
                continue
            yield current + pos
            end = pos

    def read_gPs(self):
        for _addr in self.search_mem_backward_iter(b"PEI SERV"): # EFI_TABLE_HEADER.Signature
            addr = _addr
            break
        else:
            return None
        structure = [
            [8, "Hdr.Signature"],
            [4, "Hdr.Revision"],
            [4, "Hdr.HeaderSize"],
            [4, "Hdr.CRC32"],
            [4, "Hdr.Reserved"],
            [8, "InstallPpi"],
            [8, "ReInstallPpi"],
            [8, "LocatePpi"],
            [8, "NotifyPpi"],
            [8, "GetBootMode"],
            [8, "SetBootMode"],
            [8, "GetHobList"],
            [8, "CreateHob"],
            [8, "FfsFindNextVolume"],
            [8, "FfsFindNextFile"],
            [8, "FfsFindSectionData"],
            [8, "InstallPeiMemory"],
            [8, "AllocatePages"],
            [8, "AllocatePool"],
            [8, "CopyMem"],
            [8, "SetMem"],
            [8, "ReportStatusCode"],
            [8, "ResetSystem"],
            [8, "CpuIo"],
            [8, "PciCfg"],
            [8, "FfsFindFileByName"],
            [8, "FfsGetFileInfo"],
            [8, "FfsGetVolumeInfo"],
            [8, "RegisterForShadow"],
            [8, "FindSectionData3"],
            [8, "FfsGetFileInfo2"],
            [8, "ResetSystem2"],
            [8, "FreePages"],
        ]
        return self.read_structure(addr, structure)

    def dump_gPs(self):
        self.gPs = self.read_gPs()
        if self.gPs is None:
            err("gPs is not found")
            return
        info("gPs: {:#x}".format(self.gPs["__addr"]))
        for k, v in self.gPs.items():
            if k.startswith("__"):
                continue
            if k == "Hdr.Signature":
                gef_print("  {:40s}{:#x} ({!s})".format(k + ":", v, p64(v)))
            else:
                gef_print("  {:40s}{:#x}".format(k + ":", v))
        return

    def read_mBootServices(self):
        for addr in self.search_mem_backward_iter(b"BOOTSERV"): # EFI_TABLE_HEADER.Signature
            if self.check_crc32(addr):
                break
        else:
            return None
        structure = [
            [8, "Hdr.Signature"],
            [4, "Hdr.Revision"],
            [4, "Hdr.HeaderSize"],
            [4, "Hdr.CRC32"],
            [4, "Hdr.Reserved"],
            [8, "RaiseTPL"],
            [8, "RestoreTPL"],
            [8, "AllocatePages"],
            [8, "FreePages"],
            [8, "GetMemoryMap"],
            [8, "AllocatePool"],
            [8, "FreePool"],
            [8, "CreateEvent"],
            [8, "SetTimer"],
            [8, "WaitForEvent"],
            [8, "SignalEvent"],
            [8, "CloseEvent"],
            [8, "CheckEvent"],
            [8, "InstallProtocolInterface"],
            [8, "ReinstallProtocolInterface"],
            [8, "UninstallProtocolInterface"],
            [8, "HandleProtocol"],
            [8, "Reserved"],
            [8, "RegisterProtocolNotify"],
            [8, "LocateHandle"],
            [8, "LocateDevicePath"],
            [8, "InstallConfigurationTable"],
            [8, "LoadImage"],
            [8, "StartImage"],
            [8, "Exit"],
            [8, "UnloadImage"],
            [8, "ExitBootServices"],
            [8, "GetNextMonotonicCount"],
            [8, "Stall"],
            [8, "SetWatchdogTimer"],
            [8, "ConnectController"],
            [8, "DisconnectController"],
            [8, "OpenProtocol"],
            [8, "CloseProtocol"],
            [8, "OpenProtocolInformation"],
            [8, "ProtocolsPerHandle"],
            [8, "LocateHandleBuffer"],
            [8, "LocateProtocol"],
            [8, "InstallMultipleProtocolInterfaces"],
            [8, "UninstallMultipleProtocolInterfaces"],
            [8, "CalculateCrc32"],
            [8, "CopyMem"],
            [8, "SetMem"],
            [8, "CreateEventEx"],
        ]
        return self.read_structure(addr, structure)

    def dump_mBootServices(self):
        self.mBootServices = self.read_mBootServices()
        if self.mBootServices is None:
            err("mBootServices is not found")
            return
        info("mBootServices: {:#x}".format(self.mBootServices["__addr"]))
        for k, v in self.mBootServices.items():
            if k.startswith("__"):
                continue
            if k == "Hdr.Signature":
                gef_print("  {:40s}{:#x} ({!s})".format(k + ":", v, p64(v)))
            else:
                gef_print("  {:40s}{:#x}".format(k + ":", v))
        return

    def read_mDxeServices(self):
        for addr in self.search_mem_backward_iter(b"DXE_SERV"): # EFI_TABLE_HEADER.Signature
            if self.check_crc32(addr):
                break
        else:
            return None
        structure = [
            [8, "Hdr.Signature"],
            [4, "Hdr.Revision"],
            [4, "Hdr.HeaderSize"],
            [4, "Hdr.CRC32"],
            [4, "Hdr.Reserved"],
            [8, "AddMemorySpace"],
            [8, "AllocateMemorySpace"],
            [8, "FreeMemorySpace"],
            [8, "RemoveMemorySpace"],
            [8, "GetMemorySpaceDescriptor"],
            [8, "SetMemorySpaceAttributes"],
            [8, "GetMemorySpaceMap"],
            [8, "AddIoSpace"],
            [8, "AllocateIoSpace"],
            [8, "FreeIoSpace"],
            [8, "RemoveIoSpace"],
            [8, "GetIoSpaceDescriptor"],
            [8, "GetIoSpaceMap"],
            [8, "Dispatch"],
            [8, "Schedule"],
            [8, "Trust"],
            [8, "ProcessFirmwareVolume"],
            [8, "SetMemorySpaceCapabilities"],
        ]
        return self.read_structure(addr, structure)

    def dump_mDxeServices(self):
        self.mDxeServices = self.read_mDxeServices()
        if self.mDxeServices is None:
            err("mDxeServices is not found")
            return
        info("mDxeServices: {:#x}".format(self.mDxeServices["__addr"]))
        for k, v in self.mDxeServices.items():
            if k.startswith("__"):
                continue
            if k == "Hdr.Signature":
                gef_print("  {:40s}{:#x} ({!s})".format(k + ":", v, p64(v)))
            else:
                gef_print("  {:40s}{:#x}".format(k + ":", v))
        return

    def read_mEfiSystemTable(self):
        for addr in self.search_mem_backward_iter(b"IBI SYST"): # EFI_TABLE_HEADER.Signature
            if self.check_crc32(addr):
                break
        else:
            return None
        structure = [
            [8, "Hdr.Signature"],
            [4, "Hdr.Revision"],
            [4, "Hdr.HeaderSize"],
            [4, "Hdr.CRC32"],
            [4, "Hdr.Reserved"],
            [8, "FirmwareVendor"],
            [8, "FirmwareRevision"],
            [8, "ConsoleInHandle"],
            [8, "ConIn"],
            [8, "ConsoleOutHandle"],
            [8, "ConOut"],
            [8, "StandardErrorHandle"],
            [8, "StdErr"],
            [8, "RuntimeServices"],
            [8, "BootServices"],
            [8, "NumberOfConfigurationTableEntries"],
            [8, "ConfigurationTable"],
        ]
        return self.read_structure(addr, structure)

    def dump_mEfiSystemTable(self):
        self.mEfiSystemTable = self.read_mEfiSystemTable()
        if self.mEfiSystemTable is None:
            err("*gDxeCoreST(=mEfiSystemTable) is not found")
            return
        info("*gDxeCoreST(=mEfiSystemTable): {:#x}".format(self.mEfiSystemTable["__addr"]))
        for k, v in self.mEfiSystemTable.items():
            if k.startswith("__"):
                continue
            if k == "Hdr.Signature":
                gef_print("  {:40s}{:#x} ({!s})".format(k + ":", v, p64(v)))
            else:
                gef_print("  {:40s}{:#x}".format(k + ":", v))
        return

    def read_mEfiRuntimeServicesTable(self):
        for addr in self.search_mem_backward_iter(b"RUNTSERV"): # EFI_TABLE_HEADER.Signature
            if self.check_crc32(addr):
                break
        else:
            return None
        structure = [
            [8, "Hdr.Signature"],
            [4, "Hdr.Revision"],
            [4, "Hdr.HeaderSize"],
            [4, "Hdr.CRC32"],
            [4, "Hdr.Reserved"],
            [8, "GetTime"],
            [8, "SetTime"],
            [8, "GetWakeupTime"],
            [8, "SetWakeupTime"],
            [8, "SetVirtualAddressMap"],
            [8, "ConvertPointer"],
            [8, "GetVariable"],
            [8, "GetNextVariableName"],
            [8, "SetVariable"],
            [8, "GetNextHighMonotonicCount"],
            [8, "ResetSystem"],
            [8, "UpdateCapsule"],
            [8, "QueryCapsuleCapabilities"],
            [8, "QueryVariableInfo"],
        ]
        return self.read_structure(addr, structure)

    def dump_mEfiRuntimeServicesTable(self):
        self.mEfiRuntimeServicesTable = self.read_mEfiRuntimeServicesTable()
        if self.mEfiRuntimeServicesTable is None:
            err("*gDxeCoreRT(=mEfiRuntimeServicesTable) is not found")
            return
        info("*gDxeCoreRT(=mEfiRuntimeServicesTable): {:#x}".format(self.mEfiRuntimeServicesTable["__addr"]))
        for k, v in self.mEfiRuntimeServicesTable.items():
            if k.startswith("__"):
                continue
            if k == "Hdr.Signature":
                gef_print("  {:40s}{:#x} ({!s})".format(k + ":", v, p64(v)))
            else:
                gef_print("  {:40s}{:#x}".format(k + ":", v))
        return

    def read_gMemoryMap(self):
        # gMemoryMap is just around mDxeServices
        if not self.mDxeServices:
            return None
        base = self.mDxeServices["__addr"] & ~0xf

        for diff in range(-0x1000, 0x1000, 8):
            addr = base + diff
            try:
                a = u64(read_physmem(addr, 8))
                b = u64(read_physmem(a + 8, 8))
                asig = u64(read_physmem(a - 8, 8))
                c = u64(read_physmem(addr + 8, 8))
                d = u64(read_physmem(c, 8))
                csig = u64(read_physmem(c - 8, 8))
                if addr == b == d and asig == csig == u32(b"mmap"):
                    break
            except (gdb.MemoryError, ValueError, OverflowError):
                pass
        else:
            return None

        structure = [
            [8, "ForwardLink"],
            [8, "BackLink"],
        ]
        return self.read_structure(addr, structure)

    def read_Entry(self, addr):
        structure = [
            [8, "Signature"],
            [8, "Link.ForwardLink"],
            [8, "Link.BackLink"],
            [4, "FromPages"], # with pad
            [4, "Type"],
            [8, "Start"],
            [8, "End"],
            [8, "VirtualStart"],
            [8, "Attribute"],
        ]
        offset_of_link = 8
        return self.read_structure(addr - offset_of_link, structure)

    def dump_memory_map(self):
        self.gMemoryMap = self.read_gMemoryMap()
        if self.gMemoryMap is None:
            err("gMemoryMap is not found")
            return
        info("gMemoryMap: {:#x}".format(self.gMemoryMap["__addr"]))

        type_names = [
            "EfiReservedMemoryType",
            "EfiLoaderCode",
            "EfiLoaderData",
            "EfiBootServicesCode",
            "EfiBootServicesData",
            "EfiRuntimeServicesCode",
            "EfiRuntimeServicesData",
            "EfiConventionalMemory",
            "EfiUnusableMemory",
            "EfiACPIReclaimMemory",
            "EfiACPIMemoryNVS",
            "EfiMemoryMappedIO",
            "EfiMemoryMappedIOPortSpace",
            "EfiPalCode",
            "EfiPersistentMemory",
            "EfiMaxMemoryType",
        ]

        att_list = {
            0x1: "UC",
            0x2: "WC",
            0x4: "WT",
            0x8: "WB",
            0x10: "UCE",
            0x1000: "WP",
            0x2000: "RP",
            0x4000: "XP",
            0x8000: "NV",
            0x10000: "MORE_RELIABLE",
            0x20000: "RO",
            0x40000: "SPM",
            0x80000: "CPU_CRYPTO",
            0x8000000000000000: "RUNTIME"
        }

        def att2str(att):
            s = []
            for k, v in att_list.items():
                if k & att:
                    s.append(v)
            return ",".join(s)

        fmt = "{:21s} {:10s} {:10s} {:30s} {:s}"
        legend = ["Paddr Start-End", "Vaddr", "Size", "Type:TypeName", "Attribute"]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        current = self.gMemoryMap["ForwardLink"]
        entries = []
        while current != self.gMemoryMap["__addr"]:
            entry = self.read_Entry(current)

            paddr_s = entry["Start"]
            paddr_e = entry["End"] + 1
            vaddr = entry["VirtualStart"]
            size = paddr_e - paddr_s
            typ = entry["Type"]
            memtype = type_names[entry["Type"]]
            att = entry["Attribute"]
            att_s = att2str(att)
            fmt = "{:#010x}-{:#010x} {:#010x} {:#010x} {:#x}:{:26s} {:#x}:[{:s}]"
            entry_text = fmt.format(paddr_s, paddr_e, vaddr, size, typ, memtype, att, att_s)
            entries.append(entry_text)

            if entry["Signature"] != u32(b"mmap"):
                err("Signature does not match. Corrupted?")
                break
            current = entry["Link.ForwardLink"]

        for entry_text in sorted(set(entries)):
            gef_print(entry_text)

        gef_print("Legend for attribute")
        gef_print("UC: It supports being configured as Un-Cacheable")
        gef_print("WC: It supports being configured as Write-Combining")
        gef_print("WT: It supports being configured as Write-Through")
        gef_print("WB: It supports being configured as Write-Back")
        gef_print("UCE: It supports being configured as Un-Cacheable and Exportable")
        gef_print("WP: It supports being configured as Write-Protected")
        gef_print("RP: It supports being configured as Read-Protected")
        gef_print("XP: It supports being configured as eXecute-Protected")
        gef_print("NV: It refers to persistent memory(Non-Volatile-Memory)")
        gef_print("MORE_RELIABLE: it has higher reliability than other")
        gef_print("RO: It supports being configured as Read-Only")
        gef_print("SP: Specific-Purpose memory")
        gef_print("CPU_CRYPTO: Encrypted and protected by CPU function")
        gef_print("RUNTIME: It will be mapped by OS when SetVirtualAddressMap() is called")
        return

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system",))
    @only_if_specific_arch(arch=("x86_32", "x86_64"))
    def do_invoke(self, args):
        gef_print(titlify("SEC (Security) phase variables"))
        gef_print("Unimplemented")
        gef_print(titlify("PEI (Pre EFI Initialization) phase variables"))
        self.dump_gPs()
        gef_print(titlify("DXE (Driver Execution Environment) phase variables"))
        self.dump_mBootServices()
        self.dump_mDxeServices()
        self.dump_mEfiSystemTable()
        self.dump_mEfiRuntimeServicesTable()
        gef_print(titlify("Memory map for UEFI"))
        self.dump_memory_map()
        gef_print(titlify("BDS (Boot Device Selection) phase variables"))
        gef_print("gBS: See `mBootServices` in the DXE phase")
        gef_print("gST: See `mEfiSystemTable` in the DXE phase")
        gef_print("gRT: See `mEfiRuntimeServicesTable` in the DXE phase")
        return


@register_command
class AddSymbolTemporaryCommand(GenericCommand):
    """Add symbol from command temporarily."""
    _cmdline_ = "add-symbol-temporary"
    _category_ = "01-g. Debugging Support - Other"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("function_name", metavar="FUNCTION_NAME", help="new symbol name to add.")
    parser.add_argument("function_start", metavar="START_ADDR", type=AddressUtil.parse_address,
                        help="start address to add a symbol.")
    parser.add_argument("function_end", metavar="END_ADDR", type=AddressUtil.parse_address, nargs="?",
                        help="end address to add a symbol.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} your_func_name $rip $rip+0x20".format(_cmdline_)

    @staticmethod
    def create_blank_elf(text_base, text_end):
        try:
            objcopy = GefUtil.which("objcopy")
        except FileNotFoundError as e:
            err("{}".format(e))
            return None

        try:
            gcc = GefUtil.which("gcc")
        except FileNotFoundError:
            gcc = None

        # create light ELF
        if gcc:
            fd, fname = tempfile.mkstemp(dir=GEF_TEMP_DIR, suffix=".c")
            blank_elf = fname + ".elf"
            os.fdopen(fd, "w").write("int main() {}")
            # When adding symbols, it is not necessary to match the architecture of the ELF to be created
            # and the architecture of the debugged kernel. Regardless of the architecture of the kernel
            # you are debugging, create an ELF using gcc in the host environment.
            os.system("{:s} '{:s}' -no-pie -o '{:s}'".format(gcc, fname, blank_elf))
            os.unlink(fname)
            # delete unneeded section for faster (`ksymaddr-remote-apply` will embed many symbols)
            os.system("{:s} --only-keep-debug '{:s}'".format(objcopy, blank_elf))
            os.system("{:s} --strip-all '{:s}'".format(objcopy, blank_elf))
            elf = Elf.get_elf(blank_elf)
            for s in elf.shdrs:
                if s.sh_name == "": # null, skip
                    continue
                if s.sh_name == ".text": # .text is needed, don't remove
                    continue
                if s.sh_name == ".interp": # broken if remove
                    continue
                if s.sh_name == ".rela.dyn": # cannot remove
                    continue
                if s.sh_name == ".dynamic": # cannot remove
                    continue
                if s.sh_name == ".data": # broken if remove (e.g.: add-symbol-temporary hoge 0x1234)
                    continue
                if s.sh_name == ".bss": # broken if remove
                    continue
                os.system("{:s} --remove-section='{:s}' '{:s}' 2>/dev/null".format(
                    objcopy, s.sh_name, blank_elf,
                ))
        else:
            # not found gcc. we use pre-built elf for x64
            blank_elf_skelton = [
                "7f45 4c46 0201 0100 0000 0000 0000 0000 0200 3e00 0100 0000 2010 4000 0000 0000",
                "4000 0000 0000 0000 1803 0000 0000 0000 0000 0000 4000 3800 0c00 4000 0800 0700",
                "0600 0000 0400 0000 4000 0000 0000 0000 4000 4000 0000 0000 4000 4000 0000 0000",
                "a002 0000 0000 0000 a002 0000 0000 0000 0800 0000 0000 0000 0300 0000 0400 0000",
                "1803 0000 0000 0000 1803 4000 0000 0000 1803 4000 0000 0000 0000 0000 0000 0000",
                "1c00 0000 0000 0000 0100 0000 0000 0000 0100 0000 0400 0000 0000 0000 0000 0000",
                "0000 4000 0000 0000 0000 4000 0000 0000 e002 0000 0000 0000 a804 0000 0000 0000",
                "0010 0000 0000 0000 0100 0000 0500 0000 2000 0000 0000 0000 2010 4000 0000 0000",
                "2010 4000 0000 0000 0000 0000 0000 0000 f500 0000 0000 0000 0010 0000 0000 0000",
                "0100 0000 0400 0000 e002 0000 0000 0000 2820 4000 0000 0000 0000 0000 0000 0000",
                "0000 0000 0000 0000 0000 0000 0000 0000 0010 0000 0000 0000 0100 0000 0600 0000",
                "480e 0000 0000 0000 483e 4000 0000 0000 483e 4000 0000 0000 0000 0000 0000 0000",
                "d001 0000 0000 0000 0010 0000 0000 0000 0200 0000 0600 0000 480e 0000 0000 0000",
                "483e 4000 0000 0000 483e 4000 0000 0000 0000 0000 0000 0000 9001 0000 0000 0000",
                "0800 0000 0000 0000 0400 0000 0400 0000 0000 0000 0000 0000 3803 4000 0000 0000",
                "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0800 0000 0000 0000",
                "0400 0000 0400 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000",
                "0000 0000 0000 0000 0000 0000 0000 0000 0800 0000 0000 0000 53e5 7464 0400 0000",
                "0000 0000 0000 0000 3803 4000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000",
                "0000 0000 0000 0000 0800 0000 0000 0000 50e5 7464 0400 0000 0000 0000 0000 0000",
                "0420 4000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000",
                "0800 0000 0000 0000 51e5 7464 0600 0000 0000 0000 0000 0000 0000 0000 0000 0000",
                "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0800 0000 0000 0000",
                "002e 7368 7374 7274 6162 002e 696e 7465 7270 002e 7265 6c61 2e64 796e 002e 7465",
                "7874 002e 6479 6e61 6d69 6300 2e64 6174 6100 2e62 7373 0000 0000 0000 0000 0000",
                "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000",
                "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0b00 0000 0800 0000",
                "0200 0000 0000 0000 1803 4000 0000 0000 1803 0000 0000 0000 1c00 0000 0000 0000",
                "0000 0000 0000 0000 0100 0000 0000 0000 0000 0000 0000 0000 1300 0000 0800 0000",
                "0200 0000 0000 0000 7804 4000 0000 0000 1803 0000 0000 0000 3000 0000 0000 0000",
                "0000 0000 0000 0000 0800 0000 0000 0000 1800 0000 0000 0000 1d00 0000 0800 0000",
                "0600 0000 0000 0000 2010 4000 0000 0000 2010 0000 0000 0000 f500 0000 0000 0000",
                "0000 0000 0000 0000 1000 0000 0000 0000 0000 0000 0000 0000 2300 0000 0800 0000",
                "0300 0000 0000 0000 483e 4000 0000 0000 480e 0000 0000 0000 9001 0000 0000 0000",
                "0000 0000 0000 0000 0800 0000 0000 0000 1000 0000 0000 0000 2c00 0000 0800 0000",
                "0300 0000 0000 0000 0040 4000 0000 0000 480e 0000 0000 0000 1000 0000 0000 0000",
                "0000 0000 0000 0000 0800 0000 0000 0000 0000 0000 0000 0000 3200 0000 0800 0000",
                "0300 0000 0000 0000 1040 4000 0000 0000 480e 0000 0000 0000 0800 0000 0000 0000",
                "0000 0000 0000 0000 0100 0000 0000 0000 0000 0000 0000 0000 0100 0000 0300 0000",
                "0000 0000 0000 0000 0000 0000 0000 0000 e002 0000 0000 0000 3700 0000 0000 0000",
                "0000 0000 0000 0000 0100 0000 0000 0000 0000 0000 0000 0000",
            ]
            blank_elf_skelton = bytes.fromhex("".join(blank_elf_skelton).replace(" ", ""))
            fd, blank_elf = tempfile.mkstemp(dir=GEF_TEMP_DIR, suffix=".elf")
            os.fdopen(fd, "wb").write(blank_elf_skelton)
            elf = Elf.get_elf(blank_elf)

        # fix .text base address
        os.system("{:s} --change-section-address .text={:#x} '{:s}' 2>/dev/null".format(
            objcopy, text_base, blank_elf,
        ))

        # fix .text section size (objcopy doesn't support it, so fix it manually)
        data = open(blank_elf, "rb").read()
        new_size = text_end - text_base
        if elf.e_class == Elf.ELF_64_BITS: # host is 64bit
            seq_to_find = p64(text_base)
            target_offset = data.rfind(seq_to_find) + 0x10
            seq_to_write = p64(new_size)
        else:
            if text_base > 0xffffffff:
                err("Unsupported adding 64 bit guest symbols when you use 32 bit host.")
                return None
            seq_to_find = p32(text_base)
            target_offset = data.rfind(seq_to_find) + 0x8
            seq_to_write = p32(new_size)
        data = data[:target_offset] + seq_to_write + data[target_offset + len(seq_to_write):]
        open(blank_elf, "wb").write(data)
        return blank_elf

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        try:
            objcopy = GefUtil.which("objcopy")
        except FileNotFoundError as e:
            err("{}".format(e))
            return

        # check address validity
        bits = AddressUtil.get_memory_alignment(in_bits=True)
        max_address = (1 << bits) - 1

        if args.function_start > max_address:
            if not args.quiet:
                err("function start address must be {:#x} or less".format(max_address))
            return
        if args.function_end is not None:
            if args.function_end > max_address:
                if not args.quiet:
                    err("function end address must be {:#x} or less".format(max_address))
                return
            if args.function_start > args.function_end:
                if not args.quiet:
                    err("function_start must be equal or less than function_end")
                return

        # make blank elf
        text_base = args.function_start & gef_getpagesize_mask_high()
        sym_elf = self.create_blank_elf(text_base, args.function_end or args.function_start + 1)
        if sym_elf is None:
            err("Failed to create blank elf")
            return

        if not args.quiet:
            info("1 entries will be added")

        # embedding symbols
        relative_addr = args.function_start - text_base
        os.system("{:s} --add-symbol '{:s}'=.text:{:#x},global,function '{}' 2>/dev/null".format(
            objcopy, args.function_name, relative_addr, sym_elf,
        ))

        if not args.quiet:
            info("1 entries were processed")

        # add symbol to gdb
        gdb.execute("add-symbol-file {:s} {:#x}".format(sym_elf, text_base), to_string=True)
        os.unlink(sym_elf)
        return


@register_command
class KsymaddrRemoteApplyCommand(GenericCommand):
    """Apply symbol from kallsyms in memory."""
    _cmdline_ = "ksymaddr-remote-apply"
    _category_ = "08-c. Qemu-system Cooperation - Linux Symbol"
    _aliases_ = ["ks-apply"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-r", "--reparse", action="store_true", help="do not use cache.")
    parser.add_argument("-q", "--quiet", action="store_true", help="enable quiet mode.")
    _syntax_ = parser.format_help()

    def create_symboled_elf(self, sym_elf_path):
        # get .kernel range
        text_base = Symbol.get_ksymaddr("_stext")
        if text_base is None:
            err("Failed to get kernel base (_stext)")
            return False
        res = gdb.execute("ksymaddr-remote --quiet --no-pager", to_string=True)
        text_end = int(res.splitlines()[-1].split()[0], 16)

        # make blank elf
        text_base &= gef_getpagesize_mask_high()
        blank_elf = AddSymbolTemporaryCommand.create_blank_elf(text_base, text_end)
        if blank_elf is None:
            err("Failed to create blank elf")
            return False

        # parse kernel symbol
        cmd_string_arr = []
        for line in res.splitlines():
            addr, typ, func_name = line.split()
            addr = int(addr, 16)

            if addr < text_base:
                # lower address is percpu-relative. It is meaningless to import the address, so it is skipped.
                continue

            if typ in ["T", "t", "W", None]:
                type_flag = "function"
            else:
                type_flag = "object"
            if typ and typ in "abcdefghijklmnopqrstuvwxyz":
                global_flag = "local"
            else:
                global_flag = "global"

            # higher address needs relative
            relative_addr = addr - text_base
            cmd_string_arr.append("--add-symbol")
            cmd_string_arr.append("{:s}=.text:{:#x},{:s},{:s}".format(func_name, relative_addr, global_flag, type_flag))

        if not self.quiet:
            info("{:d} entries will be added".format(len(cmd_string_arr) // 2))

        # embedding symbols
        objcopy = GefUtil.which("objcopy")
        processed_count = 0
        for cmd_string_arr_sliced in slicer(cmd_string_arr, 10000 * 2):
            subprocess.check_output([objcopy] + cmd_string_arr_sliced + [blank_elf])
            processed_count += len(cmd_string_arr_sliced) // 2

            # debug print
            if not self.quiet and processed_count and processed_count % 10000 == 0:
                info("{:d} entries were processed".format(processed_count))

        if not self.quiet:
            info("{:d} entries were processed".format(processed_count))
        os.rename(blank_elf, sym_elf_path)
        return True

    @parse_args
    @only_if_gdb_running
    @only_if_specific_gdb_mode(mode=("qemu-system", "vmware"))
    @only_if_specific_arch(arch=("x86_32", "x86_64", "ARM32", "ARM64"))
    @only_if_in_kernel
    def do_invoke(self, args):
        try:
            GefUtil.which("objcopy")
        except FileNotFoundError as e:
            err("{}".format(e))
            return

        if not args.quiet:
            info("Wait for memory scan")
        self.quiet = args.quiet

        # resolve kversion for saved file name
        kversion = Kernel.kernel_version()
        h = hashlib.sha256(String.str2bytes(kversion.version_string)).hexdigest()[-16:]
        sym_elf_path = os.path.join(GEF_TEMP_DIR, "ks-apply-{:s}.elf".format(h))
        if (not args.reparse) and os.path.exists(sym_elf_path) and os.path.getsize(sym_elf_path) > 0:
            if not args.quiet:
                info("A previously used file was found. reuse.")
        else:
            if os.path.exists(sym_elf_path):
                os.unlink(sym_elf_path)
            ret = self.create_symboled_elf(sym_elf_path)
            if not ret:
                return

        # add symbol to gdb
        text_base = Symbol.get_ksymaddr("_stext") & gef_getpagesize_mask_high()
        cmd = "add-symbol-file {:s} {:#x}".format(sym_elf_path, text_base)
        if not args.quiet:
            warn("Execute `{:s}`".format(cmd))
        gdb.execute(cmd)
        return


@register_command
class WalkLinkListCommand(GenericCommand, BufferingOutput):
    """Walk the link list."""
    _cmdline_ = "walk-link-list"
    _category_ = "03-b. Memory - View"
    _aliases_ = ["chain", "print-list"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-o", dest="next_offset", type=AddressUtil.parse_address, default=0,
                        help="offset of the next(or prev) pointer in the target structure.")
    parser.add_argument("-A", dest="dump_bytes_after", type=AddressUtil.parse_address, default=0,
                        help="dump bytes after link-list location.")
    parser.add_argument("-B", dest="dump_bytes_before", type=AddressUtil.parse_address, default=0,
                        help="dump bytes before link-list location.")
    parser.add_argument("--adjust-output", type=AddressUtil.parse_address, default=0,
                        help="displays the result of subtracting a specific value to the output.")
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="start address to walk.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0xffff9c60800597e0      # walk list_head.next\n".format(_cmdline_)
    _example_ += "{:s} -o 8 0xffff9c60800597e0 # walk list_head.prev".format(_cmdline_)

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_LOCATION)
        return

    def walk_link_list(self, head, offset):
        indent = " " * 12
        current = head
        seen = [current]
        idx = 1
        while True:
            try:
                flink = read_int_from_memory(current + offset)
            except gdb.MemoryError:
                self.err("memory corrupted")
                return
            if self.dump_bytes_before:
                source = read_memory(current - self.dump_bytes_before, self.dump_bytes_before)
                dump = hexdump(source, base=current - self.dump_bytes_before, unit=current_arch.ptrsize)
                for line in dump.splitlines():
                    self.out.append(indent + line)
            if self.dump_bytes_after:
                source = read_memory(current, self.dump_bytes_after)
                dump = hexdump(source, base=current, unit=current_arch.ptrsize)
                for line in dump.splitlines():
                    self.out.append(indent + line)
            la_flink = ProcessMap.lookup_address(flink)
            if self.adjust_output:
                la_flink_adjusted = ProcessMap.lookup_address(flink - self.adjust_output)
                self.out.append("[{:d}] -> {!s} (adjusted: {!s})".format(idx, la_flink, la_flink_adjusted))
            else:
                self.out.append("[{:d}] -> {!s}".format(idx, la_flink))
            if flink == 0:
                break
            if flink == head:
                self.out[-1] += " (head)"
                break
            if flink in seen[1:]:
                self.err("loop detected")
                break
            seen.append(current)
            current = flink
            idx += 1
        return

    @parse_args
    def do_invoke(self, args):
        self.dump_bytes_before = args.dump_bytes_before
        self.dump_bytes_after = args.dump_bytes_after
        self.adjust_output = args.adjust_output

        self.out = []
        self.info("head address: {:#x}".format(args.address))
        self.info("next pointer offset: {:#x}".format(args.next_offset))
        self.walk_link_list(args.address, args.next_offset)
        self.print_output(args)
        return


@register_command
class PeekPointersCommand(GenericCommand):
    """Find pointers belonging to other memory regions."""
    _cmdline_ = "peek-pointers"
    _category_ = "03-a. Memory - Search"
    _aliases_ = ["leakfind"]

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address, nargs="?",
                        help="search start address. (default: current_arch.sp)")
    parser.add_argument("name", metavar="NAME", nargs="?", help="what area to search. (default: all area)")
    parser.add_argument("-b", "--nb-byte", type=lambda x: int(x, 0), default=0,
                        help="the size to dump each area. (default: %(default)s)")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} 0x00007ffffffde000          # begin address of stack region\n".format(_cmdline_)
    _example_ += "{:s} 0x00007ffffffde000 vdso     # grep by `vdso` area".format(_cmdline_)

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        # get start address section
        start_addr = args.address or current_arch.sp
        start_addr = ProcessMap.lookup_address(AddressUtil.align_address_to_size(start_addr, current_arch.ptrsize))
        if start_addr.section is None:
            err("{:#x} does not exist".format(start_addr.value))
            return

        # get target
        vmmap = ProcessMap.get_process_maps()
        if args.name:
            section_name = args.name
            if section_name == "stack":
                sections = [[s.path, s.page_start, s.page_end] for s in vmmap if s.path.startswith("[stack]")]
            elif section_name == "heap":
                sections = [[s.path, s.page_start, s.page_end] for s in vmmap if s.path.startswith("[heap]")]
            elif section_name == "binary":
                sections = [[s.path, s.page_start, s.page_end] for s in vmmap if s.path == Path.get_filepath()]
            else:
                sections = [[s.path, s.page_start, s.page_end] for s in vmmap if section_name in s.path]
        else:
            sections = [[s.path, s.page_start, s.page_end] for s in vmmap]

        # fix pathname
        for i in range(len(sections)):
            name = sections[i][0]
            if name.startswith("/"):
                sections[i][0] = os.path.basename(name)

        # read data
        data = read_memory(start_addr.value, start_addr.section.page_end - start_addr.value)
        data = slice_unpack(data, current_arch.ptrsize)

        # search
        out = []
        for off, value in enumerate(data):
            value = ProcessMap.lookup_address(value)
            if not value:
                continue

            found = False
            for section in sections:
                sec_name, sec_start_addr, sec_end_addr = section
                if sec_start_addr <= value.value < sec_end_addr:
                    found = True
                    break
            if not found:
                continue

            sym = Symbol.get_symbol_string(value.value, " <NO_SYMBOL>")
            found_offset = off * current_arch.ptrsize
            found_addr = ProcessMap.lookup_address(start_addr.value + found_offset)
            perm = value.section.permission
            fmt = "Found at {!s} (+{:#x}): {!s}{:s} ('{:s}' [{!s}])"
            out.append(fmt.format(found_addr, found_offset, value, sym, sec_name, perm))

            # peek nbyte
            if args.nb_byte:
                try:
                    peeked_data = read_memory(value.value, args.nb_byte)
                    h = hexdump(peeked_data, 0x10, base=value.value, show_symbol=False)
                    out.append(h)
                except gdb.MemoryError:
                    pass

        if len(out) > GefUtil.get_terminal_size()[0]:
            gef_print("\n".join(out), less=not args.no_pager)
        else:
            gef_print("\n".join(out), less=False)
        return


@register_command
class StackFrameCommand(GenericCommand):
    """Display the entire stack of the current frame."""
    _cmdline_ = "stack-frame"
    _category_ = "02-d. Process Information - Trivial Information"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        ptrsize = current_arch.ptrsize
        try:
            frame = gdb.selected_frame()
        except gdb.error:
            # For unknown reasons, gdb.selected_frame() may cause an error (often occurs during kernel startup).
            err("Failed to get frame information")
            return

        if not frame.older():
            reason_str = gdb.frame_stop_reason_string(frame.unwind_stop_reason())
            warn("Cannot determine frame boundary, reason: {:s}".format(reason_str))
            return

        saved_ip = frame.older().pc()
        stack_hi = int(frame.older().read_register("sp"))
        stack_lo = int(frame.read_register("sp"))
        results = []

        if not current_arch.stack_grow_down:
            addr_lo = stack_lo
            addr_hi = stack_hi
        else:
            addr_lo = stack_hi + current_arch.ptrsize
            addr_hi = stack_lo + current_arch.ptrsize

        for offset, address in enumerate(range(addr_lo, addr_hi, ptrsize)):
            pprint_str = DereferenceCommand.pprint_dereferenced(addr_lo, offset)
            if AddressUtil.dereference(address) == saved_ip:
                pprint_str += " ($savedip)"
            results.append(pprint_str)

        if current_arch.stack_grow_down:
            results.reverse()
            gef_print(titlify("Stack top (higher address)"))
        else:
            gef_print(titlify("Stack top (lower address)"))

        for res in results:
            gef_print(res)

        if current_arch.stack_grow_down:
            gef_print(titlify("Stack bottom (lower address)"))
        else:
            gef_print(titlify("Stack bottom (higher address)"))
        return


@register_command
class XRefTelescopeCommand(SearchPatternCommand):
    """Recursively search for cross-references to a pattern in memory."""
    _cmdline_ = "xref-telescope"
    _category_ = "03-a. Memory - Search"
    _repeat_ = False # re-overwrite
    _aliases_ = [] # re-overwrite

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("pattern", metavar="PATTERN", help="search pattern.")
    parser.add_argument("depth", metavar="DEPTH", nargs="?", type=int, default=3,
                        help="max recursive depth. (default: %(default)s)")
    parser.add_argument("-v", "--verbose", action="store_true",
                        help="shows the section you are currently searching.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} AAAAAAAA\n".format(_cmdline_)
    _example_ += "{:s} 0x555555554000 15".format(_cmdline_)

    def xref_telescope(self, pattern, depth, history):
        """Recursively search a pattern within the whole userland memory."""
        if depth <= 0:
            # print history
            for i, h in enumerate(history):
                if i == 0:
                    prefix = ""
                else:
                    prefix = "  " * i + RIGHT_ARROW
                if isinstance(h, int):
                    addr = ProcessMap.lookup_address(h)
                    path = addr.section.path
                    perm = addr.section.permission
                    self.out.append("{:s}{!s} {:s} [{!s}]".format(prefix, addr, path, perm))
                else:
                    self.out.append("{:s}{:s}".format(prefix, h))
            return

        if String.is_hex(pattern):
            if Endian.get_endian() == Elf.BIG_ENDIAN:
                pattern = "".join(["\\x" + pattern[i:i + 2] for i in range(2, len(pattern), 2)])
            else:
                pattern = "".join(["\\x" + pattern[i:i + 2] for i in range(len(pattern) - 2, 0, -2)])

        locs = []
        for section in ProcessMap.get_process_maps():
            if not section.permission & Permission.READ:
                continue
            if section.path in ["[vvar]", "[vsyscall]", "[vectors]", "[sigpage]"]:
                continue

            start = section.page_start
            end = section.page_end

            locs += self.search_pattern_by_address(pattern, start, end)

        for loc, _ustr in locs:
            self.xref_telescope(AddressUtil.format_address(loc), depth - 1, [loc] + history)
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        # Since it inherits SearchPatternCommand, set the values to be used there.
        args.aligned = False
        args.interval = False
        args.limit = False
        args.phys = False

        self.args = args
        self.found_count = 0

        self.out = []
        self.out.append("Recursively searching '{:s}' in memory (depth: {:d})".format(
            Color.yellowify(args.pattern), args.depth,
        ))
        self.xref_telescope(args.pattern, args.depth, [args.pattern])

        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class BytearrayCommand(GenericCommand):
    """Generate a bytearray to be compared with possible badchars (ported from mona.py)."""
    _cmdline_ = "bytearray"
    _category_ = "09-c. Misc - Generation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-b", dest="badchars", default=[], action="append", help="characters to exclude.")
    parser.add_argument("-d", dest="dump", action="store_true", help="dump to /tmp/gef/bytearray.{txt,bin}.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} -b 414243 -b 51-53 -b 61..63".format(_cmdline_)

    def expand_hex(self, x):
        """4142..45 -> 4142434445"""
        if ".." not in x:
            return x

        if len(x) < 6:
            return False

        if "..." in x:
            return False

        while ".." in x:
            pos = x.find("..")
            if pos % 2 != 0:
                return False

            if pos < 2 or len(x) - 4 < pos:
                return False

            xa, xb = int(x[pos - 2:pos], 16), int(x[pos + 2:pos + 4], 16)
            if xa >= xb:
                return False
            middle = "".join("{:02x}".format(c) for c in range(xa, xb))
            x = x[:pos - 2] + middle + x[pos + 2:]
        return x

    @parse_args
    def do_invoke(self, args):
        excluded = set()
        for b in args.badchars:
            b = b.lower().replace("-", "..")

            if not re.match(r"[0-9a-f]+", b):
                err("{:s} is not valid hex (not match `[0-9a-f]+`)".format(b))
                return

            if (len(b) % 2) != 0:
                err("{:s} is not valid hex (odd length)".format(b))
                return

            eb = self.expand_hex(b)
            if eb is False:
                err("{:s} is not valid hex (failed to expand `..`)".format(b))
                return

            excluded |= {int(c, 16) for c in slicer(eb, 2)}

        info("Generating table, excluding {:d} bad chars...".format(len(excluded)))

        included = sorted(set(range(0, 256)) - excluded)

        if len(included) == 0:
            info("Nothing to dump")
            return

        info("Dumping table.")
        outt_arr = []
        outb_arr = []
        for c in included:
            outt_arr.append("\\x{:02x}".format(c))
            outb_arr.append(bytes([c]))

        bytesperline = 32
        outt = ""
        for s in slicer(outt_arr, bytesperline):
            outt += '"{:s}"\n'.format("".join(s))
        outb = b"".join(outb_arr)

        gef_print(outt.rstrip())

        if args.dump:
            arrayfile = os.path.join(GEF_TEMP_DIR, "bytearray.txt")
            open(arrayfile, "w").write(outt)
            info("Done, wrote {:d} bytes to file {:s}".format(len(outt_arr), arrayfile))
            binfilename = os.path.join(GEF_TEMP_DIR, "bytearray.bin")
            open(binfilename, "wb").write(outb)
            info("Binary output saved in {:s}".format(binfilename))
        return


@register_command
class FiletypeMemoryCommand(GenericCommand):
    """Scan memory by file and magika."""
    _cmdline_ = "filetype-memory"
    _category_ = "03-f. Memory - Investigation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="target address.")
    parser.add_argument("end_address", metavar="END_ADDRESS", nargs="?", type=AddressUtil.parse_address,
                        help="target end address. (default: the end of section of ADDRESS)")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        if not is_valid_addr(args.address):
            err("Memory read error")
            return

        try:
            start_address = args.address
            if args.end_address is not None:
                size = args.end_address - args.address
            else:
                section = ProcessMap.lookup_address(args.address).section
                size = section.page_end - args.address
            end_address = start_address + size
        except (AttributeError, ValueError):
            self.usage()
            return

        try:
            data = read_memory(start_address, size)
        except gdb.MemoryError:
            err("Memory read error")
            return

        dumpfile_name = "filetype_{:#x}-{:#x}.dat".format(start_address, end_address)
        filepath = os.path.join(GEF_TEMP_DIR, dumpfile_name)
        open(filepath, "wb").write(data)

        try:
            gef_print(titlify("file {:s}".format(filepath)))
            file_command = GefUtil.which("file")
            os.system("{:s} {:s}".format(file_command, filepath))
        except FileNotFoundError as e:
            warn("{}".format(e))

        try:
            gef_print(titlify("magika {:s}".format(filepath)))
            magika_command = GefUtil.which("magika")
            os.system("{:s} {:s}".format(magika_command, filepath))
        except FileNotFoundError as e:
            warn("{}".format(e))

        os.unlink(filepath)
        return


@register_command
class BinwalkMemoryCommand(GenericCommand):
    """Scan memory by binwalk."""
    _cmdline_ = "binwalk-memory"
    _category_ = "03-f. Memory - Investigation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-f", "--filter", action="append", type=re.compile, default=[],
                        help="REGEXP include filter.")
    parser.add_argument("-e", "--exclude", action="append", type=re.compile, default=[],
                        help="REGEXP exclude filter.")
    parser.add_argument("-m", "--maxsize", default=0x10000000, type=AddressUtil.parse_address,
                        help="maximum size of a section to be dumped. (default: 256 MB)")
    parser.add_argument("-c", "--commit", action="store_true", help="actually perform binwalk.")
    _syntax_ = parser.format_help()

    def memory_binwalk(self):
        try:
            binwalk = __import__("binwalk")
        except ImportError as err:
            msg = "Missing `binwalk` package for Python, install with: `apt install binwalk`."
            raise ImportWarning(msg) from err

        maps = ProcessMap.get_process_maps()
        if maps is None:
            err("Failed to get maps")
            return

        addr_len = current_arch.ptrsize * 2
        for entry in maps:
            start = entry.page_start
            end = entry.page_end
            perm = str(entry.permission)

            if entry.size > self.maxsize:
                continue

            if entry.path in ["[vvar]", "[vsyscall]", "[vectors]", "[sigpage]"]:
                continue

            if not entry.path.startswith(("[", "<")):
                path = os.path.basename(entry.path)
            else:
                path = entry.path
                path = path.replace("[", "").replace("]", "") # consider [heap], [stack], [vdso]
                path = path.replace("<", "").replace(">", "") # consider <tls-th1>, <explored>
            path = path.replace(" ", "_") # consider deleted case. e.g.: /path/to/file (deleted)

            fmt = "binwalk-{:0{}x}-{:0{}x}_{:s}_{:s}.raw"
            dumpfile_name = fmt.format(start, addr_len, end, addr_len, perm, path)

            if self.filter and not any(filt.search(dumpfile_name) for filt in self.filter):
                continue

            if self.exclude and any(ex.search(dumpfile_name) for ex in self.exclude):
                continue

            filepath = os.path.join(GEF_TEMP_DIR, dumpfile_name)

            if self.commit:
                gef_print(titlify("{:#x}-{:#x} [{}] {:s}".format(
                    entry.page_start, entry.page_end, entry.permission, entry.path,
                )))
                try:
                    data = read_memory(start, end - start)
                except gdb.MemoryError:
                    continue
                open(filepath, "wb").write(data)
                binwalk.scan(filepath, signature=True)
                os.unlink(filepath)
            else:
                gef_print(dumpfile_name)

        if not self.commit:
            warn('This is dry run mode. binwalk has not been performed yet. To execute, please add "--commit".')
        return

    @parse_args
    @only_if_gdb_running
    @exclude_specific_gdb_mode(mode=("qemu-system", "kgdb", "vmware"))
    def do_invoke(self, args):
        self.filter = args.filter
        self.exclude = args.exclude
        self.maxsize = args.maxsize
        self.commit = args.commit
        self.memory_binwalk()
        return


@register_command
class BincompareCommand(GenericCommand):
    """Compare an binary file with the memory position looking for badchars."""
    _cmdline_ = "bincompare"
    _category_ = "03-d. Memory - Calculation"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("filename", metavar="FILENAME", help="specifies the binary file to be compared")
    parser.add_argument("address", metavar="ADDRESS", type=AddressUtil.parse_address,
                        help="specifies the memory address.")
    parser.add_argument("size", metavar="SIZE", nargs="?", type=AddressUtil.parse_address,
                        help="specifies the size.")
    parser.add_argument("--file-offset", type=AddressUtil.parse_address,
                        help="specifies the file offset.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete=gdb.COMPLETE_FILENAME)
        return

    def compare(self, file_data, memory_data):
        result_table = []
        badchars = ""
        cnt = 0
        corrupted = -1
        for eachByte in file_data:
            hexchar = "{:02x}".format(eachByte)
            if cnt > len(memory_data):
                result_table.append((hexchar, "--"))
                corrupted = -1
            elif eachByte == memory_data[cnt]:
                result_table.append((hexchar, "  "))
                corrupted = -1
            else:
                result_table.append((hexchar, "{:02x}".format(memory_data[cnt])))
                if len(badchars) == 0:
                    badchars = hexchar
                else:
                    badchars += ", " + hexchar
                if corrupted == -1:
                    corrupted = cnt
            cnt += 1

        line = 0

        info("Comparison result:")
        gef_print("    +-----------------------------------------------+")
        for line in range(0, len(result_table), 16):
            pdata1 = []
            pdata2 = []
            for i in range(line, line + 16):
                if i < len(result_table):
                    pdata1.append(result_table[i][0])
                    pdata2.append(result_table[i][1])

            self.print_line("{:02x}".format(line), pdata1, "file")
            self.print_line("  ", pdata2, "memory")

        gef_print("    +-----------------------------------------------+")
        gef_print("")

        if corrupted > -1:
            info("Corruption after {:d} bytes".format(corrupted))

        if badchars == "":
            info("No badchars found!")
        else:
            info("Badchars found: {:s}".format(badchars))
        return

    def print_line(self, prefix, data, label):
        line = []
        for d in data:
            line.append(d)
        for _ in range(16 - len(line)):
            line.append("--")

        fmt = " {:s} |{:s} {:s} {:s} {:s} {:s} {:s} {:s} {:s} {:s} {:s} {:s} {:s} {:s} {:s} {:s} {:s}| {:s}"
        gef_print(fmt.format(prefix, *line, label))
        return

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        # file_data
        if not os.path.isfile(args.filename):
            err("specified file '{:s}' not exists".format(args.filename))
            return
        file_data = open(args.filename, "rb").read()
        if args.file_offset:
            file_data = file_data[args.file_offset:]
        file_size = len(file_data)

        # size
        if args.size is None:
            size = file_size
        else:
            if args.size > file_size:
                err("file size is too short")
                return
            size = args.size
            file_data = file_data[:size]

        if size == 0:
            err("comparing size is 0, nothing to do.")
            return

        # memory_data
        try:
            memory_data = read_memory(args.address, size)
        except gdb.MemoryError:
            err("cannot reach memory {:#x}".format(args.address))
            return

        self.compare(file_data, memory_data)
        return


@register_command
class SymbolsCommand(GenericCommand):
    """List up all symbols (shortcut for `maintenance print msymbols`) with coloring."""
    _cmdline_ = "symbols"
    _category_ = "02-g. Process Information - Symbol"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-t", "--type", action="append", default=[], help="filter by symbol type.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        ret = gdb.execute("maintenance print msymbols", to_string=True).strip()
        out = []
        PATTERN = re.compile(r"^(\[ ?\d+\]) (.) (0x[0-9a-f]+) (.*)")
        for line in ret.splitlines():
            line = line.strip()
            if not line:
                out.append(line)
                continue

            r = PATTERN.search(line)
            if not r:
                out.append(line)
                continue

            t = r.group(2)
            if args.type and t.lower() not in args.type:
                continue

            addr = int(r.group(3), 16)
            if not is_valid_addr(addr):
                out.append(line)
                continue

            fixed_line = r.group(1) + " {:s} {!s} {:s}".format(t, ProcessMap.lookup_address(addr), r.group(4))
            out.append(fixed_line)

        gef_print("\n".join(out), less=not args.no_pager)
        return


@register_command
class TypesCommand(GenericCommand):
    """List up all types (shortcut for `info types`) with compaction."""
    _cmdline_ = "types"
    _category_ = "02-h. Process Information - Type"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-s", "--smart", action="store_true",
                        help="temporarily override by `context.smart_cpp_function_name = True`.")
    parser.add_argument("-f", "--filter", action="append", type=re.compile, default=[],
                        help="REGEXP include filter.")
    parser.add_argument("-e", "--exclude", action="append", type=re.compile, default=[],
                        help="REGEXP exclude filter.")
    parser.add_argument("-E", "--no-enum", action="store_true", help="without enum.")
    parser.add_argument("-S", "--no-struct", action="store_true", help="without struct.")
    parser.add_argument("-T", "--no-typedef", action="store_true", help="without typedef.")
    parser.add_argument("-U", "--no-union", action="store_true", help="without union.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    parser.add_argument("-v", "--verbose", action="store_true", help="with the output of `dt` command.")
    _syntax_ = parser.format_help()

    @parse_args
    @only_if_gdb_running
    def do_invoke(self, args):
        basic_types = [
            "char", "unsigned char", "signed char",
            "int", "unsigned int", "signed int",
            "short", "unsigned short", "signed short",
            "long", "unsigned long", "signed long",
            "long long", "unsigned long long", "signed long long",
            "float",
            "double", "long double",
            "void",
            "bool",
        ]

        ret = gdb.execute("info types", to_string=True).strip()
        out = []
        for line in ret.splitlines():
            if line == "All defined types:":
                continue
            if line == "":
                continue
            if line.startswith("File "):
                continue

            line = re.sub(r"^\d+:|;$", "", line).strip()
            if line in basic_types:
                continue
            if args.filter and not any(filt.search(line) for filt in args.filter):
                continue
            if args.exclude and any(filt.search(line) for filt in args.exclude):
                continue
            if args.no_enum and line.startswith("enum "):
                continue
            if args.no_struct and line.startswith("struct "):
                continue
            if args.no_typedef and line.startswith("typedef "):
                continue
            if args.no_union and line.startswith("union "):
                continue
            out.append(line)

        out = sorted(set(out))

        if args.smart:
            old_smart_setting = Config.get_gef_setting("context.smart_cpp_function_name")
            Config.set_gef_setting("context.smart_cpp_function_name", True)

        new_out = []
        tqdm = GefUtil.get_tqdm()
        for type_name in tqdm(out, leave=False):
            if args.verbose:
                ret = gdb.execute('dt -n "{:s}"'.format(type_name), to_string=True)
                if not ret or (" is not struct or union" in ret) or ("Not found " in ret):
                    new_out.append(Instruction.smartify_text(type_name))
                    new_out.append("")
                    continue
                new_out.append(ret)
            else:
                new_out.append(Instruction.smartify_text(type_name))
        out = new_out

        if args.smart:
            Config.set_gef_setting("context.smart_cpp_function_name", old_smart_setting)

        gef_print("\n".join(out), less=not args.no_pager)
        return


@register_command
class GefCommand(GenericCommand):
    """The base command of GEF maintenance."""
    _cmdline_ = "gef"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("missing")
    subparsers.add_parser("config")
    subparsers.add_parser("save")
    subparsers.add_parser("restore")
    subparsers.add_parser("reload")
    subparsers.add_parser("arch-list")
    subparsers.add_parser("raise-exception")
    subparsers.add_parser("pyobj-list")
    subparsers.add_parser("avail-comm-list")
    subparsers.add_parser("set-arch")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=True)
        self.add_setting("follow_child", False, "Automatically set GDB to follow child when forking")
        self.add_setting("readline_compat", False, "Workaround for readline SOH/ETX issue (SEGV)")
        self.add_setting("disable_color", False, "Disable all colors in GEF")
        self.add_setting("always_no_pager", False, "Always disable pager in gef_print()")
        self.add_setting("pager_min_lines", 10, "Show pager only if output is longer than this value")
        self.add_setting("keep_pager_result", False, "Leaves temporary files in gef_print()")
        self.missing_commands = {}
        return

    def load_commands(self):
        """Load all the commands and functions defined by GEF into GDB."""
        global __gef_command_instances__
        nb_missing = 0
        time_elapsed = []
        for cmd_class in __gef_commands__:
            try:
                start_time_real = time.perf_counter()
                start_time_proc = time.process_time()

                if cmd_class._cmdline_ == "gef":
                    instance = self
                else:
                    instance = cmd_class() # command loading is here
                __gef_command_instances__[cmd_class._cmdline_] = instance

                end_time_real = time.perf_counter()
                end_time_proc = time.process_time()

                time_elapsed.append((
                    cmd_class._cmdline_,
                    end_time_real - start_time_real,
                    end_time_proc - start_time_proc,
                ))

                if hasattr(cmd_class._aliases_, "__iter__"):
                    for alias in cmd_class._aliases_:
                        GefAlias(alias, cmd_class._cmdline_, pre_defined=True)

            except Exception as reason:
                self.missing_commands[cmd_class._cmdline_] = reason
                nb_missing += 1

        DEBUG = False
        if DEBUG:
            print(titlify("Top 10 commands that took the longest to load"))
            for cmdline, real, cpu in sorted(time_elapsed, key=lambda x: x[1], reverse=True)[:10]:
                print("{:30s} Real:{:.10f} s, CPU:{:.10f} s".format(cmdline, real, cpu))

        # print message
        gef_print("{:s} is ready, type '{:s}' to start, '{:s}' to configure".format(
            Color.greenify("GEF"),
            Color.colorify("gef", "underline yellow"),
            Color.colorify("gef config", "underline magenta")
        ))

        ver = "{:d}.{:d}".format(sys.version_info.major, sys.version_info.minor)
        nb_cmds = len(__gef_command_instances__)
        gef_print("{:s} commands loaded for GDB {:s} using Python engine {:s}".format(
            Color.colorify(nb_cmds, "bold green"),
            Color.colorify(gdb.VERSION, "bold yellow"),
            Color.colorify(ver, "bold red")
        ))

        if nb_missing:
            warn("{:s} command{} could not be loaded, run `{:s}` to know why.".format(
                Color.colorify(nb_missing, "bold red"),
                "s" if nb_missing > 1 else "",
                Color.colorify("gef missing", "underline magenta")
            ))
        return

    def setup(self):
        # load all commands that has @register_command decolator.
        self.load_commands()

        # load the saved settings
        gdb.execute("gef restore")
        return

    @parse_args
    def do_invoke(self, args):
        gdb.execute("gef help") # for frequent use
        return


@register_command
class GefHelpCommand(GenericCommand):
    """Display GEF command list."""
    _cmdline_ = "gef help"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__()
        self.help_string = None
        return

    def generate_help(self):
        """Generate builtin commands documentation."""
        docs = []
        for cmdline, instance in __gef_command_instances__.items():
            doc = getattr(instance.__class__, "__doc__", "").lstrip()
            doc_lines = [Color.greenify(x) for x in doc.split("\n")]
            doc = "\n                         ".join(doc_lines)
            if hasattr(instance._aliases_, "__iter__") and instance._aliases_:
                aliases = " (alias: {:s})".format(", ".join(instance._aliases_))
            else:
                aliases = ""
            msg = "  {:<23s} -- {:s}{:s}".format(cmdline, doc, aliases)
            category = instance._category_ if hasattr(instance, "_category_") else "Uncategorized"
            docs.append([category, msg])

        newdoc = ""
        old_category = None
        for category, msg in sorted(docs):
            if old_category is None or old_category.split("-")[0] != category.split("-")[0]:
                newdoc += titlify(category.split(". ")[1].split(" - ")[0]) + "\n"
            if old_category != category:
                newdoc += "[{:s}]\n".format(Color.colorify(category, "bold yellow"))
            old_category = category
            newdoc += msg + "\n"
        self.help_string = newdoc.rstrip()
        return

    @parse_args
    def do_invoke(self, args):
        if self.help_string is None:
            self.generate_help()
        msg = titlify("GEF - GDB Enhanced Features") + "\n" + self.help_string
        gef_print(msg, less=not args.no_pager)
        return


@register_command
class GefConfigCommand(GenericCommand):
    """Display or change GEF configuration."""
    _cmdline_ = "gef config"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("setting_name", metavar="SETTING_NAME", nargs="?", help="setting name.")
    parser.add_argument("setting_value", metavar="SETTING_VALUE", nargs="?", help="setting value.")
    parser.add_argument("-s", "--show-only-changes", action="store_true", help="show only changed settings.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(complete="use_user_complete")
        return

    def print_setting(self, config_name, with_description=False, show_only_changes=False):
        res = Config.__gef_config__.get(config_name)
        res_orig = Config.__gef_config_orig__.get(config_name)
        if not res or not res_orig:
            return

        string_color = Config.get_gef_setting("theme.dereference_string")
        misc_color = Config.get_gef_setting("theme.dereference_base_address")

        _value, _type, _desc = res
        _value_orig, _, _ = res_orig

        _setting = Color.colorify(config_name, "green")
        _type = _type.__name__
        if _type == "str":
            _value = '"{:s}"'.format(Color.colorify(_value, string_color))
            _value_orig = '"{:s}"'.format(Color.colorify(_value_orig, string_color))
        else:
            _value = Color.colorify(_value, misc_color)
            _value_orig = Color.colorify(_value_orig, misc_color)

        if show_only_changes:
            if _value != _value_orig:
                gef_print("{:s} ({:s}) = {:s}   (orig: {:s})".format(_setting, _type, _value, _value_orig))
        else:
            gef_print("{:s} ({:s}) = {:s}".format(_setting, _type, _value))

        if with_description:
            gef_print(Color.colorify("\nDescription:", "bold underline"))
            gef_print("\t{:s}".format(_desc))
        return

    def set_setting(self, config_name, config_value):
        if "." not in config_name:
            err("Invalid command format")
            return

        loaded_cmdlines = [x.replace(" ", "_").replace("-", "_") for x in __gef_command_instances__.keys()]
        command_name = config_name.split(".", 1)[0]
        if command_name not in loaded_cmdlines:
            err("Unknown command '{:s}'".format(command_name))
            return

        _type = Config.__gef_config__.get(config_name, [None, None, None])[1]
        if _type is None:
            err("Failed to get '{:s}' config setting".format(config_name))
            return

        try:
            if _type == bool:
                if config_value.upper() in ("TRUE", "T", "1"):
                    _newval = True
                else:
                    _newval = False
            else:
                _newval = _type(config_value)
        except Exception:
            err("{} expects type '{}'".format(config_name, _type.__name__))
            return

        Config.__gef_config__[config_name][0] = _newval
        Cache.reset_gef_caches(all=True)
        return

    def complete(self, text, word): # noqa
        settings = sorted(Config.__gef_config__)

        if text == "":
            # no prefix: example: `gef config TAB`
            return [s for s in settings if word is None or word in s]

        if "." not in text:
            # if looking for possible prefix
            return [s for s in settings if s.startswith(text.strip())]

        # finally, look for possible values for given prefix
        return [s.split(".", 1)[1] for s in settings if s.startswith(text.strip())]

    @parse_args
    def do_invoke(self, args):
        # list up all configs
        if (args.setting_name, args.setting_value) == (None, None):
            gef_print(titlify("GEF configuration settings"))
            for name in sorted(Config.__gef_config__):
                self.print_setting(name, show_only_changes=args.show_only_changes)
            return

        # show name-matched config(s)
        if args.setting_name and args.setting_value is None:
            names = [x for x in Config.__gef_config__.keys() if x.startswith(args.setting_name)]
            if not names:
                return
            if len(names) == 1 or (args.setting_name in Config.__gef_config__): # uniquely identified or exact match
                gef_print(titlify("GEF configuration setting: {:s}".format(names[0])))
                self.print_setting(names[0], with_description=True, show_only_changes=args.show_only_changes)
            else:
                gef_print(titlify("GEF configuration settings matching '{:s}'".format(args.setting_name)))
                for name in names:
                    self.print_setting(name, show_only_changes=args.show_only_changes)
            return

        # set config value
        self.set_setting(args.setting_name, args.setting_value)
        return


@register_command
class GefSaveCommand(GenericCommand):
    """Save the current settings to '~/.gef.rc'."""
    _cmdline_ = "gef save"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet execution.")
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        cfg = configparser.RawConfigParser()
        old_sect = None

        # save the configuration
        for key in sorted(Config.__gef_config__):
            sect, optname = key.split(".", 1)
            value = Config.__gef_config__.get(key, None)
            value = value[0] if value else None

            if old_sect != sect:
                cfg.add_section(sect)
                old_sect = sect

            cfg.set(sect, optname, value)

        # save the aliases
        cfg.add_section("user-defined-aliases")
        cfg.add_section("user-defined-aliases.repeat")
        for alias in __gef_alias_instances__.values():
            # check pre-defined alias or not
            if alias._command_ in __gef_command_instances__:
                instance = __gef_command_instances__[alias._command_]
                if alias._alias_ in instance._aliases_:
                    continue

            cfg.set("user-defined-aliases", alias._alias_, alias._command_)
            cfg.set("user-defined-aliases.repeat", alias._alias_, str(alias._repeat_))

        with open(GEF_RC, "w") as fd:
            cfg.write(fd)

        if not args.quiet:
            ok("Configuration saved to '{:s}'".format(GEF_RC))
        return


@register_command
class GefRestoreCommand(GenericCommand):
    """Load settings from '~/.gef.rc'."""
    _cmdline_ = "gef restore"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-q", "--quiet", action="store_true", help="quiet execution.")
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        if not os.access(GEF_RC, os.R_OK):
            if not args.quiet:
                info("Not found {:s}, GEF uses default settings".format(GEF_RC))
            return

        cfg = configparser.ConfigParser()
        cfg.read(GEF_RC)

        for section in cfg.sections():
            if section == "user-defined-aliases.repeat":
                continue

            if section == "user-defined-aliases":
                # load the aliases
                for key in cfg.options(section):
                    repeat = cfg.get("user-defined-aliases.repeat", key)
                    GefAlias(key, cfg.get("user-defined-aliases", key), force_repeat=repeat)
                continue

            # load the other options
            for optname in cfg.options(section):
                # warn unused setting
                key = "{:s}.{:s}".format(section, optname)
                if key not in Config.__gef_config__:
                    err("Config '{:s}' is no longer in use, skipping...".format(Color.boldify(key)))
                    continue

                # restore type
                _type = Config.__gef_config__.get(key)[1]
                new_value = cfg.get(section, optname)
                try:
                    if _type == bool:
                        if new_value == "True":
                            new_value = True
                        elif new_value == "False":
                            new_value = False
                        else:
                            raise ValueError
                    else:
                        new_value = _type(new_value)
                except ValueError:
                    err("Config '{:s}' has bad value, skipping...".format(Color.boldify(key)))
                    continue

                # set
                Config.__gef_config__[key][0] = new_value

        # ensure that the temporary directory always exists
        abspath = os.path.expanduser(GEF_TEMP_DIR)
        abspath = os.path.realpath(abspath)
        if not os.path.isdir(abspath):
            os.makedirs(abspath, mode=0o755, exist_ok=True)

        if not args.quiet:
            ok("Configuration from '{:s}' restored".format(Color.colorify(GEF_RC, "bold blue")))
        return


@register_command
class GefMissingCommand(GenericCommand):
    """Display the GEF commands that could not be loaded with the reason."""
    _cmdline_ = "gef missing"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        missing_commands = __gef__.missing_commands.keys()
        if not missing_commands:
            ok("No missing command")
            return
        for missing_command in missing_commands:
            reason = __gef__.missing_commands[missing_command]
            warn("Command `{}` is missing, reason {} {}".format(missing_command, RIGHT_ARROW, reason))
        return


@register_command
class GefReloadCommand(GenericCommand):
    """Reload the GEF."""
    _cmdline_ = "gef reload"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        info("Check syntax {:s}".format(GEF_FILEPATH))

        try:
            pythonbin = GefUtil.which("python3")
        except FileNotFoundError as e:
            err("{}, failed to reload".format(e))
            return

        try:
            subprocess.check_output([pythonbin, GEF_FILEPATH])
        except subprocess.CalledProcessError:
            err("Reload aborted")
            return

        EventHooking.gef_on_continue_unhook(EventHandler.continue_handler)
        EventHooking.gef_on_stop_unhook(EventHandler.hook_stop_handler)
        EventHooking.gef_on_new_unhook(EventHandler.new_objfile_handler)
        EventHooking.gef_on_exit_unhook(EventHandler.exit_handler)
        EventHooking.gef_on_memchanged_unhook(EventHandler.memchanged_handler)
        EventHooking.gef_on_regchanged_unhook(EventHandler.regchanged_handler)
        Cache.reset_gef_caches(all=True)

        info("Reload {:s}".format(GEF_FILEPATH))
        s = gdb.execute("source {:s}".format(GEF_FILEPATH), to_string=True)
        for line in s.splitlines():
            if ".gnu_debugaltlink" in line:
                continue
            if "No debugging symbols" in line:
                continue
            gef_print(line)

        if current_arch is None:
            set_arch(get_arch())

        if not (is_qemu_user() or is_pin()):
            gdb.execute("define c\ncontinue\nend")

        Cache.reset_gef_caches(all=True)
        return


@register_command
class GefArchListCommand(GenericCommand):
    """Display defined architecture information."""
    _cmdline_ = "gef arch-list"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def print_arch_info(self, arch):
        # unsupported currently.
        # I made a definition for displaying syscalls, so it's just provisional.
        if arch.arch == "HPPA" and arch.mode == "64":
            return

        # title
        if arch.arch == "ARM":
            arch_name = "ARM (ARM/THUMB)"
        elif arch.arch == arch.mode:
            arch_name = arch.arch
        else:
            arch_name = "{:s} {:s}".format(arch.arch, arch.mode)
        self.out.append(titlify(arch_name))

        # settings
        self.out.append("{:30s} {:s} {!s}".format("bit length", RIGHT_ARROW, arch.bit_length))
        self.out.append("{:30s} {:s} {!s}".format("endianness", RIGHT_ARROW, arch.endianness))

        if arch.arch == "ARM":
            inst_len = "ARM:4 / THUMB:2or4"
        elif arch.instruction_length is None:
            inst_len = "variable length"
        else:
            inst_len = str(arch.instruction_length)
        self.out.append("{:30s} {:s} {!s}".format("instruction length", RIGHT_ARROW, inst_len))

        if arch.return_register is None:
            ret_regs = "different for each system call"
        else:
            ret_regs = str(arch.return_register)
        self.out.append("{:30s} {:s} {!s}".format("return register", RIGHT_ARROW, ret_regs))

        fparams = ", ".join(arch.function_parameters)
        if len(arch.function_parameters) == 1:
            fparams += " (passing via stack)"
        self.out.append("{:30s} {:s} {!s}".format("function parameters", RIGHT_ARROW, fparams))

        self.out.append("{:30s} {:s} {!s}".format("syscall register", RIGHT_ARROW, arch.syscall_register))

        if arch.syscall_parameters is None:
            sparams = "different for each system call"
        else:
            sparams = ", ".join(arch.syscall_parameters)
        self.out.append("{:30s} {:s} {!s}".format("syscall parameters", RIGHT_ARROW, sparams))

        self.out.append("{:30s} {:s} {!s}".format("Has a call/jump delay slot", RIGHT_ARROW, arch.has_delay_slot))
        self.out.append("{:30s} {:s} {!s}".format("Has a syscall delay slot", RIGHT_ARROW, arch.has_syscall_delay_slot))
        self.out.append("{:30s} {:s} {!s}".format("Has a ret delay slot", RIGHT_ARROW, arch.has_ret_delay_slot))
        self.out.append("{:30s} {:s} {!s}".format("Stack grow down", RIGHT_ARROW, arch.stack_grow_down))
        self.out.append("{:30s} {:s} {!s}".format("Thread Local Storage support", RIGHT_ARROW, arch.tls_supported))
        self.out.append("{:30s} {:s} {!s}".format("keystone support", RIGHT_ARROW, arch.keystone_support))
        self.out.append("{:30s} {:s} {!s}".format("capstone support", RIGHT_ARROW, arch.capstone_support))
        self.out.append("{:30s} {:s} {!s}".format("unicorn support", RIGHT_ARROW, arch.unicorn_support))
        return

    @parse_args
    def do_invoke(self, args):
        self.out = []
        queue = Architecture.__subclasses__()
        while queue:
            cls = queue.pop(0)
            self.print_arch_info(cls())
            queue = cls.__subclasses__() + queue

        gef_print("\n".join(self.out), less=not args.no_pager)
        return


@register_command
class GefRaiseExceptionCommand(GenericCommand):
    """Raise an exception for development."""
    _cmdline_ = "gef raise-exception"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        raise


@register_command
class GefPyObjListCommand(GenericCommand):
    """Display defined global python object."""
    _cmdline_ = "gef pyobj-list"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    @parse_args
    def do_invoke(self, args):
        skip_name_list = [
            "__name__",
            "__loader__",
            "__doc__",
            "__spec__",
            "__package__",
            "__annotations__",
            "__warningregistry__",
            "GdbRemoveReadlineFinder",
        ]

        skip_type_list = [
            type(re.compile("")), # regex object
            type(sys), # module
        ]

        function_type = type(lambda x:x)
        class_type = type(GefCommand)

        arch_list = []
        queue = Architecture.__subclasses__()
        while queue:
            cls = queue.pop(0)
            arch_list.append(cls)
            queue = cls.__subclasses__() + queue

        global_configs = []
        classes = []
        command_classes = []
        bp_classes = []
        arch_classes = []
        arch_determinations = []
        gdb_mode_determinations = []
        decorators = []
        syscall_defines = []
        gef_print_wrappers = []
        read_write_mems = []
        others = []

        for mod in dir(sys.modules["__main__"]): # for global object
            # skip specific
            if mod in skip_name_list:
                continue

            # skip specific type
            obj = getattr(sys.modules["__main__"], mod)
            if type(obj) in skip_type_list:
                continue

            t = type(obj)

            # classify
            if mod.startswith("__") and t != function_type:
                global_configs.append("{!s} {!s}".format(t, mod))
            elif mod in ["current_arch"]:
                global_configs.append("{!s} {!s}".format(t, mod))
            elif mod.upper() == mod and type(obj) != class_type:
                global_configs.append("{!s} {!s}".format(t, mod))
            elif type(obj) == class_type:
                if mod.endswith("Command"):
                    command_classes.append("{!s} {!s}".format(t, mod))
                elif mod.endswith("Breakpoint") or mod.endswith("Watchpoint"):
                    bp_classes.append("{!s} {!s}".format(t, mod))
                elif obj in arch_list:
                    arch_classes.append("{!s} {!s}".format(t, mod))
                else:
                    classes.append("{!s} {!s}".format(t, mod))
            elif obj.__doc__ and obj.__doc__.startswith("Architecture determination function"):
                arch_determinations.append("{!s} {!s}".format(t, mod))
            elif obj.__doc__ and obj.__doc__.startswith("GDB mode determination function"):
                gdb_mode_determinations.append("{!s} {!s}".format(t, mod))
            elif obj.__doc__ and obj.__doc__.startswith("Decorator"):
                decorators.append("{!s} {!s}".format(t, mod))
            elif mod.endswith(("syscall_tbl", "syscall_list")) or mod.startswith("syscall_defs"):
                syscall_defines.append("{!s} {!s}".format(t, mod))
            elif obj.__doc__ and obj.__doc__.startswith("The wrapper of gef_print"):
                gef_print_wrappers.append("{!s} {!s}".format(t, mod))
            elif re.match(r"(read|write)_.*(memory|physmem).*", mod):
                read_write_mems.append("{!s} {!s}".format(t, mod))
            else:
                others.append("{!s} {!s}".format(t, mod))

        # print
        output = []
        output.append(titlify("GEF global configs"))
        output.extend(sorted(global_configs))
        output.append(titlify("Command classes"))
        output.extend(sorted(command_classes))
        output.append(titlify("Breakpoint classes"))
        output.extend(sorted(bp_classes))
        output.append(titlify("Architecture classes"))
        output.extend(sorted(arch_classes))
        output.append(titlify("Architecture determination function"))
        output.extend(sorted(arch_determinations))
        output.append(titlify("GDB mode determination function"))
        output.extend(sorted(gdb_mode_determinations))
        output.append(titlify("Classes"))
        output.extend(sorted(classes))
        output.append(titlify("Syscall defines"))
        output.extend(sorted(syscall_defines))
        output.append(titlify("Decorators"))
        output.extend(sorted(decorators))
        output.append(titlify("gef_print wrapper"))
        output.extend(sorted(gef_print_wrappers))
        output.append(titlify("read/write memory functions"))
        output.extend(sorted(read_write_mems))
        output.append(titlify("Other functions"))
        output.extend(sorted(others))
        gef_print("\n".join(output), less=not args.no_pager)
        return


@register_command
class GefAvailableCommandListCommand(GenericCommand):
    """Displays a list of commands available for the current architecture and gdb execution mode."""
    _cmdline_ = "gef avail-comm-list"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-s", "--sort", action="store_true", help="sort by command name.")
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def check_include_mode(self, decorators):
        for line in decorators:
            if "@only_if_specific_gdb_mode" in line:
                if is_pin():
                    return '"pin"' in line
                if is_qemu_system():
                    return '"qemu-system"' in line
                if is_qemu_user():
                    return '"qemu-user"' in line
                if is_vmware():
                    return '"vmware"' in line
                if is_qiling():
                    return '"qiling"' in line
                if is_rr():
                    return '"rr"' in line
                if is_wine():
                    return '"wine"' in line
                if is_kgdb():
                    return '"kgdb"' in line
                return False
        return True

    def check_exclude_mode(self, decorators):
        for line in decorators:
            if "@exclude_specific_gdb_mode" in line:
                if is_pin():
                    return '"pin"' in line
                if is_qemu_system():
                    return '"qemu-system"' in line
                if is_qemu_user():
                    return '"qemu-user"' in line
                if is_vmware():
                    return '"vmware"' in line
                if is_qiling():
                    return '"qiling"' in line
                if is_rr():
                    return '"rr"' in line
                if is_wine():
                    return '"wine"' in line
                if is_kgdb():
                    return '"kgdb"' in line
                return False
        return False

    def get_arch_name(self):
        s = GefUtil.get_source(only_if_specific_arch).replace("\n", "")
        r = re.search(r"dic = (\{.*\})", s)
        dic = eval(r.group(1))

        for arch, func in dic.items():
            if func():
                return '"{:s}"'.format(arch)
        return None

    def check_include_arch(self, decorators, arch_name):
        for line in decorators:
            if "@only_if_specific_arch" in line:
                return arch_name in line
        return True

    def check_exclude_arch(self, decorators, arch_name):
        for line in decorators:
            if "@exclude_specific_arch" in line:
                return arch_name in line
        return False

    @parse_args
    def do_invoke(self, args):
        arch_name = self.get_arch_name()

        out = []
        for cmdline, instance in __gef_command_instances__.items():
            s = GefUtil.get_source(instance.do_invoke)
            decorators = [line for line in s.splitlines() if line.lstrip().startswith("@")]
            if not self.check_include_mode(decorators):
                out.append("{:<30s}: {:s} ({:s})".format(
                    cmdline, Color.colorify("Unavailable", "red bold"), "Unsupported gdb mode"),
                )
                continue
            if self.check_exclude_mode(decorators):
                out.append("{:<30s}: {:s} ({:s})".format(
                    cmdline, Color.colorify("Unavailable", "red bold"), "Unsupported gdb mode"),
                )
                continue
            if not self.check_include_arch(decorators, arch_name):
                out.append("{:<30s}: {:s} ({:s})".format(
                    cmdline, Color.colorify("Unavailable", "red bold"), "Unsupported arch"),
                )
                continue
            if self.check_exclude_arch(decorators, arch_name):
                out.append("{:<30s}: {:s} ({:s})".format(
                    cmdline, Color.colorify("Unavailable", "red bold"), "Unsupported arch"),
                )
                continue
            out.append("{:<30s}: {:s}".format(cmdline, Color.colorify("Available", "green bold")))

        if args.sort:
            out = sorted(out)

        gef_print("\n".join(out), less=not args.no_pager)
        return


@register_command
class GefSetArchCommand(GenericCommand):
    """Set a specific architecture to gef."""
    _cmdline_ = "gef set-arch"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("arch", metavar="ARCH", nargs="?", help="target architecture.")
    group.add_argument("-l", "--list", action="store_true", help="show supported architecure words.")
    _syntax_ = parser.format_help()

    def arch_listup(self):
        fmt = "{:12s} {:s}"
        legend = ["Arch", "Available names (Case insensitive)"]
        gef_print(Color.colorify(fmt.format(*legend), Config.get_gef_setting("theme.table_heading")))

        queue = Architecture.__subclasses__()
        while queue:
            cls = queue.pop(0)
            queue = cls.__subclasses__() + queue

            arch = Color.boldify("{:12s}".format(cls.__name__))
            words = ", ".join(filter(lambda x: isinstance(x, str), cls.load_condition))
            gef_print("{:s} {:s}".format(arch, words))
        return

    @parse_args
    def do_invoke(self, args):
        if args.list:
            self.arch_listup()
            return

        try:
            set_arch(args.arch)
            info("set_arch({:s}) is successfully".format(args.arch))
            Cache.reset_gef_caches(all=True)
        except OSError:
            err("set_arch({:s}) is failed".format(args.arch))
        return


class GefAlias(gdb.Command):
    """Simple aliasing wrapper because GDB doesn't do what it should."""
    _category_ = "99. GEF Maintenance Command"

    def __init__(self, alias, command, force_repeat=None, pre_defined=False):
        p = command.split()
        if not p:
            return

        # initialize
        self._alias_ = alias
        self._command_ = command
        if force_repeat is None:
            self._repeat_ = False
        else:
            self._repeat_ = force_repeat
        self._pre_defined_ = pre_defined
        self.__doc__ = "Alias for '{}'".format(Color.greenify(command))

        # Inherit settings from the aliased command
        if command in __gef_command_instances__:
            instance = __gef_command_instances__[command]
            # repeat settings
            if force_repeat is None:
                self._repeat_ = instance._repeat_
            # doc
            self.__doc__ += ": {}".format(instance.__doc__)

        # Aliased commands do not support completion.
        super().__init__(alias, gdb.COMMAND_NONE, completer_class=gdb.COMPLETE_NONE)

        # add or overwrite
        global __gef_alias_instances__
        __gef_alias_instances__[alias] = self
        return

    def invoke(self, args, from_tty): # noqa
        if not self._repeat_:
            self.dont_repeat()
        gdb.execute("{} {}".format(self._command_, args), from_tty=from_tty)
        return


@register_command
class AliasesCommand(GenericCommand):
    """The base command to add, remove or list aliases."""
    _cmdline_ = "aliases"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    if sys.version_info.minor >= 7:
        subparsers = parser.add_subparsers(title="command", required=True)
    else:
        subparsers = parser.add_subparsers(title="command")
    subparsers.add_parser("add")
    subparsers.add_parser("rm")
    subparsers.add_parser("ls")
    _syntax_ = parser.format_help()

    def __init__(self, *args, **kwargs):
        prefix = kwargs.get("prefix", True)
        super().__init__(prefix=prefix)
        return

    @parse_args
    def do_invoke(self, args):
        self.usage()
        return


@register_command
class AliasesAddCommand(AliasesCommand):
    """Add the command alias."""
    _cmdline_ = "aliases add"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("alias", metavar="ALIAS", help="the name of new alias.")
    parser.add_argument("command", metavar="COMMAND", nargs="+", help="the command of new alias.")
    parser.add_argument("-r", "--repeat", action="store_true", help="enforce repeat feature.")
    _syntax_ = parser.format_help()

    _example_ = "{:s} scope telescope".format(_cmdline_)

    def __init__(self):
        super().__init__(prefix=False)
        return

    @parse_args
    def do_invoke(self, args):
        command = " ".join(args.command)
        GefAlias(args.alias, command, force_repeat=args.repeat)
        gef_print("{:s} = {:s}".format(args.alias, command))
        return


@register_command
class AliasesRmCommand(AliasesCommand):
    """Remove the command alias."""
    _cmdline_ = "aliases rm"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("alias", metavar="ALIAS", help="the name of alias to be deleted.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=False)
        return

    @parse_args
    def do_invoke(self, args):
        global __gef_alias_instances__

        if args.alias in __gef_alias_instances__:
            del __gef_alias_instances__[args.alias]
        else:
            err("{:s} is not found in aliases.".format(args.alias))
        return


@register_command
class AliasesListCommand(AliasesCommand):
    """List the command alias."""
    _cmdline_ = "aliases ls"
    _category_ = "99. GEF Maintenance Command"

    parser = argparse.ArgumentParser(prog=_cmdline_)
    parser.add_argument("-n", "--no-pager", action="store_true", help="do not use less.")
    _syntax_ = parser.format_help()

    def __init__(self):
        super().__init__(prefix=False)
        return

    @parse_args
    def do_invoke(self, args):
        width = max(len(x) for x in __gef_alias_instances__.keys())

        out = []
        out.append(titlify("Pre-defined aliases"))
        for _, a in sorted(__gef_alias_instances__.items(), key=lambda x:x[0]):
            if a._pre_defined_:
                out.append("{:{:d}s} {} {}".format(a._alias_, width, RIGHT_ARROW, a._command_))

        out.append(titlify("User defined aliases"))
        for _, a in sorted(__gef_alias_instances__.items(), key=lambda x:x[0]):
            if not a._pre_defined_:
                out.append("{:{:d}s} {} {}".format(a._alias_, width, RIGHT_ARROW, a._command_))

        if out:
            gef_print("\n".join(out).rstrip(), less=not args.no_pager)
        return


class GefUtil:
    @staticmethod
    @Cache.cache_until_next
    def cached_lookup_type(_type):
        try:
            return gdb.lookup_type(_type).strip_typedefs()
        except RuntimeError:
            return None

    @staticmethod
    def get_tqdm(use_tqdm=True):
        tqdm = lambda x, leave=None, total=None: x # noqa: F841
        if not use_tqdm:
            return tqdm
        try:
            from tqdm import tqdm
        except ImportError:
            pass
        return tqdm

    __gef_convenience_vars_index__  = 0 # $_gef1, $_gef2, ...

    @staticmethod
    def gef_convenience(value):
        """Defines a new convenience value."""
        var_name = "$_gef{:d}".format(GefUtil.__gef_convenience_vars_index__)
        GefUtil.__gef_convenience_vars_index__ += 1
        gdb.execute("""set {:s} = "{:s}" """.format(var_name, value))
        return var_name

    class ArgparseExitProxyException(Exception):
        pass

    @staticmethod
    def get_terminal_size():
        """Return the current terminal size."""
        TIOCGWINSZ = 0x5413
        try:
            tty_rows, tty_columns = struct.unpack("hh", fcntl.ioctl(1, TIOCGWINSZ, "1234"))
            return tty_rows, tty_columns
        except OSError:
            return 600, 100

    @staticmethod
    def get_source(function):
        """Return the source of function."""
        import inspect
        s = inspect.getsource(function)
        return s.rstrip()

    @staticmethod
    @Cache.cache_this_session
    def log2(x):
        import math
        return int(math.log2(x))

    @staticmethod
    @Cache.cache_this_session
    def which(program):
        """Locate a command on the filesystem."""
        def is_exe(fpath):
            return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

        fpath = os.path.split(program)[0]
        if fpath:
            if is_exe(program):
                return program
        else:
            env_path = os.getenv("PATH")
            if not env_path:
                env_path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            env_path_list = env_path.split(os.pathsep)
            env_path_list += ["/usr/local/bin"] # for rp-lin, vmlinux-to-elf
            for path in env_path_list:
                path = path.strip('"')
                exe_file = os.path.join(path, program)
                if is_exe(exe_file):
                    return exe_file
        raise FileNotFoundError("Missing file `{:s}`".format(program))

    @staticmethod
    def show_last_exception():
        """Display the last Python exception."""
        def _show_code_line(fname, idx):
            fname = os.path.expanduser(os.path.expandvars(fname))
            __data = open(fname, "r").read().splitlines()
            return __data[idx - 1] if idx < len(__data) else ""

        gef_print("")
        exc_type, exc_value, exc_traceback = sys.exc_info()

        gef_print(" Exception raised ".center(80, HORIZONTAL_LINE))
        gef_print("{}: {}".format(Color.colorify(exc_type.__name__, "bold red underline"), exc_value))
        gef_print(" Detailed stacktrace ".center(80, HORIZONTAL_LINE))

        for fs in traceback.extract_tb(exc_traceback)[::-1]:
            filename, lineno, method, code = fs

            if not code or not code.strip():
                code = _show_code_line(filename, lineno)

            filename_c = Color.yellowify(filename)
            method_c = Color.greenify(method)
            gef_print('File "{}", line {:d}, in {}()'.format(filename_c, lineno, method_c))
            gef_print("   {}    {}".format(RIGHT_ARROW, code))

        gef_print(" Last 10 GDB commands ".center(80, HORIZONTAL_LINE))
        gdb.execute("show commands")
        gef_print(" Runtime environment ".center(80, HORIZONTAL_LINE))
        gdb.execute("version --compact")
        gef_print(HORIZONTAL_LINE * 80)
        gef_print("")
        return

    @staticmethod
    def gef_execute_external(command, as_list=False, *args, **kwargs):
        """Execute an external command and return the result."""
        res = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=kwargs.get("shell", False))
        if as_list:
            return [String.gef_pystring(x) for x in res.splitlines()]
        else:
            return String.gef_pystring(res)


class Gef:
    @staticmethod
    def gef_prompt(_current_prompt):
        """GEF custom prompt function."""
        if Config.get_gef_setting("gef.readline_compat") is True:
            return GEF_PROMPT
        if Config.get_gef_setting("gef.disable_color") is True:
            return GEF_PROMPT
        if is_alive():
            return GEF_PROMPT_ON
        return GEF_PROMPT_OFF

    @staticmethod
    def fix_venv():
        # venv check is very slow, so skip if unneeded
        skip_config = os.path.join(GEF_TEMP_DIR, "skip-venv-check")
        if os.path.exists(skip_config):
            return

        try:
            pythonbin = GefUtil.which("python3")
        except FileNotFoundError:
            open(skip_config, "w").close()
            return

        cmds = [pythonbin, "-c", "import os,sys;print(sys.prefix)"]
        PREFIX = String.gef_pystring(subprocess.check_output(cmds)).strip("\\n")
        if PREFIX != sys.base_prefix:
            cmds = [pythonbin, "-c", "import os,sys;print(os.linesep.join(sys.path).strip())"]
            SITE_PACKAGES_DIRS = subprocess.check_output(cmds).decode("utf-8").split()
            sys.path.extend(SITE_PACKAGES_DIRS)
        else:
            open(skip_config, "w").close()
        return

    @staticmethod
    def main():
        if GDB_VERSION < GDB_MIN_VERSION:
            err("GDB is too old. Try upgrading it.")
            return

        # create tmp dir
        if not os.path.exists(GEF_TEMP_DIR):
            os.mkdir(GEF_TEMP_DIR)

        # When using a python virtual environment (pyenv, venv, etc.), GDB still loads
        # the system-installed python, so GEF doesn't load site-packages dir from environment.
        # In order to fix it, from the shell we run the python3 binary,
        # take and parse its path, add the path to the current python process.
        Gef.fix_venv()

        # setup prompt
        gdb.prompt_hook = Gef.gef_prompt # noqa

        # setup config
        gdb.execute("set confirm off")
        gdb.execute("set verbose off")
        gdb.execute("set pagination off")
        gdb.execute("set print elements 0")

        # gdb history
        gdb.execute("set history save on")
        gdb.execute("set history filename ~/.gdb_history")

        # gdb input and output bases
        gdb.execute("set output-radix 0x10")

        # pretty print
        gdb.execute("set print pretty on")

        # array print
        gdb.execute("set print array on")
        gdb.execute("set print array-indexes on")

        try:
            # this will raise a gdb.error unless we're on x86
            gdb.execute("set disassembly-flavor intel")
        except gdb.error:
            # we can safely ignore this
            pass

        # SIGALRM will simply display a message, but gdb won't forward the signal to the process
        gdb.execute("handle SIGALRM print nopass")

        # SIGSEGV/SIGTERM/SIG32(for thread creation)
        gdb.execute("handle SIGSEGV print nopass")
        gdb.execute("handle SIGTERM print nopass")
        gdb.execute("handle SIG32 nostop")

        # demangle
        gdb.execute("set print asm-demangle on")

        # frame args
        gdb.execute("set print frame-arguments all")

        # object/vtbl
        gdb.execute("set print object on")
        gdb.execute("set print vtbl on")

        # load GEF
        global __gef__
        __gef__ = GefCommand()
        __gef__.setup()

        # follow mode
        if Config.get_gef_setting("gef.follow_child"):
            gdb.execute("set follow-fork-mode child")

        # index file
        gdb.execute("save gdb-index {}".format(GEF_TEMP_DIR))

        # gdb events configuration
        EventHooking.gef_on_continue_hook(EventHandler.continue_handler)
        EventHooking.gef_on_stop_hook(EventHandler.hook_stop_handler)
        EventHooking.gef_on_new_hook(EventHandler.new_objfile_handler)
        EventHooking.gef_on_exit_hook(EventHandler.exit_handler)
        EventHooking.gef_on_memchanged_hook(EventHandler.memchanged_handler)
        EventHooking.gef_on_regchanged_hook(EventHandler.regchanged_handler)

        if gdb.current_progspace().filename is not None:
            # if here, we are sourcing gef from a gdb session already attached
            # we must force a call to the new_objfile handler (see issue #278)
            EventHandler.new_objfile_handler(None)

        # python-interactive
        hexon()
        return


if __name__ == "__main__":
    Gef.main()