|
|
|
(*
|
|
|
|
* 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 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 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
|