66import subprocess
77import os
88from gtirb .cfg import EdgeType , EdgeLabel
9- from typing import List , Dict , Tuple
9+ from typing import List , Dict , Tuple , Union
1010
1111
1212ex_dir = Path ("./examples/" )
@@ -688,17 +688,24 @@ def check_edges(
688688 def check_plt_edges (
689689 self ,
690690 module : gtirb .Module ,
691- plt_calls : List [Tuple [str , EdgeLabel , EdgeLabel , str ]],
691+ plt_calls : List [
692+ Tuple [Union [str , gtirb .CodeBlock ], EdgeLabel , EdgeLabel , str ]
693+ ],
694+ is_proxy_target : bool = False ,
692695 ) -> None :
693696 """
694697 Check that each call represented in `plt_calls` has the right
695698 sequences of edges that lead to the expected target.
696699
697700 Each element in `plt_call` is a tuple with a starting
698- symbol, two edge labels, and a target symbol.
701+ symbol name or source block , two edge labels, and a target symbol.
699702 """
700703 for src , edge_label1 , edge_label2 , tgt in plt_calls :
701- src_block = next (module .symbols_named (src )).referent
704+ src_block = (
705+ next (module .symbols_named (src )).referent
706+ if isinstance (src , str )
707+ else src
708+ )
702709 edges = [
703710 edge
704711 for edge in src_block .outgoing_edges
@@ -710,19 +717,24 @@ def check_plt_edges(
710717 f"Expected one edge with label { edge_label1 } from { src } " ,
711718 )
712719 plt_block = edges [0 ].target
713- self .assertEqual (plt_block .section .name , ".plt" )
720+ self .assertIn (plt_block .section .name , [ ".plt" , ".plt.sec" ] )
714721 edges_plt = [
715722 edge
716723 for edge in plt_block .outgoing_edges
717724 if edge .label == edge_label2
718725 ]
726+
719727 self .assertEqual (
720728 len (edges_plt ),
721729 1 ,
722730 f"Expected one edge with label { edge_label2 } "
723731 f"from block at { plt_block .address :0x} called from { src } " ,
724732 )
725733 tgt_block = edges_plt [0 ].target
734+
735+ if is_proxy_target :
736+ self .assertIsInstance (tgt_block , gtirb .ProxyBlock )
737+
726738 self .assertIn (tgt , [s .name for s in tgt_block .references ])
727739
728740 @unittest .skipUnless (
@@ -1094,6 +1106,43 @@ def test_arm64_calls(self):
10941106 ]
10951107 self .check_plt_edges (m , plt_calls )
10961108
1109+ @unittest .skipUnless (
1110+ platform .system () == "Linux" , "This test is linux only."
1111+ )
1112+ def test_x86_64_plt_cfg_edge (self ):
1113+ """
1114+ Test that a CFG edge is created from a PLT block to its external
1115+ target (ProxyBlock) when the PLT block and the target have
1116+ the same symbol.
1117+ """
1118+ binary = Path ("ex" )
1119+ with cd (ex_dir / "ex_plt_cfg_edge" ):
1120+ self .assertTrue (compile ("gcc" , "g++" , "-O0" , ["--save-temps" ]))
1121+ ir_library = disassemble (binary ).ir ()
1122+ m = ir_library .modules [0 ]
1123+
1124+ main_sym = next (m .symbols_named ("main" ))
1125+ main_block = main_sym .referent
1126+
1127+ fallthrough = [
1128+ edge
1129+ for edge in main_block .outgoing_edges
1130+ if edge .label .type == EdgeType .Fallthrough
1131+ ]
1132+ self .assertEqual (1 , len (fallthrough ))
1133+
1134+ call_fun_block = fallthrough [0 ].target
1135+
1136+ plt_calls = [
1137+ (
1138+ call_fun_block ,
1139+ EdgeLabel (EdgeType .Call , False , True ),
1140+ EdgeLabel (EdgeType .Branch , False , False ),
1141+ "fun" ,
1142+ ),
1143+ ]
1144+ self .check_plt_edges (m , plt_calls , True )
1145+
10971146
10981147if __name__ == "__main__" :
10991148 unittest .main ()
0 commit comments