From 2204f46b0b488967184c3add50d3fe28f131bf18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Fri, 30 Jul 2021 19:59:20 +0200 Subject: [PATCH 1/2] Remove expected/ The intention was to catch functional regressions in non-matching functions but this doesn't actually work well because referenced code and data may have moved after a function was dumped, in which case the reference checker is unable to verify that function calls and data references are still correct. Considering this increases the amount of complexity in the checker and makes the workflow more complicated for contributors, let's just drop this mechanism. It isn't worth it. Putting binary files in the repo is also pretty meh. --- ...BAL__sub_I_resResourceActorCapture.cpp.bin | Bin 92 -> 0 bytes ...3utl13IParameterObj8copyLerpERKS1_S3_f.bin | Bin 232 -> 0 bytes ...l3utl14IParameterList10removeListEPS1_.bin | Bin 84 -> 0 bytes ...erList9removeObjEPNS0_13IParameterObjE.bin | Bin 84 -> 0 bytes ...StringBaseIcEES7_PNS0_13IParameterObjE.bin | Bin 212 -> 0 bytes ...l12MetaDataPack7Builder11CalcMemSizeEv.bin | Bin 80 -> 0 bytes ...ransceiverIdES3_RKNS_11MessageTypeEPvb.bin | Bin 236 -> 0 bytes .../_ZN4ksys17MessageDispatcher6updateEv.bin | Bin 248 -> 0 bytes ...stem4initERKNS0_7InitArgEPN4sead4HeapE.bin | Bin 572 -> 0 bytes ...S2_12TypedBitFlagINS1_10ProcFilterEiEE.bin | Bin 140 -> 0 bytes ...ad14SafeStringBaseIcEEiNS1_9EntryTypeE.bin | Bin 224 -> 0 bytes ...8BaseProcEEERKNS3_14SafeStringBaseIcEE.bin | Bin 200 -> 0 bytes ...g17DamageManagerBaseC1EPNS_3act5ActorE.bin | Bin 72 -> 0 bytes ...ngsEPNS0_13ActorBindingsEPN4sead4HeapE.bin | Bin 1132 -> 0 bytes ...ctor3IfEERKNS2_14SafeStringBaseIcEEbbb.bin | Bin 416 -> 0 bytes ...4ksys3gdt12getFlagColorENS0_8FlagTypeE.bin | Bin 360 -> 0 bytes expected/_ZN4ksys3gdt7ManagerC1Ev.bin | Bin 576 -> 0 bytes ...s11BoneControl6parse_EPhmPN4sead4HeapE.bin | Bin 7664 -> 0 bytes ...ameSaveData9doCreate_EPhjPN4sead4HeapE.bin | Bin 1572 -> 0 bytes ...ksys3res12ResourceUnit12updateStatusEv.bin | Bin 36 -> 0 bytes ...5ResourceMgrTask18controlField9c0d88Eb.bin | Bin 88 -> 0 bytes ...esourceMgrTask20setCompactionStoppedEb.bin | Bin 104 -> 0 bytes ...InfoContainer21loadResourceSizeTableEv.bin | Bin 504 -> 0 bytes expected/_ZN4ksys3res7CounterD0Ev.bin | 1 - .../_ZN4ksys3res9AIProgram9finalize_Ev.bin | Bin 188 -> 0 bytes ...3res9ModelList6parse_EPhmPN4sead4HeapE.bin | Bin 2096 -> 0 bytes .../_ZN4ksys4util10TaskThread5calc_El.bin | Bin 624 -> 0 bytes ...ksys4util11ManagedTask12detachHandleEv.bin | Bin 108 -> 0 bytes ...kQueueBase24notifyThreadsForNewTasksEv.bin | Bin 380 -> 0 bytes ...13TaskQueueBase9fetchTaskEPPNS0_4TaskE.bin | Bin 852 -> 0 bytes ...ask13submitRequestERNS0_11TaskRequestE.bin | Bin 536 -> 0 bytes expected/_ZN4ksys4util4Task9finalize_Ev.bin | Bin 108 -> 0 bytes expected/_ZN4ksys4util4TaskD0Ev.bin | Bin 136 -> 0 bytes expected/_ZN4ksys4util4TaskD1Ev.bin | Bin 128 -> 0 bytes ...askForRequest_ERNS0_14TaskMgrRequestEb.bin | Bin 276 -> 0 bytes ...S2_10IDelegate1IPPNS0_11ManagedTaskEEE.bin | Bin 380 -> 0 bytes expected/_ZN4ksys8VFRVec3f11updateStatsEv.bin | Bin 192 -> 0 bytes ...ad11BitFlagUtil18findOnBitFromRightEji.bin | Bin 116 -> 0 bytes ...11BitFlagUtil20findOnBitFromRight64Emi.bin | Bin 172 -> 0 bytes ...11ResourceMgr6createERKNS0_9CreateArgE.bin | Bin 376 -> 0 bytes ...KeyEE8eraseMinEPNS_11TreeMapNodeIS3_EE.bin | Bin 432 -> 0 bytes ..._ZN4sead13ReadWriteLock11writeUnlockEv.bin | Bin 196 -> 0 bytes ...mpressor13DecompContext10initializeEPv.bin | Bin 32 -> 0 bytes ...ad15SZSDecompressor13DecompContextC1Ev.bin | Bin 32 -> 0 bytes ...N4sead17StringBuilderBaseIcE6appendEci.bin | Bin 132 -> 0 bytes ...tringBaseIcEERKNS_14SafeStringBaseIcEE.bin | Bin 1000 -> 0 bytes ...WorkerMgrEjiiRKNS_14SafeStringBaseIcEE.bin | Bin 240 -> 0 bytes ...mit_IfEET_fPKNS0_13CurveDataInfoEPKS2_.bin | Bin 208 -> 0 bytes ...t2D_IfEET_fPKNS0_13CurveDataInfoEPKS2_.bin | Bin 344 -> 0 bytes ...r2D_IfEET_fPKNS0_13CurveDataInfoEPKS2_.bin | Bin 196 -> 0 bytes ...ctor2IT_EEfPKNS0_13CurveDataInfoEPKS3_.bin | Bin 208 -> 0 bytes ...ctor2IT_EEfPKNS0_13CurveDataInfoEPKS3_.bin | Bin 188 -> 0 bytes .../_ZN4sead7MemUtil13checkFillTypeEPKvm.bin | Bin 60 -> 0 bytes .../_ZN4sead8EnumUtil15getParseTextCS_Ev.bin | Bin 116 -> 0 bytes ...4sead8EnumUtil20getInitValueArrayCS_Ev.bin | Bin 116 -> 0 bytes expected/_ZN4sead8JobQueueC1Ev.bin | Bin 140 -> 0 bytes expected/_ZN4seadmlERKNS_8Color4u8Ef.bin | Bin 104 -> 0 bytes ...kResultERKN4sead14SafeStringBaseIcEEib.bin | Bin 1556 -> 0 bytes ...oneEPN4sead4HeapEPNS0_13IParameterObjE.bin | Bin 136 -> 0 bytes ...oneEPN4sead4HeapEPNS0_13IParameterObjE.bin | Bin 284 -> 0 bytes ...ramMgr8getParamEPKcPPNS0_10ActorParamE.bin | Bin 620 -> 0 bytes ...orEPNS_3act24ActorLinkConstDataAccessE.bin | Bin 88 -> 0 bytes ...ZNK4ksys3res12ResourceUnit9isParseOkEv.bin | Bin 228 -> 0 bytes ...ourceSizeERKN4sead14SafeStringBaseIcEE.bin | Bin 380 -> 0 bytes ...0DefinitionERKNS2_14SafeStringBaseIcEE.bin | Bin 168 -> 0 bytes ...efinitionERKN4sead14SafeStringBaseIcEE.bin | Bin 172 -> 0 bytes ...ksys3res9ActorLink6hasTagENS_3act3TagE.bin | Bin 108 -> 0 bytes ...afeStringBaseIcEEE12binarySearchEPKS2_.bin | Bin 672 -> 0 bytes tools/dump_function.py | 29 ------------------ tools/progress.py | 17 ++-------- 70 files changed, 2 insertions(+), 45 deletions(-) delete mode 100644 expected/_GLOBAL__sub_I_resResourceActorCapture.cpp.bin delete mode 100644 expected/_ZN3agl3utl13IParameterObj8copyLerpERKS1_S3_f.bin delete mode 100644 expected/_ZN3agl3utl14IParameterList10removeListEPS1_.bin delete mode 100644 expected/_ZN3agl3utl14IParameterList9removeObjEPNS0_13IParameterObjE.bin delete mode 100644 expected/_ZN3agl3utl14ParameterCurveILj4EEC1ERKN4sead14SafeStringBaseIcEES7_PNS0_13IParameterObjE.bin delete mode 100644 expected/_ZN4evfl12MetaDataPack7Builder11CalcMemSizeEv.bin delete mode 100644 expected/_ZN4ksys17MessageDispatcher29sendMessageOnProcessingThreadERKNS_16MesTransceiverIdES3_RKNS_11MessageTypeEPvb.bin delete mode 100644 expected/_ZN4ksys17MessageDispatcher6updateEv.bin delete mode 100644 expected/_ZN4ksys18OverlayArenaSystem4initERKNS0_7InitArgEPN4sead4HeapE.bin delete mode 100644 expected/_ZN4ksys3act11BaseProcMgr11forEachProcERN4sead10IDelegate1IPNS0_8BaseProcEEENS2_12TypedBitFlagINS1_10ProcFilterEiEE.bin delete mode 100644 expected/_ZN4ksys3act13InstParamPack6Buffer3addEPKvRKN4sead14SafeStringBaseIcEEiNS1_9EntryTypeE.bin delete mode 100644 expected/_ZN4ksys3act13InstParamPack6Buffer3addEPN4sead10IDelegate1IPNS0_8BaseProcEEERKNS3_14SafeStringBaseIcEE.bin delete mode 100644 expected/_ZN4ksys3dmg17DamageManagerBaseC1EPNS_3act5ActorE.bin delete mode 100644 expected/_ZN4ksys3evt16ResourceTimeline13setUpBindingsEPNS0_13ActorBindingsEPN4sead4HeapE.bin delete mode 100644 expected/_ZN4ksys3gdt12TriggerParam8setVec3fERKN4sead7Vector3IfEERKNS2_14SafeStringBaseIcEEbbb.bin delete mode 100644 expected/_ZN4ksys3gdt12getFlagColorENS0_8FlagTypeE.bin delete mode 100644 expected/_ZN4ksys3gdt7ManagerC1Ev.bin delete mode 100644 expected/_ZN4ksys3res11BoneControl6parse_EPhmPN4sead4HeapE.bin delete mode 100644 expected/_ZN4ksys3res12GameSaveData9doCreate_EPhjPN4sead4HeapE.bin delete mode 100644 expected/_ZN4ksys3res12ResourceUnit12updateStatusEv.bin delete mode 100644 expected/_ZN4ksys3res15ResourceMgrTask18controlField9c0d88Eb.bin delete mode 100644 expected/_ZN4ksys3res15ResourceMgrTask20setCompactionStoppedEb.bin delete mode 100644 expected/_ZN4ksys3res21ResourceInfoContainer21loadResourceSizeTableEv.bin delete mode 100644 expected/_ZN4ksys3res7CounterD0Ev.bin delete mode 100644 expected/_ZN4ksys3res9AIProgram9finalize_Ev.bin delete mode 100644 expected/_ZN4ksys3res9ModelList6parse_EPhmPN4sead4HeapE.bin delete mode 100644 expected/_ZN4ksys4util10TaskThread5calc_El.bin delete mode 100644 expected/_ZN4ksys4util11ManagedTask12detachHandleEv.bin delete mode 100644 expected/_ZN4ksys4util13TaskQueueBase24notifyThreadsForNewTasksEv.bin delete mode 100644 expected/_ZN4ksys4util13TaskQueueBase9fetchTaskEPPNS0_4TaskE.bin delete mode 100644 expected/_ZN4ksys4util4Task13submitRequestERNS0_11TaskRequestE.bin delete mode 100644 expected/_ZN4ksys4util4Task9finalize_Ev.bin delete mode 100644 expected/_ZN4ksys4util4TaskD0Ev.bin delete mode 100644 expected/_ZN4ksys4util4TaskD1Ev.bin delete mode 100644 expected/_ZN4ksys4util7TaskMgr24fetchIdleTaskForRequest_ERNS0_14TaskMgrRequestEb.bin delete mode 100644 expected/_ZN4ksys4util7TaskMgr4initEiPN4sead4HeapERNS2_10IDelegate1IPPNS0_11ManagedTaskEEE.bin delete mode 100644 expected/_ZN4ksys8VFRVec3f11updateStatsEv.bin delete mode 100644 expected/_ZN4sead11BitFlagUtil18findOnBitFromRightEji.bin delete mode 100644 expected/_ZN4sead11BitFlagUtil20findOnBitFromRight64Emi.bin delete mode 100644 expected/_ZN4sead11ResourceMgr6createERKNS0_9CreateArgE.bin delete mode 100644 expected/_ZN4sead11TreeMapImplIN4ksys4util13StrTreeMapKeyEE8eraseMinEPNS_11TreeMapNodeIS3_EE.bin delete mode 100644 expected/_ZN4sead13ReadWriteLock11writeUnlockEv.bin delete mode 100644 expected/_ZN4sead15SZSDecompressor13DecompContext10initializeEPv.bin delete mode 100644 expected/_ZN4sead15SZSDecompressor13DecompContextC1Ev.bin delete mode 100644 expected/_ZN4sead17StringBuilderBaseIcE6appendEci.bin delete mode 100644 expected/_ZN4sead4Path6getExtEPNS_22BufferedSafeStringBaseIcEERKNS_14SafeStringBaseIcEE.bin delete mode 100644 expected/_ZN4sead6WorkerC1EPNS_9WorkerMgrEjiiRKNS_14SafeStringBaseIcEE.bin delete mode 100644 expected/_ZN4sead6hostio12curveHermit_IfEET_fPKNS0_13CurveDataInfoEPKS2_.bin delete mode 100644 expected/_ZN4sead6hostio14curveHermit2D_IfEET_fPKNS0_13CurveDataInfoEPKS2_.bin delete mode 100644 expected/_ZN4sead6hostio14curveLinear2D_IfEET_fPKNS0_13CurveDataInfoEPKS2_.bin delete mode 100644 expected/_ZN4sead6hostio16curveHermitVec2_IfEENS_7Vector2IT_EEfPKNS0_13CurveDataInfoEPKS3_.bin delete mode 100644 expected/_ZN4sead6hostio18curveLinear2DVec2_IfEENS_7Vector2IT_EEfPKNS0_13CurveDataInfoEPKS3_.bin delete mode 100644 expected/_ZN4sead7MemUtil13checkFillTypeEPKvm.bin delete mode 100644 expected/_ZN4sead8EnumUtil15getParseTextCS_Ev.bin delete mode 100644 expected/_ZN4sead8EnumUtil20getInitValueArrayCS_Ev.bin delete mode 100644 expected/_ZN4sead8JobQueueC1Ev.bin delete mode 100644 expected/_ZN4seadmlERKNS_8Color4u8Ef.bin delete mode 100644 expected/_ZN5uking2ui16PauseMenuDataMgr16removeCookResultERKN4sead14SafeStringBaseIcEEib.bin delete mode 100644 expected/_ZNK3agl3utl14ParameterCurveILj2EE5cloneEPN4sead4HeapEPNS0_13IParameterObjE.bin delete mode 100644 expected/_ZNK3agl3utl14ParameterCurveILj4EE5cloneEPN4sead4HeapEPNS0_13IParameterObjE.bin delete mode 100644 expected/_ZNK4ksys3act13ActorParamMgr8getParamEPKcPPNS0_10ActorParamE.bin delete mode 100644 expected/_ZNK4ksys3map6Object20getActorWithAccessorEPNS_3act24ActorLinkConstDataAccessE.bin delete mode 100644 expected/_ZNK4ksys3res12ResourceUnit9isParseOkEv.bin delete mode 100644 expected/_ZNK4ksys3res21ResourceInfoContainer15getResourceSizeERKN4sead14SafeStringBaseIcEE.bin delete mode 100644 expected/_ZNK4ksys3res9AIProgram13getSInstParamEPPKN4sead7Vector3IfEERKNS1_10DefinitionERKNS2_14SafeStringBaseIcEE.bin delete mode 100644 expected/_ZNK4ksys3res9AIProgram13getSInstParamEPPKiRKNS1_10DefinitionERKN4sead14SafeStringBaseIcEE.bin delete mode 100644 expected/_ZNK4ksys3res9ActorLink6hasTagENS_3act3TagE.bin delete mode 100644 expected/_ZNK4sead8ObjArrayINS_14SafeStringBaseIcEEE12binarySearchEPKS2_.bin delete mode 100755 tools/dump_function.py diff --git a/expected/_GLOBAL__sub_I_resResourceActorCapture.cpp.bin b/expected/_GLOBAL__sub_I_resResourceActorCapture.cpp.bin deleted file mode 100644 index 0a478170b7818c7cff598b1c97c6ffa5987178dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92 zcmV-i0HgmX0|3wnfjE)r146P26sS_G=J(R;p1|@6DFCS{0|1aINkREb;-~WJ0|GMZ yQjYQpEdi;D+P6{)qM33EApp55EkG$L2|&3DB>=e#B?T!8Ee0tGIRLr917FtE10pp5 diff --git a/expected/_ZN3agl3utl13IParameterObj8copyLerpERKS1_S3_f.bin b/expected/_ZN3agl3utl13IParameterObj8copyLerpERKS1_S3_f.bin deleted file mode 100644 index 9375e67e037495ee51987fe45f96c76e942baa80..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 232 zcmaFCFZ1VHIOEDM{!A~8B7j8IV6EtW`W-~W~NnNnHg6xFxp>J zU}i8YVRQJ|!R4@XE0Dg*z_4W{kZsS%k)6Q65VDoa;pf!<|F>QP%3TA>orKCUFfoK& z1IkSU%7M&gly&&|fLVCe-)d)|-A*gNg*&c%!S3=$fkFNny4V5c_-m#A{%;8Z;tr6z x1RZ`d$gc2vz$~)rA+zYJN6cbiw}H$z`}=>(6d?WO&;Ko8xBUCR^~wML;sB!PY)$|G diff --git a/expected/_ZN3agl3utl14IParameterList10removeListEPS1_.bin b/expected/_ZN3agl3utl14IParameterList10removeListEPS1_.bin deleted file mode 100644 index 66d329d907a278e6fded634df7723f38d0a333c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84 zcmV-a0IUD#0|2TDjY0TI0syq>10SmE0}85t0Riiv002~K89@2z0}HBZ|NpfL000y! q7(n?e!2ppz0RZu65r~=!0RZ_Z7(n?*006ZK5CHi<7y$Xe17Fr5B_2%x diff --git a/expected/_ZN3agl3utl14IParameterList9removeObjEPNS0_13IParameterObjE.bin b/expected/_ZN3agl3utl14IParameterList9removeObjEPNS0_13IParameterObjE.bin deleted file mode 100644 index 59a774433014105e76ed8987333ad735fa933649..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84 zcmV-a0IUD#0|2TDjX?NH0syq>10SmE0}85t0Riiv002~K5kUFr0}HBZ|NpfL000y! q5J34WfdG*|0RZu65r~=!0RZ_Z5J34z006ZK2mtv%5CHkW17Fq?{~hE2 diff --git a/expected/_ZN3agl3utl14ParameterCurveILj4EEC1ERKN4sead14SafeStringBaseIcEES7_PNS0_13IParameterObjE.bin b/expected/_ZN3agl3utl14ParameterCurveILj4EEC1ERKN4sead14SafeStringBaseIcEES7_PNS0_13IParameterObjE.bin deleted file mode 100644 index 655ac76766f9e25d7444092af7ba035b43881b1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 212 zcmey$FZ<(*KjX^3)l4h@HZx4*U}gBganSYWXJ&>~^;`@;IUE@#er0A{^?+G)RR$Bo z&lOA#KRI|EetuzQUd6y@e{BJq!_Tsk|I-t=73}?5)f}=sLV(M(uaWf8IXO9(K54+d1dB5mX(=xY(Td=t^DHexbiEz^AAP_1`z#8WIc5`=1H%sv9)_JO85vACHJmi<9T^H=Gs_t1FmiEgAMBRu kVPyz>$;|29$;ip2$;joc!N|eQv4%mDQ-WdV0p|E?0Q(OT+5i9m diff --git a/expected/_ZN4ksys17MessageDispatcher29sendMessageOnProcessingThreadERKNS_16MesTransceiverIdES3_RKNS_11MessageTypeEPvb.bin b/expected/_ZN4ksys17MessageDispatcher29sendMessageOnProcessingThreadERKNS_16MesTransceiverIdES3_RKNS_11MessageTypeEPvb.bin deleted file mode 100644 index b0c27dfedb61988456e0ab79856ca63183994499..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 236 zcmWlUJxjw-7==%A6mG1OskS20p$Imkh|sCGWbq3`5jsZjXLNBBQNe)VU+~_|%}xsb z0+-IMUkHw=G4Bv!I-K!&9!?SRRYFJ>c_!`6naM%L><;%sw=oIm16Y-c!_Kl17omKlm z-xd`N%E`GDcd8k-?;UJ@vu?fX?Z=jbBOJCa$0e(-bf!Ela5}>?U@IXu{1>VGI5BlKRFm3 zelm1A>|83vFlDNo!_NjWhMy0ZMOVG6dOQ6)kbcqUx`Ts}AqXV)f{9`08=&|LW(K1b zO3aoom>hOK5aQ_O=yCYL!RzpI+asol51GYQF)-R+TXD$Al7orC%~Yx&CW=k8mO{}U7oh|XE=@&2u&_crCR8XnD-lW#2I3)5l@0{< z+U7QUlw5L?;-SZSFkUxpgDZFtjG8$t>;GGVr}^{#e}CS4OwzJGPb#+l^GxXR#*B^| z=X6}M)NQzCEbQQyK!CeV?^xV$h9Vo($}r*k*e_c+8a#Pu+Q89onz>~+y{~If@=IR* zU4kxskNsurc_#uZLjiRj?H8j4oNprUgd!Il)2>sou(Em;orwVLhGM+F36o^dCv1D1 zK)0!1-E>WoM?cEDeYtcvKYR`q(fv{q``nYHRbF=utowsU7Jkabb%Wf0&97ggtwjSVK{s;f&P}Y(=xCR(4JGKq&4<8S=jq`yu7AOsD+R z@&LKRImkPObmoM5r{sxq7}3dIpS~rn4or3iy;|2T>V>8!t=S8;E{Z94yP)u+>+u^? zKJ!MD5$}1-{CODI=!N1+un2SxDes8%rTqN@5hBMzX@|Kmyq^cka-vT tS*qDv1oSRbU8OqBa`r6CIl|(`15G(OsgI&E_y_8`;z|Gj diff --git a/expected/_ZN4ksys3act11BaseProcMgr11forEachProcERN4sead10IDelegate1IPNS0_8BaseProcEEENS2_12TypedBitFlagINS1_10ProcFilterEiEE.bin b/expected/_ZN4ksys3act11BaseProcMgr11forEachProcERN4sead10IDelegate1IPNS0_8BaseProcEEENS2_12TypedBitFlagINS1_10ProcFilterEiEE.bin deleted file mode 100644 index cbe2f9d755a2ff0d17a1033d053170787155bfd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmex=nDOGbaF&%{{8?B2t!7*Kx0!L`H)e)amk%*ae84Qc>I*Z|s;|t9t6t52JN<<- z!^9Wt3_o8eGfey<%&_w-KaefX@Y92n;R6Sw>(3YU%qzicR@a{#jzG1-3_lO}Is8mu pVA%4onPDO`Bf}JsnYV#v{jGKb+UdITTe!>0|A!eT9$=2Y1^^R_K?48) diff --git a/expected/_ZN4ksys3act13InstParamPack6Buffer3addEPKvRKN4sead14SafeStringBaseIcEEiNS1_9EntryTypeE.bin b/expected/_ZN4ksys3act13InstParamPack6Buffer3addEPKvRKN4sead14SafeStringBaseIcEEiNS1_9EntryTypeE.bin deleted file mode 100644 index 1710998891f5875a3f9bc6842cda784517e213fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224 zcmey)FZ1JDIOEDM{!A~8EgkCzc4dvbue*obEq;1eq(0Q`p(R> z>MJwjDtSic!WAqGAupI5esb_S{CvPHzKVg-{#qtmL*)xLho4P#4wD};i>}hLWe|!7 zs?8E&n5bzuf0jq4=8p_Ehe{4b20>1sTm~CMC5NrUWP6|*4xoHkriKMro)x>i10zTG u56A!0!D<*qxIy|en1JR1)n_moEBxySx!pjRjZ@D}x|Nt`lfBH&87|O+8ROx;Y><8B9PkLF$bNh`NB?R>_%(6TCo!{sC`_7ns zbTZX0s!JE_YNE-Z#v7dK{P7Gm-JPkX4^d@_f_BpB(-)|qr6|$7R_JJ@AV;XHtfgmS z*rcLyb*5{o&kmoO&mCqnw4f|v3+BJy0WV|wgZUzHl)4FYY$w4lVVa{s*a*y{<|u*D zdp97lNVByN-J*RP`5ssl1Z7$fCLfsQtL`4@t_2`_p1QRpj#K!|=US(vyDiYM+X3=v z2fS#+k=I$nJlAU29Da}E;F@(#iFs+R5usvf`1;_Go8%h1NS0sh?H>~NN-Q)&l$m0p zBxX0L3;TdA6kFBDPre6gk#*V%O6Mb@@Or)qqVX(k%6w11737o?7<$6$aNm-)8pd$H ze7o;N9Q8`7L3wkMOwLg#i`szo7rOjj>M{~^t5(%JI26U2%n{;=HdxfCO=8iVz{bY& zD=(gr^r!&kExRSQNJTAXt@daH%40&c=MsU6nL?}=YYn4Mhh8rSBKV$rI-|O6oIJ<6D7EFLQpM-idwZJ@;bI zKP;Q_FMlRxfBSRP_7B}=)NK&d_$FX)QMZ1bZpMmk5VPd8@H6Dr?3kUHt)R?bC}LJb zqZPetYn1fo6v{7`NNfQ67jyv&65`3kObif-jiq~^-p2Wk-KYQXIEKf_M&qn$$^%7` zzOp8BZ4J(Miq@}bL(MCVKK)~befU-pQGz7X2&YWB9{Vp^Kykm@V{k7A@qEsqXDzpz z5)pvWoN(9FO(Dk*M3~$OF!&13>3uw>A)2Lig^WPD`Hg%5VTlR!VTh7>Y&hK!lK3{Kv9NPOa(}cx$vY-;khU~ zz_NXpW@{neD%VAKj-Yy|sCCZGbQr1=4#izeZzv3^Tb*|57=>pwSsVt}a|uW%D!f2L zfuwOk>m#F{% diff --git a/expected/_ZN4ksys3gdt12getFlagColorENS0_8FlagTypeE.bin b/expected/_ZN4ksys3gdt12getFlagColorENS0_8FlagTypeE.bin deleted file mode 100644 index ecec279cdaca1a3d5f93e8db6e426e3046f22b27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 360 zcmezG%y97mKf}%!%nTpi@H_0}sC56yDabI9OOatBw;{vC9!>@mkobI6hC&5Sh7b-G zh6!MG3!Q(?=VT~ER;$3l5CT@K%TRcL9l}PIpD)Q!$N&|eZ_7})fDMZpS%$&~tWa|t z844SqY!q`8f#$P7)wnVgCIH!R_rG-iIiDBRT?x!kwT3|Zp==cM1Q`k)n4oG*f%Y>( u*eGg5f&Pbz&$k5H&j1Mv4o_E<@M2(e*sBP{PC%Rt#Q&WcCLUmpzXkv+&uUr# diff --git a/expected/_ZN4ksys3gdt7ManagerC1Ev.bin b/expected/_ZN4ksys3gdt7ManagerC1Ev.bin deleted file mode 100644 index 6d62ed287f451ff2b95fbb49387a67fa3564e170..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 576 zcmXX^F=!M~5dHr)`?JC&V33F@3>+58A$Q5<5I2RFJ1z-aqg}9x>lWef6&7+A&|to3 zXCX`w4^v(t{wpMf%@!dcHX1Af!hwQfwhAH&Q34|*m-%}shCjpm@6DTGjutlcznfei zucY+xQwAUU*oJedjDIcG_5%)Tm1}jM0v%Z-8-*CQFP+M$o{816YCF=i>Vp-4(Q=smX7t<>s{h>m_Rrds%In>}lG|E|T zAK3F-q*~Sl))#4SPv&r&v3CxeL5I&^+|S&7;xS(A98hjFEJ0n{4xeNORA zpx-KhTtD-7d$#A{rJy~IxN>?Rs@Biu^2)eNy9?Lnu==HfRq{%`JU?>{#yIn8#8Eo} c&+Be;i|$}+mC>D)>0V0uXyN^vZR<|w6dhUezW@LL diff --git a/expected/_ZN4ksys3res11BoneControl6parse_EPhmPN4sead4HeapE.bin b/expected/_ZN4ksys3res11BoneControl6parse_EPhmPN4sead4HeapE.bin deleted file mode 100644 index 96650dc9ea1445c58c5401111751bbb819637be7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7664 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 diff --git a/expected/_ZN4ksys3res15ResourceMgrTask20setCompactionStoppedEb.bin b/expected/_ZN4ksys3res15ResourceMgrTask20setCompactionStoppedEb.bin deleted file mode 100644 index d66b5dcf28025be55f075dd5d942bea867886133..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104 zcmez3zi;K=YQ~j+of#%}2rmfYSl(D9%)rrokb%Lhq%OXrgN-3DqmHv<<^TVttPBhy rP%%N6SSB;Wlnf?^om&_fOge!0Z?)sfFaC#C9AJ*W24g2MGl&2HhmR@k diff --git a/expected/_ZN4ksys3res21ResourceInfoContainer21loadResourceSizeTableEv.bin b/expected/_ZN4ksys3res21ResourceInfoContainer21loadResourceSizeTableEv.bin deleted file mode 100644 index 5e3b2aad8160db8c5838c2f17e8a27c51e2c8850..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 504 zcmXw0J!lkB5dPi{Szay}Aq0znENWpc7Q%5NYjbZ^NKOe73_9ScWxUrm`G=~D{DF@qfWlY->Fuh}lUv2cGjH|sBTK*c-nO}=W8(Hl+ z*RCCf{=s|fGWV0bM%P0!{NG0Gzb*5Dk?D8Y;eFo;oL0M zau2FkkgT}~hq(9F4J4H_FmG5>b20PD+EY1T^fkYiM^w@VigJ-I*E!$kU8+E{!ul$E jz2u&Cju#v)zL~?i7I_ot!bQICg}66YjxCYipsPE3a0kDg diff --git a/expected/_ZN4ksys3res7CounterD0Ev.bin b/expected/_ZN4ksys3res7CounterD0Ev.bin deleted file mode 100644 index 41283c91..00000000 --- a/expected/_ZN4ksys3res7CounterD0Ev.bin +++ /dev/null @@ -1 +0,0 @@ -×’þ \ No newline at end of file diff --git a/expected/_ZN4ksys3res9AIProgram9finalize_Ev.bin b/expected/_ZN4ksys3res9AIProgram9finalize_Ev.bin deleted file mode 100644 index a42591158f737e423c293f3394cf51022eeccbc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188 zcmez3zi;K=YQ~j+of#&6W@cEG80Gl$Ap^q}4rYc49A{mAGB7&)d=UF@`WK)a69ax{Vv@ZeZjs+lhFgX0=5Oe^#!~R-*6ywjo)s8E_ M_#awvfI0pe0GEhKkN^Mx diff --git a/expected/_ZN4ksys3res9ModelList6parse_EPhmPN4sead4HeapE.bin b/expected/_ZN4ksys3res9ModelList6parse_EPhmPN4sead4HeapE.bin deleted file mode 100644 index 942f12b1f2c48f832ba5e53cf7558d3a8861b7a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2096 zcmai$ZD>8$b?)x|6^6KRn1ygDot=O^MClObN8d}AmcSm3O6e1{T!8}Usx*5*;!fe=TY z-D9}7HSVYQ-wPVIh$q~ihlcBt0}A^_;J>DB&vCA>0~7s9be>m+W4tPSM`7mA83BvfL*Nb+vPp5=ld9=v(l?u)OwOefBWkg%{Xmfu*Oh3HtI<2qFNQj$7Acgs zTbTU&Hq)nCy7a03t@_-1@xY67>1nO6$cz_HZIqNVc1%f8Eai?JQBv7>%KZsBi}lV+ zz7tBy_mPsiF_)gyBE?qzNUNEj&CSibf;>^grbYX%lvD8-r(fa*&EoVPZV0Ex@bz+I zfNJ%X$f^D=omdml65OFish-eXrk<&mtaA06?43q2E~+ojfAx+cquJRf4+ zH`9JCSSrPAn{;nraxBJ;TyNB8vsX`B-iSF!Ots9c|1+4^X4C#niRa}!dU3fl9f;wi zJy<}l9lH<$XT)1CwHL~yxV3(jE}C_gLA4K}_Tnt&9zlKT!J9U#2f?zgd_CwPJ(cY}&uJpSbd837Fy6f)Fl#64|@7fGk0nYbv7U4W$Gf>M<8pSq_ z`K{KTt9vtQxo)Ntn%9aEuQplxdcn3byUcEr&t}Aja9?O@h2^uM#`5`XPCRxkch*(p zvk&pOf8K%5MVhscQkcFUgwC;2P18>lfUekjLmDoq{Poi@D@ANx!i zNb`e1@Pmj0e=qnx;@@kNTFknZkAD|=Ccihse>uZ{&2FFv2{EEb&0FGYnYV9ihVt0r2Ji*>&pAF|xL%^>V*Ky;OUuO_c z{aNB{i{`DB;$yez?|gGz*MB@>zBFf=@rUFwX6gB@-Fyc7#qQ1MvBk~j@vW@KK8Lkq zM{v@P9dj5ra6gOo=dfdSkL~e6;s+6j8Bc-lq8X1CW5=v(`S^RX{9iKs8H+!G9o_U~ zh52mq%{h!u*R6g&-SWo+gLv2ZR8OkP?McmZCKq@`_)>u0)AYMCJg#n^IeUhusF!%3 fw=SRDkMDq9d=Koycfnr$;n5yF&F%6kKQ!|%!5g{N diff --git a/expected/_ZN4ksys4util10TaskThread5calc_El.bin b/expected/_ZN4ksys4util10TaskThread5calc_El.bin deleted file mode 100644 index 3e47814c18d72a33a745f34bb06114defd570cd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 624 zcmYk4KTO*|6vp3iF)|K+Bm#sGl`KWd&?$l<4+uvgEDQ*+)Cna53ArN@w5k|DurSt> zXGUjc$;Lm44Z#8&?J+QmOA-6^H|d1+SD8-$eUqI~V?AJ2hqvZc)}fKc zs&jpabXvBYQebrkz_hwq*~@{Q{wJN{nIS5;U-&DXwJ%^-IAlEDSIXb`j<9DVK8YT8%Z6?NjFI*nH9>X>==JzOz;gZ&>L-4OYqk+;pdCh4HiWs* zyj;IV-yly0t6g{(R(H0nDlkX6?xO$LEoO&#H*-E~av-PpBb{c(4_{w0K75iU@l<2s z-O)KT=LwxfcfX$KrJBDn?TVNo9%u9TPNv*OA?M0tW*_jvCC%FUe-!8VE@ix$Z1Kby H?y>eC?6efO diff --git a/expected/_ZN4ksys4util11ManagedTask12detachHandleEv.bin b/expected/_ZN4ksys4util11ManagedTask12detachHandleEv.bin deleted file mode 100644 index 7acb130605aee9ffbd17bc262dcb9388827bdf23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmex=nBn4QZib(KtC?2*ZDyGGnVDhL17?PaEBG0vBnmnF1hH=d*%@&TKRp;3ws7z| z?5vMt_{mWzFC@>&P`HqRAtWKn;b#H^!D()S#Ph8D7S6l!i$CAWzt#LJ{~l(ZsKLnafkV{sCkLa$&o9gj zs~9>Rc3!ObJN+w={f${(>oX9CGcsK0P;#)$U}7-iV_*>Z$;@B`;;&#}FzaA)_{kya z@bdw)$SMX#`)f1V7|b7ZIs7bUV-PHR^LILmIzfcGj;e;8C;t97neF88^B1%HDw&V9 zmqF$xR9F4j&&2Th05e0#E*6F<4a^MYATdcGTLH=rW@VUifC(ZV31lZg+3`R&1CZ@e z?=a~l&@2nZ6H*+^Vq6)F45lD6I2eF#<#qV^5GeNuh(Yd^XJ9De5S}k3#wey`$;`kN z#m+Esjxxi=JHP*LJ^uf{cs&@jza(d diff --git a/expected/_ZN4ksys4util13TaskQueueBase9fetchTaskEPPNS0_4TaskE.bin b/expected/_ZN4ksys4util13TaskQueueBase9fetchTaskEPPNS0_4TaskE.bin deleted file mode 100644 index 602bdf9eb3b4494f421a9735eb12b62a35c210d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 852 zcmaKqPiPZS5XR^2%ch%nkkn>1HEr4yQo6^Ir1q3Y)ml?T3Kb7x8}Q(^ITWE(vD8L_ zqJ$iR(SY%wx9%P#5%wnZ67UqHIY&<+5mcI#ywb4F+63B55082C{(Lk1zA=+R`Do3i z9X=Gb_Oe|&xZ9^SZ%bNd)1h^)3YmQhx+*X(xfth^=s+SB)z6Gq6hauMcL2h@`zpO~ zeE&3INCblGGmN|cZhcR@WbIoNvQ>boq94j{O|#gfKBfDAN&*;YQkXoY=VrX8x9)`S zhLSKg`XIU*|my}aaW+3DJ1mz}`=PPz7m!5g@wN>@XjtxTA zJ9nD3@7SQQGRwGT#Q-zvbU^ta)Gm}DQ1bmgV z{K*Os-m^nNRhZ%EP*FOp7)V~c>MY6_i<#pP23G2 zu!t-cE}CY@+wGD6KJIZ8b2X4K9K@ZPuslGYBgENY_$N%HZ!&>GmAds&^x={h`m0pd zhjH(tBXI_>cz_&x^{xKu0q6hvb68&%kpXH0YNxk4Ig7U>!h)rz`oVaFI-xEn>BKyq K#p)|vuKWWZLP5F! diff --git a/expected/_ZN4ksys4util4Task13submitRequestERNS0_11TaskRequestE.bin b/expected/_ZN4ksys4util4Task13submitRequestERNS0_11TaskRequestE.bin deleted file mode 100644 index 260277cbe105558493688347fd8d45448575fa2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 536 zcmXw0F-+S)6n%Fm=n*7T3@O4YiBySDJVq&!ryS`5Q>7|9fywR`AqK<%?NA+~C6LFi zvAc8#l^77M7$`%BF3e?1RW`_QqL%y5X{Wn)|Nr;jdzTCLV>k(O|B5Hso=CC_ME8QF zx}?mVKpFridPhf56aU_tgufA9o`>^B9=u*(ymFTr96R%iW+a>Ns$=M`a8VmtaPktA*wr!rG(3x0s#4FLO{769RP7a0svHC z5(3x0s#4FLO{769RP7a0svHC z5M@Jj-A1*uVO5Q^O*O(q z`9=$SwNNgtQ{F*fO?0zQMAk*J0A#r#`)I&Pz%NaDhrIy%^DfyV`yjAG;AG-H!T~97 z2@mFs(wFc*+ac8^uvO2}!aGj;rOaI=EPnUml;37Eg%_a>P-@SR>Z9p<${VFPz-2K? zv>XFojs~?d!je2k170Vjq{Zs#n?rCmos}Y^+;d@7+`Cp~>ddMn&D@0YCXTQcjx#fF zO=v9~W#{^!R6nBn8s@ZFA|0E(`iDj-iBywp;0ie4A&H=IV{rAy$%jBOStjS&4j)wX k`0Y2wjP#1wEh6>{iycF1FA-Gxj#d5Uz;OR}t6{A116MwrD*ylh diff --git a/expected/_ZN4ksys8VFRVec3f11updateStatsEv.bin b/expected/_ZN4ksys8VFRVec3f11updateStatsEv.bin deleted file mode 100644 index ca4bb814df2a3cddda3aa25516110ab9a375734c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192 zcmaFGFZ1W6GGp!+f2NgxtC?5+JU+_2Vl;>qA|(b|!K$>n12M?0u>1nESWddF2;>r*DA$`EMJ$x!&3fgywo$o635;L7;_-&BZ!K?Ed!fI0r! zOJ)vl4n|Hc4xl_|En~3eM+PAv-<$I(kgjD4<^a)*oZK9O9^4#ffow$}?dZYHAj$yN F4*(kd7JL8z diff --git a/expected/_ZN4sead11BitFlagUtil20findOnBitFromRight64Emi.bin b/expected/_ZN4sead11BitFlagUtil20findOnBitFromRight64Emi.bin deleted file mode 100644 index 977386103548189f0950428920c238625ca64de0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 172 zcmWlSF$%&!6hvoT1Alj`1nraZdkIMwNhR8=ovjB5Sm!9#+S`kT1iXQuSb2aDXN%99 z$1wc2#i=ql>li6;%rwDr?r``5YoFjz8EN;!aLIv5?5}q7{8+h(ajmd-P1)%WneVrq yGp?3?*9o1wdiFx5&1j{O#s^OdT_Wk4E`p?0&^!BrnUsQFGMD6(&dZI2`1cRo^(bHf diff --git a/expected/_ZN4sead11ResourceMgr6createERKNS0_9CreateArgE.bin b/expected/_ZN4sead11ResourceMgr6createERKNS0_9CreateArgE.bin deleted file mode 100644 index ab02e1021a9629b14a5b36ec13fb08057b002493..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 376 zcmZvYzfZzY5XbNOtP~6-(TIoxI=L`9KpcGh&=`%nG;su7C^n9|u!xh1n%GI5VDvR{ z!+{Ch_zPIY&4h_aNFSuZLly_8Z|?iKyWD+8p{P47pm1}F7#uUvKbjFUS(Y75o#K6sVsB($rc>1v`u+sDYp#emlnf9N{oCv RE{9lq!a8*4f4s?Z?H|dhj%fe@ diff --git a/expected/_ZN4sead11TreeMapImplIN4ksys4util13StrTreeMapKeyEE8eraseMinEPNS_11TreeMapNodeIS3_EE.bin b/expected/_ZN4sead11TreeMapImplIN4ksys4util13StrTreeMapKeyEE8eraseMinEPNS_11TreeMapNodeIS3_EE.bin deleted file mode 100644 index 619cef40a0f8d45caa78948ada3b3165f356d165..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 432 zcma)2ty0547~JHNa+gVq2)ec81<1r5pvp@SP{}h?)Z-Wg&yeVQ05muRIX zekXqjfvZ8GtH}G>?cT+!BF6@By0WDXP-yNd`B`-IX2zP{qU}}I$@{pvZHJ4y?R5kv z{w73`aF~^zk6N?x1_FDy4$Fv`xQR>X{nbU8^P3^)8mJF N{OQ%AJDhrd{sF#gimV~jNX90IogAzTh1p;>!%hum2Gfitrit}o3_m$*<2$ri83MU#xjR<>|8Hs!RF}ZO z5R#C@IPsVS!;}mmhKbnJFfszobz;OS*9g@Ax7u;#XLhF_2bklpf!GO33=={8jS>tZ E01a40uK)l5 diff --git a/expected/_ZN4sead15SZSDecompressor13DecompContext10initializeEPv.bin b/expected/_ZN4sead15SZSDecompressor13DecompContext10initializeEPv.bin deleted file mode 100644 index 882cd6d43773e8022cc98c8320a32383fe70333f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32 ncmaFCEMp`u!mv}`fT2>}gTYc>fuWKkgTa!qhGFFa=J;y>cGd_D diff --git a/expected/_ZN4sead15SZSDecompressor13DecompContextC1Ev.bin b/expected/_ZN4sead15SZSDecompressor13DecompContextC1Ev.bin deleted file mode 100644 index 314984bc1a90febb31932b62aa378ff7aff22a3f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32 mcmaFCEMp`u!mv}`fT2>}gTYc>fuWKk14!2}tUSORe+>Y4#t16_ diff --git a/expected/_ZN4sead17StringBuilderBaseIcE6appendEci.bin b/expected/_ZN4sead17StringBuilderBaseIcE6appendEci.bin deleted file mode 100644 index de42db80945b1596cb6dd22cbc5f05ce915cb330..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132 zcmV-~0DJ%TSG}q9PXVd@djhHbg8-590|2UD1ORcX0svHYB0(wEen69T0zml+1praW z0s;$40TxR?0SIeUu!t71E}r?UFd=+#+H!<+XOuwjj!Zv{Pbn2$tF_r04&ojYF}cPWRpW-h2P=_kI7jKmXd>vzWJg zL-BU5a<8`-@p_!OKRGo^!(wBHvu27>Ne}Pe6B}$YO5vW5V zXz`IIv4TI?C->C<U4P-|fI|nzEYqCZ;8;Pu z0vvO;-H)YC85~ut7ZIP+$juCqTRq~yc_W7UrS@hRCNt4Po{UEEu^7D?`!X5mr$q4W zpx98^gi~P2@;F<)o~PQK%WL)L9Zp%vkNvKW8fK1qDRr$kR7pq3EU@uy9sfFNl6_vq z9A)k%`Y3hZL-${^HIK1LrU8#+kSr&1RM^QJ$PGB$|G;to7>AsPMz!JgyDJYgFn#C6 z^-qfK+=cJdN6XGxaIGk8yT!?D!z-9~)*#K9-L!Jj6Vmg8nF-9uC>_oyjaY?Gq~E1q zq~~$I?|HnNzUSLqGins$J!fVxddSSN>JhX2 zs>jSMT2GkewVp9^YJFj5Sfy#rFlGKfhMgx^87^?xy8q;KWSGdo$UL!=iQ#956vNN? zOpH6{D*)`<X%I|6L4hcl1BoGsM9Bn*l2Pze zSZCk)&gPz5-HDd0HEu+;Cf7cL?fV;y;gL_OiX++-Y6#65UCLpPgKDkf!#>bZQZ2E$3{lzloPUS-H5ic^Lu~Z)EQQsawg! z5b}^&T~3~tp>Qz=L&yte`Bg80*h`i{NZWv6;v4paO-YOndmVsk&oDBCXtFX)<(Pn&nL|a6ML)T1KD3R26VDwhmZx02z&C73;`V14nMIDqyx1IN+^<;QVs>#!=PS@c)tswQOxI0 zdqM#-StwFgQkY0Gs7axsAw#2~D4CEeG&yU?h_Z7(ZpuDG8N*;kt=Ib1xaHkh&AETi bg>z@_ZrLL(-*|8DUYFdx;d}m1$()~GbaE>7 diff --git a/expected/_ZN4sead6hostio18curveLinear2DVec2_IfEENS_7Vector2IT_EEfPKNS0_13CurveDataInfoEPKS3_.bin b/expected/_ZN4sead6hostio18curveLinear2DVec2_IfEENS_7Vector2IT_EEfPKNS0_13CurveDataInfoEPKS3_.bin deleted file mode 100644 index 3abca45319bffea96b8f22cfa1c850e1336b8535..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188 zcmY#naM-J$pdiP^%n-uC<6y~E%NXoYDId(q$q=Y`BXbW(E|ZBNzYCv4(i g diff --git a/expected/_ZN4sead8EnumUtil15getParseTextCS_Ev.bin b/expected/_ZN4sead8EnumUtil15getParseTextCS_Ev.bin deleted file mode 100644 index d4fff1e8f854339759c48e55fe56a79fe562d015..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmey&FZbhbHRH;^&I}V@urf^GNaUNy@%KK52NQ$&10bIv0mwh`fBFGN29wV~esL1- z#0Sj6tCGzarW{~p*l>uI;Q|AX>rbaGjz1p)#aoa5pAOTv@7Vw8f2$o=LioHBKeIdi JIKUi#4FHc3Fe?B6 diff --git a/expected/_ZN4sead8EnumUtil20getInitValueArrayCS_Ev.bin b/expected/_ZN4sead8EnumUtil20getInitValueArrayCS_Ev.bin deleted file mode 100644 index b322cdff6011ec643dca2f7ba1410219be35f999..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmey&FZbhbHRH;^&I}V@urf^GXyl*B@%KK52NQ$&10bKFfq&xbO?3eG8BMpZ>SnaV3P$H}NyO K(~kqp@z((D6fs)> diff --git a/expected/_ZN4sead8JobQueueC1Ev.bin b/expected/_ZN4sead8JobQueueC1Ev.bin deleted file mode 100644 index edc2dec99c9d705366644e8707696d78b9264d47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmey&FZbhbHRH;^&I}VzvM_A;%*?Rr1S`V_O!lcWW^yt7e96i%K{M3l zCx;`$L`@)0Si~^#Av1$frV_)-dO3!j^-2soC)hDeIl;m(fn%q{#QGwjSQ*343_FIO oFPLRF)jP5MsLun60mU=)z+y%jNenyxRy(fz%jm^w`$pApDc0Ln7}`Zm=>K9cw{MY+)v58ZtD7Q`nHXWX7e*q9ztK# ziY0j!D=Q9|#F`ey5uX(m=92K$9bJ-!sGb^<*T~2glU4Y9eMF`*VcXT>y{|w16Yu zrm~2paz#@`tELupY3i+ zFK2oa&OXld7|s}a+Ruf4i5KY;DPdfW$FKkX1YMBupPB5My#5`z^f?MHToE)Q5Pw$) z)0xG`z+1p?gC79bIXLdhftP}N!E52a1MUUC%HT&GtKc$tDR>^b)WVjBtq8UbqL~%^ z7O+XBWV~HXMzBWY-~7vtX0h9*K3gAIscq@Z)i-x;_MF6SZ^Mp%5xc$>JO4!b{`uo+ LyPq3#BDU~1WWOBk diff --git a/expected/_ZNK3agl3utl14ParameterCurveILj2EE5cloneEPN4sead4HeapEPNS0_13IParameterObjE.bin b/expected/_ZNK3agl3utl14ParameterCurveILj2EE5cloneEPN4sead4HeapEPNS0_13IParameterObjE.bin deleted file mode 100644 index 504bd607be7fcaa596d5df4749a565172a18301c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 136 zcmV;30C)fYLjlqC69D=2PXnp_djzTd0|Alq0|Kh_0|2T3DS%Sq106E2a{reI1px2} zO-K0%K>(5H3jp~k1ptsK(Lwns1wi@XLjaND0|1fZ0~4zC0|2V&4*>b-CjhDE{{NSt qA_0+sA_0-&0~j(HasQX#0~MN;^dW diff --git a/expected/_ZNK3agl3utl14ParameterCurveILj4EE5cloneEPN4sead4HeapEPNS0_13IParameterObjE.bin b/expected/_ZNK3agl3utl14ParameterCurveILj4EE5cloneEPN4sead4HeapEPNS0_13IParameterObjE.bin deleted file mode 100644 index 993db8eb9032cbb617cfd41538b8348debd12a7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 284 zcmW+vJxIe)5Wbf)ZESH+jXUQTt=^wfiGRr*`1>UyM6 J#IJZb{R2zva=rin diff --git a/expected/_ZNK4ksys3act13ActorParamMgr8getParamEPKcPPNS0_10ActorParamE.bin b/expected/_ZNK4ksys3act13ActorParamMgr8getParamEPKcPPNS0_10ActorParamE.bin deleted file mode 100644 index aac1453730f7bb71df592a53aed1dcadebf252a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 620 zcmZ|NKTMiI6aesdcTx@rZ6i%UH2H?ccG1o-G(G;PQIne3OB`vZ+I%r4otiL+n}+_o zrHs(c`z8mR)wsyWV%++TL?)wEu7Y3RCk|NC>GIyYKkt`&9;40fD%F49Gu5HX+ zK3{mCd&Qvc9T4@KfipsCi#7UOT{7yNGvc^GFli`#oZ0az%fqnEXY(dWL^{r)eiJuy z=89R)SO(PAGht%mqvZ=0a}K{|Ivn>|Bx(NykS!`qD*!uZ6wD;RlTTSt-8V#YCJc`X zV7mzA1iVx)UQKZu`Uao(a9aX%E*sCbaq{!2F*qXfo97$UwiTloo-N= jM%}BpxVKlF!P%L{8Jfab%HvGsbayqYJx0|YD;)g=dwbwb diff --git a/expected/_ZNK4ksys3map6Object20getActorWithAccessorEPNS_3act24ActorLinkConstDataAccessE.bin b/expected/_ZNK4ksys3map6Object20getActorWithAccessorEPNS_3act24ActorLinkConstDataAccessE.bin deleted file mode 100644 index 796b2e843a25acf9d405e45afd65704f3466cb5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88 zcmV-e0H^=-Prj-BdjYBaLjaLz1OV^|DMk780|2T30YLfl0|BZa0RXh--Ts&0001_K u9zgl1006WJkwG~>2>@{cF`t?O000!>10SmWdqJt-0~4zBPr|5U%l;Q%+9Xf_ diff --git a/expected/_ZNK4ksys3res12ResourceUnit9isParseOkEv.bin b/expected/_ZNK4ksys3res12ResourceUnit9isParseOkEv.bin deleted file mode 100644 index b6051461268b9f2152e1ec249ef6fa05ac2ae1b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 228 zcmXwzuMYuX7{|YlH+VI>DFjEm6U}DQy*Ikebkm4_v@4=WvMHvyO9DYLB!7X#h*ypB zhBJ>KJ=^E=*|YDvzV{=K{HTiQOCYcW*2ApQ(ss3s?($41=a|8A^>O%_DME>xiG0?y z&D_3m>tbpV^uO~4pIMWz8OM~)b0dlGRq2OF1t8~Q0{xM(n8$$BLzqF=P&=oBUK?nJ z0>$Ky16wDL-jZ2|_n3rd7++)(>_TA{*l+$`f;Xg<{{5CfBl27y1mj<q!7f`2w#& BOHu#; diff --git a/expected/_ZNK4ksys3res21ResourceInfoContainer15getResourceSizeERKN4sead14SafeStringBaseIcEE.bin b/expected/_ZNK4ksys3res21ResourceInfoContainer15getResourceSizeERKN4sead14SafeStringBaseIcEE.bin deleted file mode 100644 index 847c80a1046464585122df1be56e36268dd803e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 380 zcmXAlKTN_<5XSHI0oGQc1`MGlVsxS-!Nj=m{I}>}Vn|F}$_SLDiwkMQ4O1P6CQ2M+ z!BE^xOklz=xwtapCXr3hb^yI6+k1Dv@4oNOon3Ssjo9Buf;~8(_9*YMN0gKXl+=p? zb45RMzbMqZG*}0c=oEa+jbDs!(#Nb>^gz5vBdX*D<5GZRI>y|6GA*AHF!ZXW=q3r| zO!I0clWW`)&@%wZKJpYG*e3i9F{~SV^Oh3zT1tXQx;*|(3fSkfRMbkDY(qnB3bi8E zdsJ2v==aF~Z&3@ptQi3?`X2PpPBIPA{m+>vpbi_#rIF5%dzPMJ0^6UU9eO z)%Ck~+-nKoxa4_!tM zKN&n6e}*tR{G7tTu%(;JVP`!fNA>~+h7e6whCnYxhKZX0|C{nNFo<+8IsD|1b@=&! zS!5Lhqy05`0fxedKy_eoMT9ued?Oa1dXV`bvtKaFYb7u-{QO((xbgurht?PWLn{t2 H$6o^gZyi2d diff --git a/expected/_ZNK4ksys3res9AIProgram13getSInstParamEPPKiRKNS1_10DefinitionERKN4sead14SafeStringBaseIcEE.bin b/expected/_ZNK4ksys3res9AIProgram13getSInstParamEPPKiRKNS1_10DefinitionERKN4sead14SafeStringBaseIcEE.bin deleted file mode 100644 index 6b2bbfdd69bd930095426693fdd5fe62dbe40530..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 172 zcmez3zi;K=YQ~j+of#%RU}j$Rg_&v9XJ*D#LYMzd?~HQT`GT22%afVGq|3|hy|z~WIjkQ$c_XihM#|{9albJ=Fs}$e`v)4 H=J;y>*&jY> diff --git a/expected/_ZNK4ksys3res9ActorLink6hasTagENS_3act3TagE.bin b/expected/_ZNK4ksys3res9ActorLink6hasTagENS_3act3TagE.bin deleted file mode 100644 index b2e64d381f33cb953398d6250de9c979e29e27cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmd-`aNo(r%22qPfg$7tv%Jv diff --git a/expected/_ZNK4sead8ObjArrayINS_14SafeStringBaseIcEEE12binarySearchEPKS2_.bin b/expected/_ZNK4sead8ObjArrayINS_14SafeStringBaseIcEEE12binarySearchEPKS2_.bin deleted file mode 100644 index 9e6e364d9f7141d8393b110597465d51542999ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 672 zcmey(FZJVBI^)V8@k}efg)^`G;?J`3Z#C=6zs`&kIT##ver9G|l_A7n@{L(uOG1HR zV!0B-L`hbL!d^~>5DjLA3mj`*eo8SqSZXkfamzC@6ml%>kP@k76y{)d_$hj`_i|w7-VV&w$GBW&^1a2CK;cvg?^SULRm&2w4SWzhstQ<(-*n!2`rO zj6B|N7#K|J8KtrhFffE@vNBAxXLS0={r`Um69afxg0vD>CzCb&BIDeSE0EQ39{uj&)Mxb!86rLh=jctn5eJ06l?eG6X zK;a>Bv+PF)+$|ztzoPSDZl4Nv8zMaRGjY6DU}6Z-28MYTP%ax7?%BX_2f5P+7%sd( z+{?)8{T3KD^BK9ZhK()}VFPndG1z{n8$n?MwEqDxK0x+^!UvcAx=axJ8_?qB3$qwF zd_));gdQ-9X#K5r1*SC@V48CVrah;XztSC7{$_Xkaez7g+J0d8U0F0g>f8VS;s8-% B>8t<% diff --git a/tools/dump_function.py b/tools/dump_function.py deleted file mode 100755 index f95f3b7a..00000000 --- a/tools/dump_function.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 - -import argparse - -import util.elf -from util import utils - - -def dump_fn(name: str) -> None: - expected_dir = utils.get_repo_root() / "expected" - try: - fn = util.elf.get_fn_from_my_elf(name) - path = expected_dir / f"{name}.bin" - path.parent.mkdir(exist_ok=True) - path.write_bytes(fn.data) - except KeyError: - utils.fail("could not find function") - - -def main() -> None: - parser = argparse.ArgumentParser() - parser.add_argument("function_name", help="Name of the function to dump") - args = parser.parse_args() - - dump_fn(args.function_name) - - -if __name__ == "__main__": - main() diff --git a/tools/progress.py b/tools/progress.py index 155a6572..f5166701 100755 --- a/tools/progress.py +++ b/tools/progress.py @@ -2,8 +2,6 @@ import argparse from collections import defaultdict from colorama import Back, Fore, Style -import enum -from pathlib import Path from util import utils from util.utils import FunctionStatus import typing as tp @@ -17,8 +15,6 @@ parser.add_argument("--print-eq", "-e", action="store_true", help="Print non-matching functions with minor issues") parser.add_argument("--print-ok", "-m", action="store_true", help="Print matching functions") -parser.add_argument("--hide-nonmatchings-with-dumps", "-H", help="Hide non-matching functions that have expected " - "output dumps", action="store_true") args = parser.parse_args() code_size_total = 0 @@ -26,15 +22,6 @@ num_total = 0 code_size: tp.DefaultDict[FunctionStatus, int] = defaultdict(int) counts: tp.DefaultDict[FunctionStatus, int] = defaultdict(int) -nonmatching_fns_with_dump = {p.stem for p in (Path(__file__).parent.parent / "expected").glob("*.bin")} - - -def should_hide_nonmatching(name: str) -> bool: - if not args.hide_nonmatchings_with_dumps: - return False - return name in nonmatching_fns_with_dump - - for info in utils.get_functions(): code_size_total += info.size num_total += 1 @@ -47,10 +34,10 @@ for info in utils.get_functions(): if not args.csv: if info.status == FunctionStatus.NonMatching: - if args.print_nm and not should_hide_nonmatching(info.decomp_name): + if args.print_nm: print(f"{Fore.RED}NM{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}") elif info.status == FunctionStatus.Equivalent: - if args.print_eq and not should_hide_nonmatching(info.decomp_name): + if args.print_eq: print(f"{Fore.YELLOW}EQ{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}") elif info.status == FunctionStatus.Matching: if args.print_ok: From 6e30bbea3274679c34832182dcbeb4ed1211dd16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 24 Jul 2021 20:04:26 +0200 Subject: [PATCH 2/2] tools: Add a new, optimized check tool Reimplements tools/check.py in a faster language (picked Rust to learn and play with the language and because installing dependencies is way easier than with C++) On my machine, a full run takes ~160ms with this new implementation and 49s (!) with check.py. The main performance improvements come from not having to use pyelftools and the Python bindings of Capstone (which are both insanely slow and perhaps less efficient than they could be). Function checking is now also performed in parallel rather than sequentially for yet another significant performance boost. Other tweaks include editing Capstone and the bindings to avoid computing expensive things that we don't actually need and avoiding dynamic memory allocations in hot paths as much as possible. check.py will be removed after the setup instructions are updated. --- ...seProc16isSpecialJobTypeENS0_7JobTypeE.bin | Bin 104 -> 0 bytes tools/viking/.gitignore | 1 + tools/viking/Cargo.lock | 506 +++++++++++++++++ tools/viking/Cargo.toml | 28 + tools/viking/LICENSE | 21 + tools/viking/src/capstone_utils.rs | 89 +++ tools/viking/src/checks.rs | 518 ++++++++++++++++++ tools/viking/src/elf.rs | 311 +++++++++++ tools/viking/src/functions.rs | 142 +++++ tools/viking/src/lib.rs | 6 + tools/viking/src/repo.rs | 20 + tools/viking/src/tools/check.rs | 180 ++++++ tools/viking/src/ui.rs | 59 ++ 13 files changed, 1881 insertions(+) delete mode 100644 expected/_ZN4ksys3act8BaseProc16isSpecialJobTypeENS0_7JobTypeE.bin create mode 100644 tools/viking/.gitignore create mode 100644 tools/viking/Cargo.lock create mode 100644 tools/viking/Cargo.toml create mode 100644 tools/viking/LICENSE create mode 100644 tools/viking/src/capstone_utils.rs create mode 100644 tools/viking/src/checks.rs create mode 100644 tools/viking/src/elf.rs create mode 100644 tools/viking/src/functions.rs create mode 100644 tools/viking/src/lib.rs create mode 100644 tools/viking/src/repo.rs create mode 100644 tools/viking/src/tools/check.rs create mode 100644 tools/viking/src/ui.rs diff --git a/expected/_ZN4ksys3act8BaseProc16isSpecialJobTypeENS0_7JobTypeE.bin b/expected/_ZN4ksys3act8BaseProc16isSpecialJobTypeENS0_7JobTypeE.bin deleted file mode 100644 index 11fc42ab1d482670784b263dd50b601dbcc5f1a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104 zcmez3zi;K=YQ~j+of#&6VP;s>!Q}9hBhumLXJ$q%21fg92@DJ-511K@co`T(rZ_qL z3}Iy00#oyVS!C5iW?`^8c@~Dk1ONVq$a63h9t6@4nB}$pRy(fz;(utx0p|E?05wV} AYybcN diff --git a/tools/viking/.gitignore b/tools/viking/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/tools/viking/.gitignore @@ -0,0 +1 @@ +/target diff --git a/tools/viking/Cargo.lock b/tools/viking/Cargo.lock new file mode 100644 index 00000000..93534165 --- /dev/null +++ b/tools/viking/Cargo.lock @@ -0,0 +1,506 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bstr" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "capstone" +version = "0.9.0" +source = "git+https://github.com/leoetlino/capstone-rs#1f962210b1e2ff418cf6c1bcb6c6785427662a07" +dependencies = [ + "capstone-sys", + "libc", +] + +[[package]] +name = "capstone-sys" +version = "0.13.0" +source = "git+https://github.com/leoetlino/capstone-rs#1f962210b1e2ff418cf6c1bcb6c6785427662a07" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "cc" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "cpp_demangle" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea47428dc9d2237f3c6bc134472edfd63ebba0af932e783506dcfd66f10d18a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "goblin" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b1800b95efee8ad4ef04517d4d69f8e209e763b1668f1179aeeedd0e454da55" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "lazy-init" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23517540be87a91d06324e6bf6286ba8214171123ee8862ae9a5e7d938d71815" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1b8479c593dba88c2741fc50b92e13dbabbbe0bd504d979f244ccc1a5b1c01" +dependencies = [ + "cc", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" + +[[package]] +name = "memmap" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mimalloc" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb74897ce508e6c49156fd1476fc5922cbc6e75183c65e399c765a09122e5130" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "owning_ref" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "proc-macro2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scroll" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" + +[[package]] +name = "smawk" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + +[[package]] +name = "unicode-linebreak" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a52dcaab0c48d931f7cc8ef826fa51690a08e1ea55117ef26f89864f532383f" +dependencies = [ + "regex", +] + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "viking" +version = "1.0.0" +dependencies = [ + "anyhow", + "capstone", + "colored", + "cpp_demangle", + "csv", + "goblin", + "itertools", + "lazy-init", + "memmap", + "mimalloc", + "owning_ref", + "rayon", + "rustc-hash", + "textwrap", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/tools/viking/Cargo.toml b/tools/viking/Cargo.toml new file mode 100644 index 00000000..b2d5f80e --- /dev/null +++ b/tools/viking/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "viking" +version = "1.0.0" +edition = "2018" + +[profile.release] +debug = 1 +lto = "thin" + +[dependencies] +anyhow = "1.0" +capstone = { git = "https://github.com/leoetlino/capstone-rs" } +colored = "2" +cpp_demangle = "0.3.3" +csv = "1.1" +goblin = "0.4" +itertools = "0.10.1" +lazy-init = "0.5.0" +memmap = "0.6.1" +mimalloc = { version = "*", default-features = false } +owning_ref = "0.4.1" +rayon = "1.5.1" +rustc-hash = "1.1.0" +textwrap = "0.14.2" + +[[bin]] +name = "botw-check" +path = "src/tools/check.rs" diff --git a/tools/viking/LICENSE b/tools/viking/LICENSE new file mode 100644 index 00000000..b14590d0 --- /dev/null +++ b/tools/viking/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 leoetlino + +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. diff --git a/tools/viking/src/capstone_utils.rs b/tools/viking/src/capstone_utils.rs new file mode 100644 index 00000000..e1f19e00 --- /dev/null +++ b/tools/viking/src/capstone_utils.rs @@ -0,0 +1,89 @@ +use anyhow::{bail, Result}; +use capstone as cs; +use cs::arch::arm64::{Arm64Insn, Arm64OpMem, Arm64Operand, Arm64OperandType}; +use cs::{arch::ArchOperand, RegId}; + +pub fn translate_cs_error(err: cs::Error) -> Result { + bail!("capstone error: {}", err) +} + +#[inline] +pub fn map_two<'a, T, R, F: FnMut(&'a T) -> R>(x: &'a T, y: &'a T, mut f: F) -> (R, R) { + (f(x), f(y)) +} + +#[inline] +pub fn map_pair<'a, T, R, F: FnMut(&'a T) -> R>(pair: &'a (T, T), f: F) -> (R, R) { + map_two(&pair.0, &pair.1, f) +} + +#[inline] +pub fn try_map_two<'a, T, R, F: FnMut(&'a T) -> Result>( + x: &'a T, + y: &'a T, + mut f: F, +) -> Result<(R, R)> { + Ok(( + f(x).or_else(translate_cs_error)?, + f(y).or_else(translate_cs_error)?, + )) +} + +/// Checks if `id` is in [start, end] (inclusive range). +#[inline] +pub fn is_id_in_range(start: Arm64Insn, end: Arm64Insn, id: Arm64Insn) -> bool { + let range = (start as u32)..=(end as u32); + range.contains(&(id as u32)) +} + +/// Used to make accessing arch-specific data less cumbersome. +pub trait CsArchOperandUtil { + fn arm64(&self) -> &Arm64Operand; +} + +impl CsArchOperandUtil for ArchOperand { + fn arm64(&self) -> &Arm64Operand { + match self { + Self::Arm64Operand(x) => x, + _ => unreachable!(), + } + } +} + +/// Used to make accessing arch-specific data less cumbersome. +pub trait CsArm64OperandTypeUtil { + fn reg(&self) -> RegId; + fn imm(&self) -> i64; + fn try_mem(&self) -> Option; + fn mem(&self) -> Arm64OpMem; +} + +impl CsArm64OperandTypeUtil for Arm64OperandType { + fn reg(&self) -> RegId { + match self { + Self::Reg(x) => *x, + _ => panic!("expected Reg, got {:#?}", &self), + } + } + + fn imm(&self) -> i64 { + match self { + Self::Imm(x) => *x, + _ => panic!("expected Imm, got {:#?}", &self), + } + } + + fn try_mem(&self) -> Option { + match self { + Self::Mem(x) => Some(*x), + _ => None, + } + } + + fn mem(&self) -> Arm64OpMem { + match self { + Self::Mem(x) => *x, + _ => panic!("expected Mem, got {:#?}", &self), + } + } +} diff --git a/tools/viking/src/checks.rs b/tools/viking/src/checks.rs new file mode 100644 index 00000000..ccdc8a38 --- /dev/null +++ b/tools/viking/src/checks.rs @@ -0,0 +1,518 @@ +use anyhow::{ensure, Result}; +use capstone as cs; +use cs::arch::arm64::{Arm64Insn, Arm64Operand, Arm64OperandType}; +use itertools::zip; +use lazy_init::Lazy; +use rustc_hash::FxHashMap; +use std::collections::{HashMap, HashSet}; +use std::convert::TryInto; +use std::path::{Path, PathBuf}; + +use crate::{capstone_utils::*, elf, functions, repo, ui}; + +struct DataSymbol { + /// Address of the symbol in the original executable. + pub addr: u64, + /// Name of the symbol in our source code. + pub name: String, + /// Size of the symbol in our source code (according to ELF info). + pub size: u64, +} + +/// Keeps track of known data symbols so that data loads can be validated. +#[derive(Default)] +struct KnownDataSymbolMap { + /// Symbols. Must be sorted by address. + symbols: Vec, +} + +impl KnownDataSymbolMap { + fn new() -> Self { + Default::default() + } + + fn load(&mut self, csv_path: &Path, decomp_symtab: &elf::SymbolTableByName) -> Result<()> { + let mut reader = csv::ReaderBuilder::new() + .has_headers(false) + .quoting(false) + .from_path(csv_path)?; + for (line, maybe_record) in reader.records().enumerate() { + let record = &maybe_record?; + ensure!( + record.len() == 2, + "invalid number of fields on line {}", + line + ); + + let addr = functions::parse_address(&record[0])?; + let name = &record[1]; + + let symbol = decomp_symtab.get(name); + // Ignore missing symbols. + if symbol.is_none() { + continue; + } + let symbol = symbol.unwrap(); + + self.symbols.push(DataSymbol { + addr, + name: name.to_string(), + size: symbol.st_size, + }); + } + self.symbols.sort_by_key(|sym| sym.addr); + Ok(()) + } + + /// If addr is part of a known data symbol, this function returns the corresponding symbol. + fn get_symbol(&self, addr: u64) -> Option<&DataSymbol> { + // Perform a binary search since `symbols` is sorted. + let mut a: isize = 0; + let mut b: isize = self.symbols.len() as isize - 1; + while a <= b { + let m = a + (b - a) / 2; + + let mid_symbol = &self.symbols[m as usize]; + let mid_addr_begin = mid_symbol.addr; + let mid_addr_end = mid_addr_begin + mid_symbol.size as u64; + + if mid_addr_begin <= addr && addr < mid_addr_end { + return Some(mid_symbol); + } + if addr <= mid_addr_begin { + b = m - 1; + } else if addr >= mid_addr_end { + a = m + 1; + } else { + break; + } + } + None + } +} + +fn get_data_symbol_csv_path() -> Result { + let mut path = repo::get_repo_root()?; + path.push("data"); + path.push("data_symbols.csv"); + Ok(path) +} + +#[derive(Debug)] +pub struct ReferenceDiff { + pub referenced_symbol: u64, + pub expected_ref_in_decomp: u64, + pub actual_ref_in_decomp: u64, + + pub expected_symbol_name: String, + pub actual_symbol_name: String, +} + +impl std::fmt::Display for ReferenceDiff { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "wrong reference to {ref} {ref_name}\n\ + --> decomp source code is referencing {actual} {actual_name}\n\ + --> expected to see {expected} to match original code", + ref=ui::format_address(self.referenced_symbol), + ref_name=ui::format_symbol_name(&self.expected_symbol_name), + expected=ui::format_address(self.expected_ref_in_decomp), + actual=ui::format_address(self.actual_ref_in_decomp), + actual_name=ui::format_symbol_name(&self.actual_symbol_name), + ) + } +} + +#[derive(Debug)] +pub enum MismatchCause { + FunctionSize, + Register, + Mnemonic, + BranchTarget, + FunctionCall(ReferenceDiff), + DataReference(ReferenceDiff), + Immediate, + Unknown, +} + +impl std::fmt::Display for MismatchCause { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self { + Self::FunctionSize => write!(f, "wrong function size"), + Self::Register => write!(f, "wrong register"), + Self::Mnemonic => write!(f, "wrong mnemonic"), + Self::BranchTarget => write!(f, "wrong branch target"), + Self::FunctionCall(diff) => write!(f, "wrong function call\n{}", diff), + Self::DataReference(diff) => write!(f, "wrong data reference\n{}", diff), + Self::Immediate => write!(f, "wrong immediate"), + Self::Unknown => write!(f, "unknown reason; check diff.py"), + } + } +} + +#[derive(Debug)] +pub struct Mismatch { + pub addr_orig: u64, + pub addr_decomp: u64, + pub cause: MismatchCause, +} + +impl std::fmt::Display for Mismatch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "mismatch at {}: {}", + ui::format_address(self.addr_orig), + self.cause, + ) + } +} + +pub struct FunctionChecker<'a, 'functions, 'orig_elf, 'decomp_elf> { + decomp_elf: &'decomp_elf elf::OwnedElf, + decomp_symtab: &'a elf::SymbolTableByName<'decomp_elf>, + decomp_glob_data_table: elf::GlobDataTable, + + // Optional, only initialized when a mismatch is detected. + decomp_addr_to_name_map: Lazy>, + + known_data_symbols: KnownDataSymbolMap, + known_functions: FxHashMap, + + orig_elf: &'orig_elf elf::OwnedElf, + orig_got_section: &'orig_elf goblin::elf::SectionHeader, +} + +impl<'a, 'functions, 'orig_elf, 'decomp_elf> + FunctionChecker<'a, 'functions, 'orig_elf, 'decomp_elf> +{ + pub fn new( + orig_elf: &'orig_elf elf::OwnedElf, + decomp_elf: &'decomp_elf elf::OwnedElf, + decomp_symtab: &'a elf::SymbolTableByName<'decomp_elf>, + decomp_glob_data_table: elf::GlobDataTable, + functions: &'functions [functions::Info], + ) -> Result { + let mut known_data_symbols = KnownDataSymbolMap::new(); + known_data_symbols.load(get_data_symbol_csv_path()?.as_path(), &decomp_symtab)?; + + let known_functions = functions::make_known_function_map(functions); + let orig_got_section = elf::find_section(orig_elf, ".got")?; + + Ok(FunctionChecker { + decomp_elf, + decomp_symtab, + decomp_glob_data_table, + decomp_addr_to_name_map: Lazy::new(), + + known_data_symbols, + known_functions, + + orig_elf, + orig_got_section, + }) + } + + pub fn check( + &self, + cs: &mut cs::Capstone, + orig_fn: &elf::Function, + decomp_fn: &elf::Function, + ) -> Result> { + // Keep track of registers that are used with ADRP so that we can check global data + // references even when data is not placed at the same addresses + // as in the original executable. + #[derive(Default)] + struct State { + gprs1: HashMap, + gprs2: HashMap, + adrp_pair_registers: HashSet, + } + + impl State { + fn forget_modified_registers(&mut self, detail: &cs::InsnDetail) { + for reg in detail.regs_write() { + self.adrp_pair_registers.remove(®); + } + } + } + + let mut state = State::default(); + + if orig_fn.code.len() != decomp_fn.code.len() { + return Ok(Some(Mismatch { + addr_orig: orig_fn.addr, + addr_decomp: decomp_fn.addr, + cause: MismatchCause::FunctionSize, + })); + } + + let mut instructions = try_map_two(&orig_fn, &decomp_fn, |func| { + cs.disasm_iter(func.code, func.addr) + })?; + + // Check every pair of instructions. + while let (Some(i1), Some(i2)) = (instructions.0.next(), instructions.1.next()) { + let ids = map_two(&i1, &i2, |i| i.id().0); + let detail = try_map_two(&i1, &i2, |insn| cs.insn_detail(&insn))?; + let arch_detail = map_pair(&detail, |d| d.arch_detail()); + let ops = map_pair(&arch_detail, |a| a.arm64().unwrap().operands_ref()); + + if ids.0 != ids.1 { + return Self::make_mismatch(&i1, &i2, MismatchCause::Mnemonic); + } + + let id = ids.0; + + match id.into() { + // Branches or function calls. + Arm64Insn::ARM64_INS_B | Arm64Insn::ARM64_INS_BL => { + let target = + map_pair(&ops, |ops| Arm64Operand::from(&ops[0]).op_type.imm() as u64); + + // If we are branching outside the function, this is likely a tail call. + // Treat it as a function call. + if !orig_fn.get_addr_range().contains(&target.0) { + if let Some(mismatch_cause) = self.check_function_call(target.0, target.1) { + return Self::make_mismatch(&i1, &i2, mismatch_cause); + } + } else { + // Otherwise, it's a simple branch, and both targets must match. + if i1.bytes() != i2.bytes() { + return Self::make_mismatch(&i1, &i2, MismatchCause::BranchTarget); + } + } + } + + // Catch ADRP + (ADD/load/store) instruction pairs. + Arm64Insn::ARM64_INS_ADRP => { + let reg = map_pair(&ops, |ops| Arm64Operand::from(&ops[0]).op_type.reg()); + let imm = + map_pair(&ops, |ops| Arm64Operand::from(&ops[1]).op_type.imm() as u64); + + if reg.0 != reg.1 { + return Self::make_mismatch(&i1, &i2, MismatchCause::Register); + } + + state.gprs1.insert(reg.0, imm.0); + state.gprs2.insert(reg.1, imm.1); + state.adrp_pair_registers.insert(reg.0); + } + + // Catch ADRP + ADD instruction pairs. + Arm64Insn::ARM64_INS_ADD => { + let mut diff_ok = false; + + if ops.0.len() == 3 { + let dest_reg = + map_pair(&ops, |ops| Arm64Operand::from(&ops[0]).op_type.reg()); + let reg = map_pair(&ops, |ops| Arm64Operand::from(&ops[1]).op_type.reg()); + + if let Arm64OperandType::Imm(_) = Arm64Operand::from(&ops.0[2]).op_type { + let imm = + map_pair(&ops, |ops| Arm64Operand::from(&ops[2]).op_type.imm()); + + if dest_reg.0 != dest_reg.1 || reg.0 != reg.1 { + return Self::make_mismatch(&i1, &i2, MismatchCause::Register); + } + + // Is this an ADRP pair we can check? + if state.adrp_pair_registers.contains(®.0) { + let orig_addr = state.gprs1[®.0] + imm.0 as u64; + let decomp_addr = state.gprs2[®.1] + imm.1 as u64; + + if let Some(mismatch_cause) = + self.check_data_symbol(orig_addr, decomp_addr) + { + return Self::make_mismatch(&i1, &i2, mismatch_cause); + } + + // If the data symbol reference matches, allow the instructions to be different. + diff_ok = true; + } + } + } + + if !diff_ok && i1.bytes() != i2.bytes() { + return Self::make_mismatch(&i1, &i2, MismatchCause::Unknown); + } + + state.forget_modified_registers(&detail.0); + } + + // Loads and stores (single or paired). + id if is_id_in_range(Arm64Insn::ARM64_INS_LD1, Arm64Insn::ARM64_INS_LDXRH, id) + || is_id_in_range(Arm64Insn::ARM64_INS_ST1, Arm64Insn::ARM64_INS_STXR, id) => + { + let mut diff_ok = false; + + // Check all operands for mismatches, except the Arm64OpMem which will be checked later. + let mut mem = (None, None); + for (op1, op2) in zip(ops.0, ops.1) { + let op1 = Arm64Operand::from(op1); + let op2 = Arm64Operand::from(op2); + if let Some(mem1) = op1.op_type.try_mem() { + if let Some(mem2) = op2.op_type.try_mem() { + ensure!( + mem.0.is_none() && mem.1.is_none(), + "found more than one OpMem" + ); + mem.0 = Some(mem1); + mem.1 = Some(mem2); + continue; + } + } + + if op1 != op2 { + return Self::make_mismatch(&i1, &i2, MismatchCause::Unknown); + } + } + + ensure!(mem.0.is_some() && mem.1.is_some(), "didn't find an OpMem"); + + let mem = (mem.0.unwrap(), mem.1.unwrap()); + + if mem.0.base() != mem.1.base() { + return Self::make_mismatch(&i1, &i2, MismatchCause::Register); + } + + let reg = mem.0.base(); + + // Is this an ADRP pair we can check? + if state.adrp_pair_registers.contains(®) { + let orig_addr_ptr = (state.gprs1[®] as i64 + mem.0.disp() as i64) as u64; + let decomp_addr_ptr = + (state.gprs2[®] as i64 + mem.1.disp() as i64) as u64; + + if let Some(mismatch_cause) = + self.check_data_symbol_ptr(orig_addr_ptr, decomp_addr_ptr) + { + return Self::make_mismatch(&i1, &i2, mismatch_cause); + } + + // If the data symbol reference matches, allow the instructions to be different. + diff_ok = true; + } + + if !diff_ok && i1.bytes() != i2.bytes() { + return Self::make_mismatch(&i1, &i2, MismatchCause::Unknown); + } + + state.forget_modified_registers(&detail.0); + } + + // Anything else. + _ => { + if i1.bytes() != i2.bytes() { + return Self::make_mismatch(&i1, &i2, MismatchCause::Unknown); + } + + state.forget_modified_registers(&detail.0); + } + } + } + + Ok(None) + } + + /// Returns None on success and a MismatchCause on failure. + fn check_function_call(&self, orig_addr: u64, decomp_addr: u64) -> Option { + let info = *self.known_functions.get(&orig_addr)?; + let name = info.name.as_str(); + let decomp_symbol = self.decomp_symtab.get(name)?; + let expected = decomp_symbol.st_value; + + if decomp_addr == expected { + None + } else { + let actual_symbol_name = self.translate_decomp_addr_to_name(decomp_addr); + + Some(MismatchCause::FunctionCall(ReferenceDiff { + referenced_symbol: orig_addr, + expected_ref_in_decomp: expected, + actual_ref_in_decomp: decomp_addr, + expected_symbol_name: name.to_string(), + actual_symbol_name: actual_symbol_name.unwrap_or("unknown").to_string(), + })) + } + } + + /// Returns None on success and a MismatchCause on failure. + fn check_data_symbol_ex( + &self, + orig_addr: u64, + decomp_addr: u64, + symbol: &DataSymbol, + ) -> Option { + let decomp_symbol = self.decomp_symtab.get(symbol.name.as_str())?; + let expected = decomp_symbol.st_value; + + if decomp_addr == expected { + None + } else { + let actual_symbol_name = self.translate_decomp_addr_to_name(decomp_addr); + + Some(MismatchCause::DataReference(ReferenceDiff { + referenced_symbol: orig_addr, + expected_ref_in_decomp: expected, + actual_ref_in_decomp: decomp_addr, + expected_symbol_name: symbol.name.to_string(), + actual_symbol_name: actual_symbol_name.unwrap_or("unknown").to_string(), + })) + } + } + + /// Returns None on success and a MismatchCause on failure. + fn check_data_symbol(&self, orig_addr: u64, decomp_addr: u64) -> Option { + let symbol = self.known_data_symbols.get_symbol(orig_addr)?; + self.check_data_symbol_ex(orig_addr, decomp_addr, symbol) + } + + /// Returns None on success and a MismatchCause on failure. + /// Unlike check_data_symbol, this function takes the addresses of *pointers to* possible data symbols, + /// not the symbols themselves. + fn check_data_symbol_ptr( + &self, + orig_addr_ptr: u64, + decomp_addr_ptr: u64, + ) -> Option { + if !elf::is_in_section(&self.orig_got_section, orig_addr_ptr, 8) { + return None; + } + + let orig_offset = elf::get_offset_in_file(&self.orig_elf, orig_addr_ptr).ok()? as u64; + let orig_addr = u64::from_le_bytes( + elf::get_elf_bytes(&self.orig_elf, orig_offset, 8) + .ok()? + .try_into() + .ok()?, + ); + + let data_symbol = self.known_data_symbols.get_symbol(orig_addr)?; + let decomp_addr = *self.decomp_glob_data_table.get(&decomp_addr_ptr)?; + self.check_data_symbol_ex(orig_addr, decomp_addr, &data_symbol) + } + + fn make_mismatch( + i1: &cs::Insn, + i2: &cs::Insn, + cause: MismatchCause, + ) -> Result> { + Ok(Some(Mismatch { + addr_orig: i1.address(), + addr_decomp: i2.address(), + cause, + })) + } + + #[cold] + #[inline(never)] + fn translate_decomp_addr_to_name(&self, decomp_addr: u64) -> Option<&'decomp_elf str> { + let map = self.decomp_addr_to_name_map.get_or_create(|| { + let map = elf::make_addr_to_name_map(&self.decomp_elf).ok(); + map.unwrap_or_default() + }); + map.get(&decomp_addr).copied() + } +} diff --git a/tools/viking/src/elf.rs b/tools/viking/src/elf.rs new file mode 100644 index 00000000..b289c8a4 --- /dev/null +++ b/tools/viking/src/elf.rs @@ -0,0 +1,311 @@ +use std::{collections::HashMap, ffi::CStr, fs::File, ops::Range, path::Path}; + +use anyhow::{anyhow, bail, Context, Result}; +use goblin::{ + container, + elf::{ + dynamic, reloc, section_header, sym, Dynamic, Elf, ProgramHeader, RelocSection, + SectionHeader, Sym, Symtab, + }, + elf64::program_header::PT_LOAD, + strtab::Strtab, +}; +use memmap::{Mmap, MmapOptions}; +use owning_ref::OwningHandle; +use rustc_hash::FxHashMap; + +use crate::repo; + +pub type OwnedElf = OwningHandle, Mmap)>, Box>>; +pub type SymbolTableByName<'a> = HashMap<&'a str, goblin::elf::Sym>; +pub type SymbolTableByAddr = FxHashMap; +pub type AddrToNameMap<'a> = FxHashMap; +pub type GlobDataTable = FxHashMap; + +pub struct Function<'a> { + /// The virtual address of the function in its containing executable. + /// *Note*: does not contain the IDA base (0x7100000000). + pub addr: u64, + /// The bytes that make up the code for this function. + pub code: &'a [u8], +} + +impl<'a> Function<'a> { + #[inline] + pub fn get_addr_range(&self) -> Range { + self.addr..(self.addr + self.code.len() as u64) + } +} + +#[inline] +fn make_goblin_ctx() -> container::Ctx { + // 64-bit, little endian + container::Ctx::new(container::Container::Big, container::Endian::Little) +} + +/// A stripped down version of `goblin::elf::Elf::parse`, parsing only the sections that we need. +/// +/// *Warning*: In particular, `strtab`, `dynstrtab`, `soname` and `libraries` are **not** parsed. +fn parse_elf_faster(bytes: &[u8]) -> Result { + let header = Elf::parse_header(bytes)?; + let mut elf = Elf::lazy_parse(header)?; + let ctx = make_goblin_ctx(); + + elf.program_headers = + ProgramHeader::parse(bytes, header.e_phoff as usize, header.e_phnum as usize, ctx)?; + + elf.section_headers = + SectionHeader::parse(bytes, header.e_shoff as usize, header.e_shnum as usize, ctx)?; + + let get_strtab = |section_headers: &[SectionHeader], section_idx: usize| { + if section_idx >= section_headers.len() { + Ok(Strtab::default()) + } else { + let shdr = §ion_headers[section_idx]; + shdr.check_size(bytes.len())?; + Strtab::parse(bytes, shdr.sh_offset as usize, shdr.sh_size as usize, 0x0) + } + }; + + let strtab_idx = header.e_shstrndx as usize; + elf.shdr_strtab = get_strtab(&elf.section_headers, strtab_idx)?; + + for shdr in &elf.section_headers { + if shdr.sh_type as u32 == section_header::SHT_SYMTAB { + let size = shdr.sh_entsize; + let count = if size == 0 { 0 } else { shdr.sh_size / size }; + elf.syms = Symtab::parse(bytes, shdr.sh_offset as usize, count as usize, ctx)?; + } + } + + elf.dynamic = Dynamic::parse(bytes, &elf.program_headers, ctx)?; + if let Some(ref dynamic) = elf.dynamic { + let dyn_info = &dynamic.info; + // parse the dynamic relocations + elf.dynrelas = RelocSection::parse(bytes, dyn_info.rela, dyn_info.relasz, true, ctx)?; + elf.dynrels = RelocSection::parse(bytes, dyn_info.rel, dyn_info.relsz, false, ctx)?; + let is_rela = dyn_info.pltrel as u64 == dynamic::DT_RELA; + elf.pltrelocs = + RelocSection::parse(bytes, dyn_info.jmprel, dyn_info.pltrelsz, is_rela, ctx)?; + } + + Ok(elf) +} + +pub fn load_elf(path: &Path) -> Result { + let file = Box::new(File::open(path)?); + let mmap = unsafe { MmapOptions::new().map(&file)? }; + + OwningHandle::try_new(Box::new((file, mmap)), |pair| unsafe { + let elf = parse_elf_faster(&(*pair).1).with_context(|| "failed to load ELF")?; + Ok(Box::new(elf)) + }) +} + +pub fn load_orig_elf() -> Result { + let mut path = repo::get_repo_root()?; + path.push("data"); + path.push("main.elf"); + load_elf(path.as_path()) +} + +pub fn load_decomp_elf() -> Result { + let mut path = repo::get_repo_root()?; + path.push("build"); + path.push("uking"); + load_elf(path.as_path()) +} + +struct SymbolStringTable<'elf> { + bytes: &'elf [u8], +} + +impl<'elf> SymbolStringTable<'elf> { + pub fn from_elf(elf: &'elf OwnedElf) -> Result { + let bytes = &*elf.as_owner().1; + for shdr in &elf.section_headers { + if shdr.sh_type as u32 == section_header::SHT_SYMTAB { + let table_hdr = elf + .section_headers + .get(shdr.sh_link as usize) + .ok_or_else(|| anyhow!("symbol string table index out of bounds"))?; + + table_hdr.check_size(bytes.len())?; + + let start = table_hdr.sh_offset as usize; + let end = start + table_hdr.sh_size as usize; + return Ok(SymbolStringTable { + bytes: &bytes[start..end], + }); + } + } + bail!("couldn't find symbol string table") + } + + pub fn get_string(&self, offset: usize) -> &'elf str { + unsafe { + std::str::from_utf8_unchecked( + CStr::from_ptr(self.bytes[offset..self.bytes.len()].as_ptr() as *const i8) + .to_bytes(), + ) + } + } +} + +fn filter_out_useless_syms(sym: &Sym) -> bool { + matches!( + sym.st_type(), + sym::STT_OBJECT | sym::STT_FUNC | sym::STT_COMMON | sym::STT_TLS + ) +} + +pub fn make_symbol_map_by_name(elf: &OwnedElf) -> Result { + let mut map = SymbolTableByName::with_capacity_and_hasher( + elf.syms.iter().filter(filter_out_useless_syms).count(), + Default::default(), + ); + + let strtab = SymbolStringTable::from_elf(&elf)?; + + for symbol in elf.syms.iter().filter(filter_out_useless_syms) { + map.entry(strtab.get_string(symbol.st_name)) + .or_insert(symbol); + } + Ok(map) +} + +pub fn make_symbol_map_by_addr(elf: &OwnedElf) -> SymbolTableByAddr { + let mut map = SymbolTableByAddr::with_capacity_and_hasher( + elf.syms.iter().filter(filter_out_useless_syms).count(), + Default::default(), + ); + for symbol in elf.syms.iter().filter(filter_out_useless_syms) { + map.entry(symbol.st_value).or_insert(symbol); + } + map +} + +pub fn make_addr_to_name_map(elf: &OwnedElf) -> Result { + let mut map = AddrToNameMap::with_capacity_and_hasher( + elf.syms.iter().filter(filter_out_useless_syms).count(), + Default::default(), + ); + + let strtab = SymbolStringTable::from_elf(&elf)?; + + for symbol in elf.syms.iter().filter(filter_out_useless_syms) { + map.entry(symbol.st_value) + .or_insert_with(|| strtab.get_string(symbol.st_name)); + } + Ok(map) +} + +fn parse_symtab<'a>(elf: &'a OwnedElf, shdr: &'a SectionHeader) -> Result> { + let bytes = &elf.as_owner().1; + let size = shdr.sh_entsize; + let count = if size == 0 { 0 } else { shdr.sh_size / size }; + + let syms = Symtab::parse( + bytes, + shdr.sh_offset as usize, + count as usize, + make_goblin_ctx(), + )?; + Ok(syms) +} + +pub fn find_section<'a>(elf: &'a OwnedElf, name: &str) -> Result<&'a SectionHeader> { + elf.section_headers + .iter() + .find(|&header| &elf.shdr_strtab[header.sh_name] == name) + .ok_or_else(|| anyhow!("failed to find {} section", name)) +} + +pub fn get_linked_section<'a>( + elf: &'a OwnedElf, + shdr: &'a SectionHeader, +) -> Result<&'a SectionHeader> { + elf.section_headers + .get(shdr.sh_link as usize) + .ok_or_else(|| anyhow!("could not get linked section")) +} + +#[inline] +pub fn is_in_section(section: &SectionHeader, addr: u64, size: u64) -> bool { + let begin = section.sh_addr; + let end = begin + section.sh_size; + (begin..end).contains(&addr) && (begin..=end).contains(&(addr + size)) +} + +pub fn build_glob_data_table(elf: &OwnedElf) -> Result { + let section = &elf.dynrelas; + let section_hdr = find_section(elf, ".rela.dyn")?; + // The corresponding symbol table. + let symtab = parse_symtab(elf, get_linked_section(elf, §ion_hdr)?)?; + + let mut table = GlobDataTable::with_capacity_and_hasher(section.len(), Default::default()); + + for reloc in section.iter() { + let symbol_value: u64 = symtab + .get(reloc.r_sym) + .ok_or_else(|| anyhow!("invalid symbol index"))? + .st_value; + + match reloc.r_type { + reloc::R_AARCH64_GLOB_DAT => { + table.insert( + reloc.r_offset, + (symbol_value as i64 + reloc.r_addend.unwrap()) as u64, + ); + } + reloc::R_AARCH64_RELATIVE => { + // FIXME: this should be Delta(S) + A. + table.insert( + reloc.r_offset, + (symbol_value as i64 + reloc.r_addend.unwrap()) as u64, + ); + } + _ => (), + } + } + + Ok(table) +} + +pub fn get_offset_in_file(elf: &OwnedElf, addr: u64) -> Result { + let addr = addr as usize; + for segment in elf.program_headers.iter() { + if segment.p_type != PT_LOAD { + continue; + } + + if segment.vm_range().contains(&addr) { + return Ok(segment.file_range().start + addr - segment.vm_range().start); + } + } + bail!("{:#x} doesn't belong to any segment", addr) +} + +pub fn get_elf_bytes(elf: &OwnedElf, addr: u64, size: u64) -> Result<&[u8]> { + let offset = get_offset_in_file(&elf, addr)?; + let size = size as usize; + Ok(&elf.as_owner().1[offset..(offset + size)]) +} + +pub fn get_function(elf: &OwnedElf, addr: u64, size: u64) -> Result { + Ok(Function { + addr, + code: get_elf_bytes(&elf, addr, size)?, + }) +} + +pub fn get_function_by_name<'a>( + elf: &'a OwnedElf, + symbols: &SymbolTableByName, + name: &str, +) -> Result> { + let symbol = symbols + .get(&name) + .ok_or_else(|| anyhow!("unknown function: {}", name))?; + get_function(&elf, symbol.st_value, symbol.st_size) +} diff --git a/tools/viking/src/functions.rs b/tools/viking/src/functions.rs new file mode 100644 index 00000000..1529396f --- /dev/null +++ b/tools/viking/src/functions.rs @@ -0,0 +1,142 @@ +use crate::repo; +use anyhow::{bail, ensure, Context, Result}; +use rustc_hash::FxHashMap; +use std::path::{Path, PathBuf}; + +pub enum Status { + Matching, + NonMatchingMinor, + NonMatchingMajor, + NotDecompiled, + Library, +} + +pub struct Info { + pub addr: u64, + pub size: u32, + pub name: String, + pub status: Status, +} + +impl Info { + pub fn is_decompiled(&self) -> bool { + !matches!(self.status, Status::NotDecompiled | Status::Library) + } +} + +pub const ADDRESS_BASE: u64 = 0x71_0000_0000; + +fn parse_base_16(value: &str) -> Result { + if let Some(stripped) = value.strip_prefix("0x") { + Ok(u64::from_str_radix(stripped, 16)?) + } else { + Ok(u64::from_str_radix(value, 16)?) + } +} + +pub fn parse_address(value: &str) -> Result { + Ok(parse_base_16(value)? - ADDRESS_BASE) +} + +fn parse_function_csv_entry(record: &csv::StringRecord) -> Result { + ensure!(record.len() == 4, "invalid record"); + + let addr = parse_address(&record[0])?; + let status_code = record[1].chars().next(); + let size = record[2].parse::()?; + let decomp_name = record[3].to_string(); + + let status = match status_code { + Some('m') => Status::NonMatchingMinor, + Some('M') => Status::NonMatchingMajor, + Some('O') => Status::Matching, + Some('U') => Status::NotDecompiled, + Some('L') => Status::Library, + Some(code) => bail!("unexpected status code: {}", code), + None => bail!("missing status code"), + }; + + Ok(Info { + addr, + size, + name: decomp_name, + status, + }) +} + +pub fn get_functions_csv_path() -> Result { + let mut path = repo::get_repo_root()?; + path.push("data"); + path.push("uking_functions.csv"); + Ok(path) +} + +/// Returns a Vec of all functions that are listed in the specified CSV. +pub fn get_functions_for_path(csv_path: &Path) -> Result> { + let mut reader = csv::ReaderBuilder::new() + .has_headers(false) + .quoting(false) + .from_path(csv_path)?; + + // We build the result array manually without using csv iterators for performance reasons. + let mut result = Vec::with_capacity(110_000); + let mut record = csv::StringRecord::new(); + let mut line_number = 1; + if reader.read_record(&mut record)? { + // Verify that the CSV has the correct format. + ensure!(record.len() == 4, "invalid record; expected 4 fields"); + ensure!( + &record[0] == "Address" + && &record[1] == "Quality" + && &record[2] == "Size" + && &record[3] == "Name", + "wrong CSV format; this program only works with the new function list format (added in commit 1d4c815fbae3)" + ); + line_number += 1; + } + + while reader.read_record(&mut record)? { + result.push( + parse_function_csv_entry(&record) + .with_context(|| format!("failed to parse CSV record at line {}", line_number))?, + ); + line_number += 1; + } + Ok(result) +} + +/// Returns a Vec of all known functions in the executable. +pub fn get_functions() -> Result> { + get_functions_for_path(get_functions_csv_path()?.as_path()) +} + +pub fn make_known_function_map(functions: &[Info]) -> FxHashMap { + let mut known_functions = + FxHashMap::with_capacity_and_hasher(functions.len(), Default::default()); + + for function in functions { + if !function.is_decompiled() { + continue; + } + known_functions.insert(function.addr, function); + } + + known_functions +} + +/// Demangle a C++ symbol. +pub fn demangle_str(name: &str) -> Result { + if !name.starts_with("_Z") { + bail!("not an external mangled name"); + } + + let symbol = cpp_demangle::Symbol::new(name)?; + let options = cpp_demangle::DemangleOptions::new(); + Ok(symbol.demangle(&options)?) +} + +pub fn get_expected_dir_path() -> Result { + let mut path = repo::get_repo_root()?; + path.push("expected"); + Ok(path) +} diff --git a/tools/viking/src/lib.rs b/tools/viking/src/lib.rs new file mode 100644 index 00000000..cf6378b6 --- /dev/null +++ b/tools/viking/src/lib.rs @@ -0,0 +1,6 @@ +pub mod capstone_utils; +pub mod checks; +pub mod elf; +pub mod functions; +pub mod repo; +pub mod ui; diff --git a/tools/viking/src/repo.rs b/tools/viking/src/repo.rs new file mode 100644 index 00000000..b08528c6 --- /dev/null +++ b/tools/viking/src/repo.rs @@ -0,0 +1,20 @@ +use anyhow::{bail, Result}; +use std::path::PathBuf; + +pub fn get_repo_root() -> Result { + let current_dir = std::env::current_dir()?; + let mut dir = current_dir.as_path(); + + loop { + if ["data", "src"].iter().all(|name| dir.join(name).is_dir()) { + return Ok(dir.to_path_buf()); + } + + match dir.parent() { + None => { + bail!("failed to find repo root -- run this program inside the repo"); + } + Some(parent) => dir = parent, + }; + } +} diff --git a/tools/viking/src/tools/check.rs b/tools/viking/src/tools/check.rs new file mode 100644 index 00000000..3bae256f --- /dev/null +++ b/tools/viking/src/tools/check.rs @@ -0,0 +1,180 @@ +use anyhow::bail; +use anyhow::Context; +use anyhow::Result; +use capstone as cs; +use capstone::arch::BuildsCapstone; +use colored::*; +use rayon::prelude::*; +use std::cell::RefCell; +use std::sync::atomic::AtomicBool; +use viking::checks::FunctionChecker; +use viking::elf; +use viking::functions; +use viking::functions::Status; +use viking::ui; + +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +/// Returns false if the program should exit with a failure code at the end. +fn check_function( + checker: &FunctionChecker, + mut cs: &mut capstone::Capstone, + orig_elf: &elf::OwnedElf, + decomp_elf: &elf::OwnedElf, + decomp_symtab: &elf::SymbolTableByName, + function: &functions::Info, +) -> Result { + if !function.is_decompiled() { + return Ok(true); + } + + let name = function.name.as_str(); + let decomp_fn = elf::get_function_by_name(&decomp_elf, &decomp_symtab, &name); + + if decomp_fn.is_err() { + let error = decomp_fn.err().unwrap(); + ui::print_warning(&format!( + "couldn't check {}: {}", + ui::format_symbol_name(name), + error.to_string().dimmed(), + )); + return Ok(true); + } + + let decomp_fn = decomp_fn.unwrap(); + + let get_orig_fn = || { + elf::get_function(&orig_elf, function.addr, function.size as u64).with_context(|| { + format!( + "failed to get function {} ({}) from the original executable", + name, + ui::format_address(function.addr), + ) + }) + }; + + match function.status { + Status::Matching => { + let orig_fn = get_orig_fn()?; + + let result = checker + .check(&mut cs, &orig_fn, &decomp_fn) + .with_context(|| format!("checking {}", name))?; + + if let Some(mismatch) = result { + let stderr = std::io::stderr(); + let mut lock = stderr.lock(); + ui::print_error_ex( + &mut lock, + &format!( + "function {} is marked as matching but does not match", + ui::format_symbol_name(name), + ), + ); + ui::print_detail_ex(&mut lock, &format!("{}", mismatch)); + return Ok(false); + } + } + + Status::NonMatchingMinor | Status::NonMatchingMajor => { + let orig_fn = get_orig_fn()?; + + let result = checker + .check(&mut cs, &orig_fn, &decomp_fn) + .with_context(|| format!("checking {}", name))?; + + if result.is_none() { + ui::print_note(&format!( + "function {} is marked as non-matching but matches", + ui::format_symbol_name(name), + )); + } + } + + Status::NotDecompiled | Status::Library => unreachable!(), + }; + + Ok(true) +} + +#[cold] +#[inline(never)] +fn make_cs() -> Result { + cs::Capstone::new() + .arm64() + .mode(cs::arch::arm64::ArchMode::Arm) + .detail(true) + .build() + .or_else(viking::capstone_utils::translate_cs_error) +} + +thread_local! { + static CAPSTONE: RefCell = RefCell::new(make_cs().unwrap()); +} + +fn main() -> Result<()> { + let orig_elf = elf::load_orig_elf().with_context(|| "failed to load original ELF")?; + let decomp_elf = elf::load_decomp_elf().with_context(|| "failed to load decomp ELF")?; + + // Load these in parallel. + let mut decomp_symtab = None; + let mut decomp_glob_data_table = None; + let mut functions = None; + + rayon::scope(|s| { + s.spawn(|_| decomp_symtab = Some(elf::make_symbol_map_by_name(&decomp_elf))); + s.spawn(|_| decomp_glob_data_table = Some(elf::build_glob_data_table(&decomp_elf))); + s.spawn(|_| functions = Some(functions::get_functions())); + }); + + let decomp_symtab = decomp_symtab + .unwrap() + .with_context(|| "failed to make symbol map")?; + + let decomp_glob_data_table = decomp_glob_data_table + .unwrap() + .with_context(|| "failed to make global data table")?; + + let functions = functions + .unwrap() + .with_context(|| "failed to load function CSV")?; + + let checker = FunctionChecker::new( + &orig_elf, + &decomp_elf, + &decomp_symtab, + decomp_glob_data_table, + &functions, + ) + .with_context(|| "failed to construct FunctionChecker")?; + + let failed = AtomicBool::new(false); + + functions.par_iter().try_for_each(|function| { + CAPSTONE.with(|cs| -> Result<()> { + let mut cs = cs.borrow_mut(); + let ok = check_function( + &checker, + &mut cs, + &orig_elf, + &decomp_elf, + &decomp_symtab, + function, + )?; + if !ok { + failed.store(true, std::sync::atomic::Ordering::Relaxed); + } + + Ok(()) + }) + })?; + + if failed.load(std::sync::atomic::Ordering::Relaxed) { + bail!("found at least one error"); + } else { + Ok(()) + } +} diff --git a/tools/viking/src/ui.rs b/tools/viking/src/ui.rs new file mode 100644 index 00000000..725dc6d0 --- /dev/null +++ b/tools/viking/src/ui.rs @@ -0,0 +1,59 @@ +use colored::*; +use std::io::StderrLock; +use std::io::Write; +use textwrap::indent; + +use crate::functions; + +pub fn print_note(msg: &str) { + eprintln!("{}{}{}", "note".bold().cyan(), ": ".bold(), msg.bold()) +} + +pub fn print_warning(msg: &str) { + eprintln!("{}{}{}", "warning".bold().yellow(), ": ".bold(), msg.bold()) +} + +pub fn print_error(msg: &str) { + let stderr = std::io::stderr(); + let mut lock = stderr.lock(); + print_error_ex(&mut lock, msg); +} + +pub fn print_error_ex(lock: &mut StderrLock, msg: &str) { + writeln!( + lock, + "{}{}{}", + "error".bold().red(), + ": ".bold(), + msg.bold() + ) + .unwrap(); +} + +pub fn format_symbol_name(name: &str) -> String { + functions::demangle_str(name).map_or(name.blue().to_string(), |demangled| { + format!("{} ({})", demangled.blue(), name.blue().dimmed(),) + }) +} + +pub fn format_address(addr: u64) -> String { + format!("{:#x}", addr).green().to_string() +} + +pub fn print_detail(msg: &str) { + let stderr = std::io::stderr(); + let mut lock = stderr.lock(); + print_detail_ex(&mut lock, msg); +} + +pub fn print_detail_ex(lock: &mut StderrLock, msg: &str) { + writeln!( + lock, + "{}\n", + indent( + &msg.clear().to_string(), + &" │ ".bold().dimmed().to_string() + ) + ) + .unwrap(); +}