From 48a5a100fa2dce23f5fb31f58e222430db4465e3 Mon Sep 17 00:00:00 2001 From: Henny Sipma Date: Wed, 30 Sep 2026 22:51:45 -0700 Subject: [PATCH] CHB:ARM: add disassembly-level callgraph --- CodeHawk/CHB/bchanalyze/bCHFileIO.ml | 13 ++++++++++ CodeHawk/CHB/bchanalyze/bCHFileIO.mli | 1 + CodeHawk/CHB/bchcmdline/bCHXBinaryAnalyzer.ml | 10 +++++++- CodeHawk/CHB/bchlib/bCHCallgraph.ml | 24 +++++++++++++++++-- CodeHawk/CHB/bchlib/bCHPreFileIO.ml | 8 +++++++ CodeHawk/CHB/bchlib/bCHPreFileIO.mli | 1 + CodeHawk/CHB/bchlib/bCHVersion.ml | 4 ++-- .../CHB/bchlibarm32/bCHARMAssemblyFunction.ml | 24 +++++++++++++++++-- .../bchlibarm32/bCHFnARMTypeConstraints.ml | 3 +++ 9 files changed, 81 insertions(+), 7 deletions(-) diff --git a/CodeHawk/CHB/bchanalyze/bCHFileIO.ml b/CodeHawk/CHB/bchanalyze/bCHFileIO.ml index c9bc0b8c1..2812d780e 100644 --- a/CodeHawk/CHB/bchanalyze/bCHFileIO.ml +++ b/CodeHawk/CHB/bchanalyze/bCHFileIO.ml @@ -187,6 +187,19 @@ let save_arm_functions_list () = end +let save_arm_callgraph () = + let filename = get_callgraph_filename () in + let doc = xmlDocument () in + let root = get_bch_root "callgraph" in + let cNode = xmlElement "callgraph" in + let callgraph = BCHARMAssemblyFunctions.arm_assembly_functions#get_callgraph in + begin + callgraph#write_xml cNode; + doc#setNode root; + root#appendChildren [cNode]; + file_output#saveFile filename doc#toPretty + end + let save_global_state () = let filename = get_global_state_filename () in diff --git a/CodeHawk/CHB/bchanalyze/bCHFileIO.mli b/CodeHawk/CHB/bchanalyze/bCHFileIO.mli index 9511e6c70..76810e11e 100644 --- a/CodeHawk/CHB/bchanalyze/bCHFileIO.mli +++ b/CodeHawk/CHB/bchanalyze/bCHFileIO.mli @@ -41,6 +41,7 @@ val save_functions_list: unit -> unit (** save function cfg info for arm functions *) val save_arm_functions_list: unit -> unit +val save_arm_callgraph: unit -> unit val save_global_state: unit -> unit val save_global_memory_map: unit -> unit diff --git a/CodeHawk/CHB/bchcmdline/bCHXBinaryAnalyzer.ml b/CodeHawk/CHB/bchcmdline/bCHXBinaryAnalyzer.ml index c18dd1a85..b5b7209d8 100644 --- a/CodeHawk/CHB/bchcmdline/bCHXBinaryAnalyzer.ml +++ b/CodeHawk/CHB/bchcmdline/bCHXBinaryAnalyzer.ml @@ -116,6 +116,7 @@ let add_print_datasection (s: string) = print_datasections := s :: !print_datasections let save_asm_cfg_info = ref false (* save functions list with cfg info in xml *) +let save_asm_callgraph = ref false (* save callgraph edges based on disassembly *) let set_datablocks = ref false (* only supported for arm *) let construct_all_functions = ref false @@ -226,6 +227,8 @@ let speclist = "save assembly listing in the analysis directory"); ("-save_asm_cfg_info", Arg.Unit (fun () -> save_asm_cfg_info := true), "save list of functions with cfg info to xml file (may be slow)"); + ("-save_asm_callgraph", Arg.Unit (fun () -> save_asm_callgraph := true), + "save list of callgraph edges based on disassembly only in xml"); ("-print_datasection", Arg.String (fun s -> add_print_datasection s), "print the data sections as part of the assembly listing"); ("-construct_all_functions", @@ -618,7 +621,12 @@ let main () = (if !save_asm_cfg_info then begin save_arm_functions_list (); - pr_timing [STR "function cfg info saved"] + pr_timing [STR "function cfg info saved"]; + end); + (if !save_asm_callgraph then + begin + save_arm_callgraph (); + pr_timing [STR "callgraph saved"] end); save_system_info (); pr_timing [STR "system_info saved"]; diff --git a/CodeHawk/CHB/bchlib/bCHCallgraph.ml b/CodeHawk/CHB/bchlib/bCHCallgraph.ml index 51e2812de..26102a610 100644 --- a/CodeHawk/CHB/bchlib/bCHCallgraph.ml +++ b/CodeHawk/CHB/bchlib/bCHCallgraph.ml @@ -151,6 +151,7 @@ object ('a) method get_constraint : xpr_t method get_stack_arguments : (int * xpr_t) list method get_register_arguments: (variable_t * xpr_t) list + method write_xml : xml_element_int -> unit (* printing *) method toPretty : pretty_t @@ -223,7 +224,7 @@ class callgraph_edge_t (callsite:ctxt_iaddress_t) (_argExprs:(int * string * xpr_t) list) :callgraph_edge_int = -object (_:'a) +object (self:'a) method compare (other:'a) = let l0 = src#compare other#get_source in @@ -246,6 +247,18 @@ object (_:'a) method get_register_arguments = [] + method write_xml (node: xml_element_int) = + let set = node#setAttribute in + let seta t a = set t a#to_hex_string in + let tgtinfo = new callgraph_node_info_t self#get_target in + let tgtnode = xmlElement "tgt" in + begin + seta "src" self#get_source; + set "cs" self#get_callsite; + tgtinfo#write_xml tgtnode; + node#appendChildren [tgtnode] + end + method toPretty = LBLOCK [ src#toPretty ; STR " -> " ; callgraph_node_to_pretty tgt ; STR " @ " ; @@ -349,7 +362,14 @@ object (self) let eNode = xmlElement "edges" in let edges = ref [] in let _ = out_n#iter (fun _ s -> edges := s#toList @ !edges) in - node#appendChildren [ eNode ] + let _ = + List.iter (fun e -> + let edgenode = xmlElement "edge" in + begin + e#write_xml edgenode; + eNode#appendChildren [edgenode] + end) !edges in + node#appendChildren [eNode] end diff --git a/CodeHawk/CHB/bchlib/bCHPreFileIO.ml b/CodeHawk/CHB/bchlib/bCHPreFileIO.ml index 9d15ef264..063b1a637 100644 --- a/CodeHawk/CHB/bchlib/bCHPreFileIO.ml +++ b/CodeHawk/CHB/bchlib/bCHPreFileIO.ml @@ -328,6 +328,14 @@ let get_functions_filename () = let _ = create_directory fdir in Filename.concat fdir (exename ^ "_functions.xml") + +let get_callgraph_filename () = + let exename = get_filename () in + let fdir = get_analysis_dir () in + let _ = create_directory fdir in + Filename.concat fdir (exename ^ "_callgraph.xml") + + let get_function_filename (fname:string) (ext:string) = let exename = get_filename () in let fdir = get_analysis_dir () in diff --git a/CodeHawk/CHB/bchlib/bCHPreFileIO.mli b/CodeHawk/CHB/bchlib/bCHPreFileIO.mli index 5a7eb3f00..5da4070c7 100644 --- a/CodeHawk/CHB/bchlib/bCHPreFileIO.mli +++ b/CodeHawk/CHB/bchlib/bCHPreFileIO.mli @@ -55,6 +55,7 @@ val get_pwr_dictionary_filename: unit -> string val get_pwr_assembly_instructions_filename: unit -> string val get_functions_filename: unit -> string +val get_callgraph_filename: unit -> string val get_global_state_filename: unit -> string val get_global_memory_map_filename: unit -> string val get_system_info_filename: unit -> string diff --git a/CodeHawk/CHB/bchlib/bCHVersion.ml b/CodeHawk/CHB/bchlib/bCHVersion.ml index 939115dc5..59556f6ea 100644 --- a/CodeHawk/CHB/bchlib/bCHVersion.ml +++ b/CodeHawk/CHB/bchlib/bCHVersion.ml @@ -95,8 +95,8 @@ end let version = new version_info_t - ~version:"0.6.0_20260909" - ~date:"2026-0909" + ~version:"0.6.0_20260930" + ~date:"2026-09-30" ~licensee: None ~maxfilesize: None () diff --git a/CodeHawk/CHB/bchlibarm32/bCHARMAssemblyFunction.ml b/CodeHawk/CHB/bchlibarm32/bCHARMAssemblyFunction.ml index 1d42306f8..b5095a986 100644 --- a/CodeHawk/CHB/bchlibarm32/bCHARMAssemblyFunction.ml +++ b/CodeHawk/CHB/bchlibarm32/bCHARMAssemblyFunction.ml @@ -229,8 +229,28 @@ object (self) List.iter (fun (b:arm_assembly_block_int) -> b#itera (fun iaddr instr -> f faddr iaddr instr)) self#get_blocks - method populate_callgraph (_callgraph: callgraph_int) = - self#iteri (fun _ _iaddr _instr -> ()) + method populate_callgraph (callgraph: callgraph_int) = + let finfo = BCHFunctionInfo.get_function_info faddr in + self#iteri (fun _ iaddr instr -> + match instr#get_opcode with + | BranchLink _ + | BranchLinkExchange _ + | Branch _ -> + if finfo#has_call_target iaddr then + let rec add_call_target tgt = + match tgt with + | StubTarget (SOFunction name) + | StaticStubTarget (_, SOFunction name) -> + callgraph#add_so_edge faddr name iaddr [] + | AppTarget a -> callgraph#add_app_edge faddr a iaddr [] + | UnknownTarget -> + callgraph#add_unresolved_edge faddr (-1) iaddr [] + | IndirectTarget (_, tgts) -> List.iter add_call_target tgts + | _ -> () in + add_call_target (finfo#get_call_target iaddr)#get_target + else + () + | _ -> () ) method includes_instruction_address (va:doubleword_int) = List.exists (fun b -> b#includes_instruction_address va) blocks diff --git a/CodeHawk/CHB/bchlibarm32/bCHFnARMTypeConstraints.ml b/CodeHawk/CHB/bchlibarm32/bCHFnARMTypeConstraints.ml index e683bbe47..a3bd115af 100644 --- a/CodeHawk/CHB/bchlibarm32/bCHFnARMTypeConstraints.ml +++ b/CodeHawk/CHB/bchlibarm32/bCHFnARMTypeConstraints.ml @@ -1632,6 +1632,9 @@ object (self) ) rmdefs); end + | ReverseSubtract (_, _, rd, _, _, _) -> + regvar_type_introduction "RSB" rd + | SignedMultiplyLong (_, _, rdlo, rdhi, rn, rm) -> let rdloreg = rdlo#to_register in let lhslotypevar = mk_reglhs_typevar rdloreg faddr iaddr in