You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.7 KiB
139 lines
4.7 KiB
8 years ago
|
(*
|
||
|
* Copyright (c) 2009 - 2013 Monoidics ltd.
|
||
|
* Copyright (c) 2013 - present Facebook, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* This source code is licensed under the BSD style license found in the
|
||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||
|
*)
|
||
|
|
||
|
(** The Smallfoot Intermediate Language: Decompiled Expressions *)
|
||
|
open! IStd
|
||
|
module L = Logging
|
||
|
module F = Format
|
||
|
|
||
|
(** expression representing the result of decompilation *)
|
||
|
type t =
|
||
|
| Darray of t * t
|
||
|
| Dbinop of Binop.t * t * t
|
||
|
| Dconst of Const.t
|
||
|
| Dsizeof of Typ.t * t option * Subtype.t
|
||
|
| Dderef of t
|
||
|
| Dfcall of t * t list * Location.t * CallFlags.t
|
||
|
| Darrow of t * Typ.Fieldname.t
|
||
|
| Ddot of t * Typ.Fieldname.t
|
||
|
| Dpvar of Pvar.t
|
||
|
| Dpvaraddr of Pvar.t
|
||
|
| Dunop of Unop.t * t
|
||
|
| Dunknown
|
||
|
| Dretcall of t * t list * Location.t * CallFlags.t
|
||
|
|
||
|
(** Value paths: identify an occurrence of a value in a symbolic heap
|
||
|
each expression represents a path, with Dpvar being the simplest one *)
|
||
|
type vpath = t option
|
||
|
|
||
|
let java () = Config.equal_language !Config.curr_language Config.Java
|
||
|
|
||
|
let eradicate_java () = Config.eradicate && java ()
|
||
|
|
||
|
(** convert a dexp to a string *)
|
||
|
let rec to_string = function
|
||
|
| Darray (de1, de2)
|
||
|
-> to_string de1 ^ "[" ^ to_string de2 ^ "]"
|
||
|
| Dbinop (op, de1, de2)
|
||
|
-> "(" ^ to_string de1 ^ Binop.str Pp.text op ^ to_string de2 ^ ")"
|
||
|
| Dconst Cfun pn
|
||
|
-> Typ.Procname.to_simplified_string pn
|
||
|
| Dconst c
|
||
|
-> Const.to_string c
|
||
|
| Dderef de
|
||
|
-> "*" ^ to_string de
|
||
|
| Dfcall (fun_dexp, args, _, {cf_virtual= isvirtual})
|
||
|
-> let pp_arg fmt de = F.fprintf fmt "%s" (to_string de) in
|
||
|
let pp_args fmt des =
|
||
|
if eradicate_java () then ( if des <> [] then F.fprintf fmt "..." )
|
||
|
else Pp.comma_seq pp_arg fmt des
|
||
|
in
|
||
|
let pp_fun fmt = function
|
||
|
| Dconst Cfun pname
|
||
|
-> let s =
|
||
|
match pname with
|
||
|
| Typ.Procname.Java pname_java
|
||
|
-> Typ.Procname.java_get_method pname_java
|
||
|
| _
|
||
|
-> Typ.Procname.to_string pname
|
||
|
in
|
||
|
F.fprintf fmt "%s" s
|
||
|
| de
|
||
|
-> F.fprintf fmt "%s" (to_string de)
|
||
|
in
|
||
|
let receiver, args' =
|
||
|
match args with
|
||
|
| (Dpvar pv) :: args' when isvirtual && Pvar.is_this pv
|
||
|
-> (None, args')
|
||
|
| a :: args' when isvirtual
|
||
|
-> (Some a, args')
|
||
|
| _
|
||
|
-> (None, args)
|
||
|
in
|
||
|
let pp fmt =
|
||
|
let pp_receiver fmt = function None -> () | Some arg -> F.fprintf fmt "%a." pp_arg arg in
|
||
|
F.fprintf fmt "%a%a(%a)" pp_receiver receiver pp_fun fun_dexp pp_args args'
|
||
|
in
|
||
|
F.asprintf "%t" pp
|
||
|
| Darrow (Dpvar pv, f) when Pvar.is_this pv
|
||
|
-> (* this->fieldname *)
|
||
|
Typ.Fieldname.to_simplified_string f
|
||
|
| Darrow (de, f)
|
||
|
-> if Typ.Fieldname.is_hidden f then to_string de
|
||
|
else if java () then to_string de ^ "." ^ Typ.Fieldname.to_flat_string f
|
||
|
else to_string de ^ "->" ^ Typ.Fieldname.to_string f
|
||
|
| Ddot (Dpvar _, fe) when eradicate_java ()
|
||
|
-> (* static field access *)
|
||
|
Typ.Fieldname.to_simplified_string fe
|
||
|
| Ddot (de, f)
|
||
|
-> if Typ.Fieldname.is_hidden f then "&" ^ to_string de
|
||
|
else if java () then to_string de ^ "." ^ Typ.Fieldname.to_flat_string f
|
||
|
else to_string de ^ "." ^ Typ.Fieldname.to_string f
|
||
|
| Dpvar pv
|
||
|
-> Mangled.to_string (Pvar.get_name pv)
|
||
|
| Dpvaraddr pv
|
||
|
-> let s =
|
||
|
if eradicate_java () then Pvar.get_simplified_name pv
|
||
|
else Mangled.to_string (Pvar.get_name pv)
|
||
|
in
|
||
|
let ampersand = if eradicate_java () then "" else "&" in
|
||
|
ampersand ^ s
|
||
|
| Dunop (op, de)
|
||
|
-> Unop.str op ^ to_string de
|
||
|
| Dsizeof (typ, _, _)
|
||
|
-> F.asprintf "%a" (Typ.pp_full Pp.text) typ
|
||
|
| Dunknown
|
||
|
-> "unknown"
|
||
|
| Dretcall (de, _, _, _)
|
||
|
-> "returned by " ^ to_string de
|
||
|
|
||
|
(** Pretty print a dexp. *)
|
||
|
let pp fmt de = F.fprintf fmt "%s" (to_string de)
|
||
|
|
||
|
(** Pretty print a value path *)
|
||
|
let pp_vpath pe fmt vpath =
|
||
|
let pp fmt = function Some de -> pp fmt de | None -> () in
|
||
|
if Pp.equal_print_kind pe.Pp.kind Pp.HTML then
|
||
|
F.fprintf fmt " %a{vpath: %a}%a" Io_infer.Html.pp_start_color Pp.Orange pp vpath
|
||
|
Io_infer.Html.pp_end_color ()
|
||
|
else F.fprintf fmt "%a" pp vpath
|
||
|
|
||
|
let rec has_tmp_var = function
|
||
|
| Dpvar pvar | Dpvaraddr pvar
|
||
|
-> Pvar.is_frontend_tmp pvar
|
||
|
| Dderef dexp | Ddot (dexp, _) | Darrow (dexp, _) | Dunop (_, dexp) | Dsizeof (_, Some dexp, _)
|
||
|
-> has_tmp_var dexp
|
||
|
| Darray (dexp1, dexp2) | Dbinop (_, dexp1, dexp2)
|
||
|
-> has_tmp_var dexp1 || has_tmp_var dexp2
|
||
|
| Dretcall (dexp, dexp_list, _, _) | Dfcall (dexp, dexp_list, _, _)
|
||
|
-> has_tmp_var dexp || List.exists ~f:has_tmp_var dexp_list
|
||
|
| Dconst _ | Dunknown | Dsizeof (_, None, _)
|
||
|
-> false
|