diff --git a/Makefile b/Makefile
index 0dd665f826204332ab4022ab8055f520d83ff2a7..b99afea518b664558478423dade71ea554e0a325 100644
--- a/Makefile
+++ b/Makefile
@@ -825,6 +825,8 @@ PLUGIN_EXTRA_DIRS:=engine values domains api domains/cvalue domains/apron \
 	domains/gauges domains/equality legacy partitioning utils gui_files \
 	api values/numerors domains/numerors
 PLUGIN_TESTS_DIRS+=value/traces
+PLUGIN_GENERATED:=$(PLUGIN_DIR)/Eva.mli
+PLUGIN_DISTRIB_EXTERNAL+=gen-api.sh
 
 # Files for the binding to Apron domains. Only available if Apron is available.
 ifeq ($(HAS_APRON),yes)
@@ -908,7 +910,7 @@ PLUGIN_CMO:= partitioning/split_strategy domains/domain_mode value_parameters \
 	domains/taint_domain \
 	$(APRON_CMO) $(NUMERORS_CMO) \
 	api/general_requests api/values_request \
-	utils/unit_tests
+	utils/unit_tests utils/results
 PLUGIN_CMI:= values/abstract_value values/abstract_location \
 	domains/abstract_domain domains/simpler_domains
 PLUGIN_DEPENDENCIES:=Server
@@ -927,8 +929,26 @@ VALUE_TYPES:=$(addprefix src/plugins/value_types/,\
 PLUGIN_TYPES_CMO:=$(VALUE_TYPES)
 PLUGIN_TYPES_TODOC:=$(addsuffix .mli,$(VALUE_TYPES))
 
+# Eva API.
+API_MLI := $(addprefix $(PLUGIN_DIR)/, \
+  engine/analysis.mli utils/results.mli \
+  value_parameters.mli utils/eva_annotations.mli \
+  eval.mli domains/cvalue/builtins.mli \
+  legacy/eval_terms.mli utils/value_results.mli utils/unit_tests.mli)
+
+$(PLUGIN_DIR)/Eva.mli: $(PLUGIN_DIR)/gen-api.sh Makefile $(API_MLI)
+	$(PRINT_MAKING) $@
+	$(RM) $@ $@.tmp
+	$< $(API_MLI) > $@.tmp
+	$(CHMOD_RO) $@.tmp
+	$(MV) $@.tmp $@
+
+clean::
+	$(RM) $(PLUGIN_DIR)/Eva.mli
+
 $(eval $(call include_generic_plugin_Makefile,$(PLUGIN_NAME)))
 
+
 #########
 # Reduc #
 #########
diff --git a/doc/developer/advance.tex b/doc/developer/advance.tex
index 508230d7c8c933b49215876099e358da74ff20ed..906403ec31d7d23a95bc4be30992c333c53901f1 100644
--- a/doc/developer/advance.tex
+++ b/doc/developer/advance.tex
@@ -2487,10 +2487,10 @@ following.
 ~
 
 \begin{ocamlcode}
-!Db.Value.compute();
-Kernel.feedback "%B" (Db.Value.is_computed ()); (* true *)
+Eva.Analysis.compute();
+Kernel.feedback "%B" (Eva.Analysis.is_computed ()); (* true *)
 Globals.set_entry_point "f" true;
-Kernel.feedback "%B" (Db.Value.is_computed ()); (* false *)
+Kernel.feedback "%B" (Eva.Analysis.is_computed ()); (* false *)
 \end{ocamlcode}
 As the value analysis has been automatically reset when setting the entry point,
 the above code outputs
@@ -2548,7 +2548,7 @@ let compute_info (kf,vi) = ...
 let memoize s =
   try Stmt.Hashtbl.find state s
   with Not_found -> Stmt.Hashtbl.add state s (compute_info s)
-let run () = ... !Db.Value.compute (); ... memoize some_stmt ...
+let run () = ... Eva.Analysis.compute (); ... memoize some_stmt ...
 \end{ocamlcode}
 
 However, if one puts this code inside \framac, it does not work because this
@@ -2570,7 +2570,7 @@ module State =
      end)
 let compute_info (kf,vi) = ...
 let memoize = State.memo compute_info
-let run () = ... !Db.Value.compute (); ... memoize some_stmt ...
+let run () = ... Eva.Analysis.compute (); ... memoize some_stmt ...
 \end{ocamlcode}
 A quick look on this code shows that the declaration of the state itself is more
 complicated (it uses a functor application) but its use is
@@ -2870,14 +2870,14 @@ value analysis has never been computed previously)
 \scodeidx{Project}{IOError}
 \begin{ocamlcode}
 let print_computed () =
-  Kernel.feedback "%B" (Db.Value.is_computed ())
+  Kernel.feedback "%B" (Eva.Analysis.is_computed ())
 in
 print_computed ();   (* false *)
 let old = Project.current () in
 try
   let foo = Project.load ~name:"foo" "foo.sav" in
   Project.set_current foo;
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   print_computed ();   (* true *)
   Project.set_current old;
   print_computed ()    (* false *)
@@ -2913,13 +2913,13 @@ The following code is equivalent to the one given in
 Example~\ref{ex:set_current}.
 \begin{ocamlcode}
 let print_computed () =
-  Value_parameters.feedback "%B" (Db.Value.is_computed ())
+  Value_parameters.feedback "%B" (Eva.Analysis.is_computed ())
 in
 print_computed ();   (* false *)
 try
   let foo = Project.load ~name:"foo" "foo.sav" in
   Project.on foo
-    (fun () -> !Db.Value.compute (); print_computed () (* true *)) ();
+    (fun () -> Eva.Analysis.compute (); print_computed () (* true *)) ();
   print_computed ()    (* false *)
 with Project.IOError _ ->
   exit 1
diff --git a/doc/developer/check_api/run.oracle b/doc/developer/check_api/run.oracle
index 769847618c69cf2f9ca6f482711374dd559b3953..c5b9bea960a39741875927a46cfaee4c321bb3ec 100644
--- a/doc/developer/check_api/run.oracle
+++ b/doc/developer/check_api/run.oracle
@@ -96,7 +96,7 @@ Logic_utils.expr_to_term/cast:bool -> Cil_types.exp -> Cil_types.term/translates
 Journal/(string -> string) Pervasives.refend /Journalization of functions./
 Cil.cilVisitor.vstmt/Cil_types.stmt -> Cil_types.stmt Cil.visitAction/Control-flow statement. The default DoChildren action does not create a  new statement when the components change. Instead it updates the contents  of the original statement. This is done to preserve the sharing with  Goto and Case statements that point to the original statement. If you  use the ChangeTo action then you should take care of preserving that  sharing yourself./
 Cil.get_varinfo/Cil.visitor_behavior -> Cil_types.varinfo -> Cil_types.varinfo/retrieve the representative of a given varinfo in the current state of the visitor/
-Db.Value.is_computed/unit -> bool/Return true iff the value analysis has been done./
+Eva.Analysis.is_computed/unit -> bool/Return true iff the value analysis has been done./
 Kernel.Unicode/('a -> 'b) -> 'a -> 'bend /Behavior of option "-unicode"./
 Design.register_extension/(Design.main_window_extension_points -> unit) -> unit/Register an extension to the main GUI. It will be invoked at initialization time./
 Cil_types.global/ | GType of Cil_types.typeinfo * Cil_types.location | GCompTag of Cil_types.compinfo * Cil_types.location | GCompTagDecl of Cil_types.compinfo * Cil_types.location | GEnumTag of Cil_types.enuminfo * Cil_types.location | GEnumTagDecl of Cil_types.enuminfo * Cil_types.location | GVarDecl of Cil_types.varinfo * Cil_types.location | GFunDecl of Cil_types.funspec * Cil_types.varinfo * Cil_types.location | GVar of Cil_types.varinfo * Cil_types.initinfo * Cil_types.location | GFun of Cil_types.fundec * Cil_types.location | GAsm of string * Cil_types.location | GPragma of Cil_types.attribute * Cil_types.location | GText of string | GAnnot of Cil_types.global_annotation * Cil_types.location/The main type for representing global declarations and definitions. A list of these form a CIL file. The order of globals in the file is generally important./
diff --git a/doc/developer/tutorial/viewcfg/src/dump_function_memo_clear_cache.ml b/doc/developer/tutorial/viewcfg/src/dump_function_memo_clear_cache.ml
index 3a83c607bb9f1075517684d443f10c25305c122f..36eb30f11660c19bc89f3524067d71382e014733 100644
--- a/doc/developer/tutorial/viewcfg/src/dump_function_memo_clear_cache.ml
+++ b/doc/developer/tutorial/viewcfg/src/dump_function_memo_clear_cache.ml
@@ -1,5 +1,5 @@
 let dump_function fundec fmt =
-  if not (Value_is_computed.get ()) && Db.Value.is_computed () then begin 
+  if not (Value_is_computed.get ()) && Eva.Analysis.is_computed () then begin 
     Value_is_computed.set true;
     let selection = State_selection.with_dependencies Cfg_graph_state.self in
     Project.clear ~selection ();
diff --git a/doc/developer/tutorial/viewcfg/src/print_cfg_vstmt_aux_value.ml b/doc/developer/tutorial/viewcfg/src/print_cfg_vstmt_aux_value.ml
index 04446722a1f84abc19e1553058e7cc6f4ad2a5f8..67038d53098490e5c6d7b14991dac834b5b9e9a9 100644
--- a/doc/developer/tutorial/viewcfg/src/print_cfg_vstmt_aux_value.ml
+++ b/doc/developer/tutorial/viewcfg/src/print_cfg_vstmt_aux_value.ml
@@ -1,6 +1,6 @@
   method! vstmt_aux s =
     let color = 
-      if Db.Value.is_computed () then
+      if Eva.Analysis.is_computed () then
 	let state = Db.Value.get_stmt_state s in
 	let reachable = Db.Value.is_reachable state in
 	if reachable then "fillcolor=\"#ccffcc\" style=filled"
diff --git a/doc/training/developer/project.tex b/doc/training/developer/project.tex
index 98e08c503c07304da355bff6274bb29fbcde8398..8af2d2bceb399a059fc13eeb0438d6119316513c 100644
--- a/doc/training/developer/project.tex
+++ b/doc/training/developer/project.tex
@@ -175,7 +175,7 @@ let main () =
       ~select_annot:false
       ~select_slice_pragma:false
    in
-   Project.on p !Db.Value.compute ()
+   Project.on p Eva.Analysis.compute ()
 \end{ocamlcode}
   \end{itemize}
 
diff --git a/doc/training/developer/sources/basic_script.ml b/doc/training/developer/sources/basic_script.ml
index a9160149a1cbdab32d79dd1d34a89a53c04ff4b1..fd83c661bb190de5faf19f44fb978f59641aa548 100644
--- a/doc/training/developer/sources/basic_script.ml
+++ b/doc/training/developer/sources/basic_script.ml
@@ -10,7 +10,7 @@ let run f () =
   incr nb_entry_points;
   Kernel.MainFunction.set f;
   Kernel.LibEntry.on ();
-  !Db.Value.compute ()
+  Eva.Analysis.compute ()
 
 (*# Main driver function*)
 let all_entry_points () =
diff --git a/doc/training/developer/sources/const_violation.ml b/doc/training/developer/sources/const_violation.ml
index e057b7fbf7701f7492ff6aebc14db153cfec0c57..2eadb5524debd6e35c3ca20913df90252636c07a 100644
--- a/doc/training/developer/sources/const_violation.ml
+++ b/doc/training/developer/sources/const_violation.ml
@@ -3,7 +3,7 @@ let run () =
   let glob = Globals.Vars.find_from_astinfo "Glob" Cil_types.VGlobal in
   let glob_expr = Cil.evar ~loc:Cil_datatype.Location.unknown glob in
   let main = Globals.Functions.find_by_name "main" in
-  let () = !Db.Value.compute () in
+  let () = Eva.Analysis.compute () in
   let init_stmt = Kernel_function.find_first_stmt main in
   let init_state = Db.Value.get_stmt_state init_stmt in
   let end_stmt = Kernel_function.find_return main in
diff --git a/headers/header_spec.txt b/headers/header_spec.txt
index cb21c86bf52c61ebfa4df23d3f566ad493728ae0..4a1d41dd38f7885727b646bf7f65d7a19b4aed76 100644
--- a/headers/header_spec.txt
+++ b/headers/header_spec.txt
@@ -1316,7 +1316,7 @@ src/plugins/users/users_register.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/users/users_register.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/.merlin: .ignore
 src/plugins/value/Changelog_non_free: .ignore
-src/plugins/value/Eva.mli: CEA_LGPL_OR_PROPRIETARY
+src/plugins/value/Eva.mli: .ignore
 src/plugins/value/alarmset.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/alarmset.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/api/general_requests.ml: CEA_LGPL_OR_PROPRIETARY
@@ -1429,6 +1429,7 @@ src/plugins/value/engine/transfer_stmt.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/engine/transfer_stmt.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/eval.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/eval.mli: CEA_LGPL_OR_PROPRIETARY
+src/plugins/value/gen-api.sh: .ignore
 src/plugins/value/gui_files/gui_callstacks_filters.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/gui_files/gui_callstacks_filters.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/gui_files/gui_callstacks_manager.ml: CEA_LGPL_OR_PROPRIETARY
@@ -1451,6 +1452,8 @@ src/plugins/value/legacy/function_args.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/legacy/function_args.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/register.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/register.mli: CEA_LGPL_OR_PROPRIETARY
+src/plugins/value/utils/results.ml: CEA_LGPL_OR_PROPRIETARY
+src/plugins/value/utils/results.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/partitioning/auto_loop_unroll.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/partitioning/auto_loop_unroll.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/partitioning/partition.ml: CEA_LGPL_OR_PROPRIETARY
diff --git a/src/plugins/aorai/aorai_eva_analysis.enabled.ml b/src/plugins/aorai/aorai_eva_analysis.enabled.ml
index 8b007c55b15b021ba234a5d76899eb55587c0967..f95b747b5e7e9ce175417d44afa1832b6d2f3f62 100644
--- a/src/plugins/aorai/aorai_eva_analysis.enabled.ml
+++ b/src/plugins/aorai/aorai_eva_analysis.enabled.ml
@@ -25,7 +25,7 @@
 
 let show_aorai_variable state fmt var_name =
   let vi = Data_for_aorai.(get_varinfo var_name) in
-  let cvalue = !Db.Value.eval_expr state (Cil.evar vi) in
+  let cvalue = Cvalue.Model.find state (Locations.loc_of_varinfo vi) in
   try
     let i = Ival.project_int (Cvalue.V.project_ival cvalue) in
     let state_name = Data_for_aorai.getStateName (Integer.to_int_exn i) in
diff --git a/src/plugins/constant_propagation/api.ml b/src/plugins/constant_propagation/api.ml
index 569d5d24e3aeb69d3dbbf390330390aecc1c60da..be5eb41d5d1c6f1f542cf27a213372c95b6037d5 100644
--- a/src/plugins/constant_propagation/api.ml
+++ b/src/plugins/constant_propagation/api.ml
@@ -131,11 +131,11 @@ class propagate project fnames ~cast_intro = object(self)
           | TEnum _) -> ()
         | _ -> raise Cannot_expand
       end;
-      let ki = match self#current_stmt with
+      let stmt = match self#current_stmt with
         | None -> raise Cannot_change
-        | Some s -> Kstmt s
+        | Some s -> s
       in
-      let evaled = !Db.Value.access_expr ki expr in
+      let evaled = Eva.Results.(before stmt |> eval_exp expr |> as_cvalue) in
       let b, m = Cvalue.V.find_lonely_binding evaled in
       let can_replace vi =
         (* can replace the current expr by [vi] iff (1) it is a source var, or
@@ -340,7 +340,7 @@ module Result =
       let size = 7
       let name = "Semantical constant propagation"
       let dependencies =
-        [ Db.Value.self;
+        [ Eva.Analysis.self;
           PropagationParameters.CastIntro.self;
           PropagationParameters.Project_name.self ]
     end)
@@ -352,7 +352,7 @@ let journalized_get =
   let get fnames cast_intro =
     Result.memo
       (fun _ ->
-         !Db.Value.compute ();
+         Eva.Analysis.compute ();
          let fresh_project =
            FC_file.create_project_from_visitor
              (PropagationParameters.Project_name.get ())
diff --git a/src/plugins/dive/build.ml b/src/plugins/dive/build.ml
index 6a08979f28db393ec3fcb6024a20c670f6a89241..b694d6d85ecb58b9256b6e05dcbf66547377dfa3 100644
--- a/src/plugins/dive/build.ml
+++ b/src/plugins/dive/build.ml
@@ -27,7 +27,6 @@ module Graph = Dive_graph
 
 let dkey = Self.register_category "build"
 
-
 (* --- Utility function --- *)
 
 (* Breaks a list at n-th element into two sublists *)
@@ -76,29 +75,24 @@ end
 
 module Eval =
 struct
-  let to_kf_list kinstr expr =
-    let _,set = !Db.Value.expr_to_kernel_function kinstr ~deps:None expr in
-    Kernel_function.Hptset.fold (fun kf acc -> kf :: acc) set []
+  open Eva.Results
+
+  let to_kf_list kinstr callee =
+    before_kinstr kinstr |> eval_callee callee |>
+    Result.value ~default:[]
 
   let to_cvalue kinstr lval =
-    let state = Db.Value.get_state kinstr in
-    let _,cvalue = !Db.Value.eval_lval None state lval in
-    cvalue
+    before_kinstr kinstr |> eval_lval lval |> as_cvalue
 
   let to_location kinstr lval =
-    let state = Db.Value.get_state kinstr in
-    !Db.Value.lval_to_loc_state state lval
+    before_kinstr kinstr |> eval_address lval |> as_location |>
+    Result.value ~default:Locations.loc_bottom
 
   let to_zone kinstr lval =
-    !Db.Value.lval_to_zone kinstr lval
+    before_kinstr kinstr |> eval_address lval |> as_zone
 
   let to_callstacks stmt =
-    let states = Db.Value.get_stmt_state_callstack ~after:false stmt in
-    match states with
-    | None -> assert false
-    | Some table ->
-      let module Table = Value_types.Callstack.Hashtbl in
-      Table.fold (fun cs _ acc -> cs :: acc) table []
+    before stmt |> callstacks
 
   let studia_is_direct (_,{Studia.Writes.direct}) = direct
 
diff --git a/src/plugins/dive/context.ml b/src/plugins/dive/context.ml
index 3b91fbdf9ea2bbd5eb459079d421414f051f59c7..5dc407e377dc58dbfb24efb86459aa1fb28db5a1 100644
--- a/src/plugins/dive/context.ml
+++ b/src/plugins/dive/context.ml
@@ -51,7 +51,7 @@ type t = {
 (* --- initialization --- *)
 
 let create () =
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   {
     graph = Graph.create ();
     vertex_table = Index.create 13;
diff --git a/src/plugins/dive/server_interface.ml b/src/plugins/dive/server_interface.ml
index 93e389396dc826aae8771fb83ef57878bb4d635a..999e07549497bb37b4bf985f2d81397f58f9ba81 100644
--- a/src/plugins/dive/server_interface.ml
+++ b/src/plugins/dive/server_interface.ml
@@ -38,7 +38,7 @@ let get_context =
     match !context with
     | Some c -> c
     | None ->
-      if Db.Value.is_computed () then
+      if Eva.Analysis.is_computed () then
         let c = Context.create () in
         context := Some c;
         c
diff --git a/src/plugins/impact/compute_impact.ml b/src/plugins/impact/compute_impact.ml
index 4305f65b876bc2d4292644d27645c2ed8445ad9a..a4579f1fb6fab4ac5556f8da78e9cb40393268e4 100644
--- a/src/plugins/impact/compute_impact.ml
+++ b/src/plugins/impact/compute_impact.ml
@@ -332,8 +332,8 @@ let downward_one_call_node wl (pnode, _ as node) caller_kf pdg =
 
   | Key.SigCallKey(id, key) ->
     let stmt = Key.call_from_id id in
-    let called_kfs = Db.Value.call_to_kernel_function stmt in
-    KFS.iter
+    let called_kfs = Eva.Results.callee stmt in
+    List.iter
       (fun called_kf ->
          let called_pdg = !Db.Pdg.get called_kf in
          let nodes_callee, pdg_ok =
@@ -452,7 +452,7 @@ let all_upward_callers wl kfs =
                let pdg_caller = !Db.Pdg.get caller in
                List.iter (aux_call (caller, pdg_caller) (kf, pdg_kf)) callsites;
                KFS.add caller todo
-            ) todo (!Db.Value.callers kf);
+            ) todo (Eva.Results.callsites kf);
         )
         else todo
       in
@@ -536,7 +536,7 @@ let initial_worklist ?(skip=Locations.Zone.bottom) ?(reason=false) nodes kf =
 let initial_nodes ~skip kf stmt =
   Options.debug ~level:3 "computing initial nodes for %d" stmt.sid;
   let pdg = !Db.Pdg.get kf in
-  if Db.Value.is_reachable_stmt stmt then
+  if Eva.Results.is_reachable stmt then
     try
       let all = !Db.Pdg.find_simple_stmt_nodes pdg stmt in
       let filter n = match PdgTypes.Node.elem_key n with
diff --git a/src/plugins/impact/register_gui.ml b/src/plugins/impact/register_gui.ml
index 38bba42a81961373ba276d255a81ef2986236755..75e1f7a1487d74eddfa93cee9851ded33f655ccd 100644
--- a/src/plugins/impact/register_gui.ml
+++ b/src/plugins/impact/register_gui.ml
@@ -208,7 +208,7 @@ let impact_statement =
 
 
 let impact_statement_ui (main_ui:Design.main_window_extension_points) s =
-  let val_computed = Db.Value.is_computed () in
+  let val_computed = Eva.Analysis.is_computed () in
   ignore (impact_statement (*restriction*)Locations.Zone.top s);
   if not val_computed then
     main_ui#reset ()
diff --git a/src/plugins/inout/derefs.ml b/src/plugins/inout/derefs.ml
index 19bba4c86cccbfb4e72afb0a15313f0db8239d84..53bf4d9d7fa06d2c3c57adc9c83a48294bd6144e 100644
--- a/src/plugins/inout/derefs.ml
+++ b/src/plugins/inout/derefs.ml
@@ -86,7 +86,7 @@ module Externals =
 let get_external =
   Externals.memo
     (fun kf ->
-       !Db.Value.compute ();
+       Eva.Analysis.compute ();
        if Kernel_function.is_definition kf then
          try
            externalize
diff --git a/src/plugins/inout/operational_inputs.ml b/src/plugins/inout/operational_inputs.ml
index 43736a78c9436ab1209a6d1bd9af3bed5476bfe3..85835a4966e9698c6afb0cbfd4cfb3df631d73f7 100644
--- a/src/plugins/inout/operational_inputs.ml
+++ b/src/plugins/inout/operational_inputs.ml
@@ -374,26 +374,18 @@ module Computer(Fenv:Dataflows.FUNCTION_ENV)(X:sig
          | AAssert (_, p)
          | AInvariant (_, true, p) ->
            begin
-             let env =
-               Eva.Eval_terms.env_annot
-                 ~pre:X.kf_pre_state
-                 ~here:(X.stmt_state stmt)
-                 ()
+             let pre = X.kf_pre_state
+             and here = X.stmt_state stmt in
+             let deps =
+               Eva.Eval_terms.annot_predicate_deps ~pre ~here p.tp_statement
              in
-             match Eva.Eval_terms.predicate_deps env p.tp_statement with
+             match deps with
              | None ->
                (* To be sound, we should perform a join with the top zone here.
                   We do nothing instead because the latter behavior would
                   directly disable memexec. *)
                ()
-             | Some logic_deps ->
-               let p_zone =
-                 Cil_datatype.Logic_label.Map.fold
-                   (fun _ -> Zone.join)
-                   logic_deps
-                   Zone.bottom
-               in
-               store_non_terminating_logic_inputs p_zone
+             | Some p_zone -> store_non_terminating_logic_inputs p_zone
            end
          | _ -> ())
       stmt
@@ -807,7 +799,7 @@ end
 let get_internal =
   Internals.memo
     (fun kf ->
-       !Db.Value.compute ();
+       Eva.Analysis.compute ();
        try Internals.find kf (* The results may have been computed by the call
                                 to Value.compute *)
        with
diff --git a/src/plugins/inout/outputs.ml b/src/plugins/inout/outputs.ml
index 1137bece59862b3720436f2da090395382a8cc9e..5976c3b6f0fafc7bcc6e3e495609392e96e47bf7 100644
--- a/src/plugins/inout/outputs.ml
+++ b/src/plugins/inout/outputs.ml
@@ -48,11 +48,10 @@ class virtual do_it_ = object(self)
     (* For local initializations, counts the written variable as an output of the
        function, even if it is const; thus, [for_writing] is false in this case. *)
   method private do_assign ~for_writing lv =
-    let state = Db.Value.get_state self#current_kinstr in
-    let _deps, bits_loc, _exact =
-      !Db.Value.lval_to_zone_with_deps_state state
-        ~deps:None ~for_writing lv
-    in
+    let access = if for_writing then Write else Read in
+    let bits_loc = Eva.Results.(
+        before_kinstr self#current_kinstr |> eval_address lv |>
+        as_zone ~access) in
     self#join bits_loc
 
   method! vinst i =
diff --git a/src/plugins/inout/register.ml b/src/plugins/inout/register.ml
index f8615a255af358297d2005df233cabb149b43e94..00ca70a65a077cf27bdc6ef4ab6a1d6386517c7d 100644
--- a/src/plugins/inout/register.ml
+++ b/src/plugins/inout/register.ml
@@ -49,7 +49,7 @@ let main () =
      Inout_parameters.Output.get () && ShouldOutput.get ()
   then begin
     ShouldOutput.set false;
-    !Db.Value.compute ();
+    Eva.Analysis.compute ();
     Callgraph.Uses.iter_in_rev_order
       (fun kf ->
          if Kernel_function.is_definition kf && !Db.Value.is_called kf
diff --git a/src/plugins/loop_analysis/Makefile.in b/src/plugins/loop_analysis/Makefile.in
index 4cb7ceebdc781357e9221147bad002aae4d4c284..a4aee4ac5c07f8d1596462e154ed1f4a874feb59 100644
--- a/src/plugins/loop_analysis/Makefile.in
+++ b/src/plugins/loop_analysis/Makefile.in
@@ -33,6 +33,7 @@ PLUGIN_DISTRIBUTED:=$(PLUGIN_ENABLE)
 PLUGIN_NAME:= LoopAnalysis
 PLUGIN_CMO:= options region_analysis region_analysis_stmt loop_analysis register
 PLUGIN_CMI:= region_analysis_sig
+PLUGIN_DEPENDENCIES:= Eva
 PLUGIN_DISTRIB_EXTERNAL:= Makefile.in configure.ac configure test.c test.oracle README.org
 PLUGIN_TESTS_DIRS:=loop_analysis
 
diff --git a/src/plugins/loop_analysis/loop_analysis.ml b/src/plugins/loop_analysis/loop_analysis.ml
index 39a8827dd6a6ccf49727ac1b7cdb7a18c4d32dde..a37f5ec6586e66fc2b74e11a11b627dc6b060d7a 100644
--- a/src/plugins/loop_analysis/loop_analysis.ml
+++ b/src/plugins/loop_analysis/loop_analysis.ml
@@ -340,37 +340,18 @@ module Store(* (B:sig *)
         Printer.pp_stmt stmt
 
   let value_min_max stmt vi =
-    if (Db.Value.is_computed ()) then
+    if (Eva.Analysis.is_computed ()) then
       begin
         Options.feedback ~dkey ~once:true
           "value analysis computed, trying results";
-        if Db.Value.is_reachable_stmt stmt then
-          let state = Db.Value.get_stmt_state stmt in
-          try
-            let loc = Locations.loc_of_varinfo vi in
-            let v = Db.Value.find state loc in
-            let ival = Cvalue.V.project_ival v in
-            let omin, omax = Ival.min_and_max ival in
-            omin, omax
-          with
-          | Not_found ->
-            Options.feedback ~dkey "value_min_max: not found: %a@.\
-                                    function: %a, stmt: %a"
-              Printer.pp_varinfo vi Kernel_function.pretty
-              (Kernel_function.find_englobing_kf stmt) Printer.pp_stmt stmt;
-            None, None
-          | Cvalue.V.Not_based_on_null ->
-            Options.feedback ~dkey "value_min_max: not based on null: %a@.\
-                                    function: %a, stmt: %a"
-              Printer.pp_varinfo vi Kernel_function.pretty
-              (Kernel_function.find_englobing_kf stmt) Printer.pp_stmt stmt;
-            None, None
-        else
-          begin
+        let value = Eva.Results.(before stmt |> eval_var vi |> as_ival) in
+        match value with
+        | Result.Ok ival -> Ival.min_and_max ival
+        | Error e ->
+          if e = Eva.Results.Bottom then
             Options.feedback ~dkey "skipping unreachable stmt (function: %a)"
               Kernel_function.pretty (Kernel_function.find_englobing_kf stmt);
-            None, None
-          end
+          None, None
       end
     else
       begin
@@ -490,7 +471,7 @@ module Store(* (B:sig *)
             with Not_found -> ()
           end
         | c ->
-          if (Db.Value.is_computed ()) then
+          if (Eva.Analysis.is_computed ()) then
             begin
               let min_max_int = value_min_max stmt in
               match c with
diff --git a/src/plugins/loop_analysis/tests/loop_analysis/oracle/with_value.res.oracle b/src/plugins/loop_analysis/tests/loop_analysis/oracle/with_value.res.oracle
index f2851d8cb74760ca575b38650701d31b54dcc5f9..b7db69d0c82a6d489540170eed6b3c41a2e97997 100644
--- a/src/plugins/loop_analysis/tests/loop_analysis/oracle/with_value.res.oracle
+++ b/src/plugins/loop_analysis/tests/loop_analysis/oracle/with_value.res.oracle
@@ -433,6 +433,10 @@
   with_value.i:26: 5
   with_value.i:30: 5
   with_value.i:34: 4
+  with_value.i:38: 2147483648
+  with_value.i:42: 2147483649
+  with_value.i:46: 2147483649
+  with_value.i:50: 2147483648
   with_value.i:54: 2147483646
   with_value.i:58: 2147483647
   with_value.i:62: 2147483647
diff --git a/src/plugins/markdown-report/eva_info.ml b/src/plugins/markdown-report/eva_info.ml
index 7c00cc4ae15e0e88f9a093f261341904dcb1994d..b0a59dc172472ee3f611be9e4c075057457e46ba 100644
--- a/src/plugins/markdown-report/eva_info.ml
+++ b/src/plugins/markdown-report/eva_info.ml
@@ -96,7 +96,7 @@ class eva_coverage_vis ~from_entry_point = object(self)
     | Block _ | UnspecifiedSequence _ -> Cil.DoChildren
     | _ ->
       self#incr_total_stmts;
-      if Db.Value.is_reachable_stmt s then self#incr_covered_stmts;
+      if Eva.Results.is_reachable s then self#incr_covered_stmts;
       Cil.DoChildren
 
   method! vinst i =
@@ -114,7 +114,7 @@ class eva_coverage_vis ~from_entry_point = object(self)
       Cil.SkipChildren
     | Call(_,{ enode = Lval (Mem _,NoOffset)},_,_) ->
       let s = Option.get self#current_stmt in
-      let kfs = Db.Value.call_to_kernel_function s in
+      let kfs = Eva.Results.callee s in
       let handle_one kf =
         let vi = Kernel_function.get_vi kf in
         if not (Cil_datatype.Varinfo.Hashtbl.mem calls vi)
@@ -129,7 +129,7 @@ class eva_coverage_vis ~from_entry_point = object(self)
           end
         end
       in
-      Kernel_function.Hptset.iter handle_one kfs;
+      List.iter handle_one kfs;
       Cil.SkipChildren
     | _ -> Cil.SkipChildren (* No need to go further. *)
 
@@ -187,7 +187,7 @@ open Markdown
 
 let coverage_md_gen () =
   let main = Kernel.MainFunction.get () in
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   let vis = new eva_coverage_vis ~from_entry_point:false in
   let stats = vis#compute () in
   let summary_whole =
diff --git a/src/plugins/metrics/metrics_coverage.ml b/src/plugins/metrics/metrics_coverage.ml
index ead657ccfe1122c0ac7ec88c2823ce2b5f0e9682..fad2d481a43a7c6b40a8e539bbe95b0b9d76a93e 100644
--- a/src/plugins/metrics/metrics_coverage.ml
+++ b/src/plugins/metrics/metrics_coverage.ml
@@ -215,7 +215,7 @@ class coverageByFun = object
 
   method! vstmt s =
     total <- total + 1;
-    if Db.Value.is_reachable_stmt s then value <- value + 1;
+    if Eva.Results.is_reachable s then value <- value + 1;
     Cil.DoChildren
 
   method result = (total, value)
@@ -244,12 +244,12 @@ let compute_coverage_for kf =
   with Kernel_function.No_Definition -> ()
 
 let compute_coverage_by_fun () =
-  if Db.Value.is_computed () && not (is_computed_by_fun ())
+  if Eva.Analysis.is_computed () && not (is_computed_by_fun ())
   then
     let libc = Metrics_parameters.Libc.get () in
     Globals.Functions.iter
       (fun kf ->
-         if !Db.Value.is_called kf &&
+         if Eva.Results.is_called kf &&
             Metrics_base.consider_function ~libc (Kernel_function.get_vi kf)
          then compute_coverage_for kf)
 
@@ -264,12 +264,12 @@ let compute_syntactic ~libc kf =
 let dkey_sem = Metrics_parameters.register_category "semantic-visitor"
 
 let compute_semantic ~libc =
-  assert (Db.Value.is_computed ());
+  assert (Eva.Analysis.is_computed ());
   let res = ref Varinfo.Set.empty in
   (* Just iter on all the functions and consult the appropriate table *)
   Globals.Functions.iter
     (fun kf ->
-       if !Db.Value.is_called kf &&
+       if Eva.Results.is_called kf &&
           Metrics_base.consider_function ~libc
             (Kernel_function.get_vi kf)
        then begin
@@ -360,7 +360,7 @@ class semantic_printer ~libc (cov_metrics : coverage_metrics) = object(self)
 
   (* uses semantic *)
   method pp_value_coverage fmt =
-    assert (Db.Value.is_computed ());
+    assert (Eva.Analysis.is_computed ());
     let all = self#all_funs in
     let syntactic = cov_metrics.syntactic
     and semantic = cov_metrics.semantic in
@@ -425,7 +425,7 @@ let percent_coverage ~libc cov_metrics =
 ;;
 
 let compute ~libc =
-  assert (Db.Value.is_computed ());
+  assert (Eva.Analysis.is_computed ());
   let semantic = compute_semantic ~libc in
   let main = fst (Globals.entry_point ()) in
   let syntactic, initializers = compute_syntactic ~libc main in
diff --git a/src/plugins/metrics/register.ml b/src/plugins/metrics/register.ml
index 1ab4336a288ce79a1cc5a57321819fddc016c314..2ea7050327a6cdcfb61737a06a89477433d5ee13 100644
--- a/src/plugins/metrics/register.ml
+++ b/src/plugins/metrics/register.ml
@@ -47,8 +47,8 @@ let syntactic ?(libc=Metrics_parameters.Libc.get ()) () =
 let () = ValueCoverage.set_output_dependencies [Db.Value.self; Libc.self]
 
 let value ~libc () =
-  !Db.Value.compute ();
-  if Db.Value.is_computed () then begin
+  Eva.Analysis.compute ();
+  if Eva.Analysis.is_computed () then begin
     let cov_metrics = Metrics_coverage.compute ~libc in
     let cov_printer = new Metrics_coverage.semantic_printer ~libc cov_metrics in
     Metrics_parameters.result "%t" cov_printer#pp_value_coverage;
diff --git a/src/plugins/metrics/register_gui.ml b/src/plugins/metrics/register_gui.ml
index ace660eb586bb41b196a5e55fe44b4344204e7a9..a75dd2ed93332dc3d996871daf9eacf801d58b61 100644
--- a/src/plugins/metrics/register_gui.ml
+++ b/src/plugins/metrics/register_gui.ml
@@ -146,7 +146,7 @@ module CyclomaticMetricsGUI = struct
       end
 
     method cyclo_selector (popup_factory:GMenu.menu GMenu.factory) main_ui ~button localizable =
-      if button = 3 && Db.Value.is_computed () then
+      if button = 3 && Eva.Analysis.is_computed () then
         match localizable with
         | PVDecl (Some kf, _,_) ->
           let callback1 () =
@@ -214,7 +214,7 @@ module ValueCoverageGUI = struct
     begin
       match !result with
       | None ->
-        !Db.Value.compute ();
+        Eva.Analysis.compute ();
         result := Some (Metrics_coverage.compute ~libc)
       | Some _ -> ()
     end;
diff --git a/src/plugins/nonterm/nonterm_run.ml b/src/plugins/nonterm/nonterm_run.ml
index 23d5aa7635938046ba7d24391cc8e6bbdfb613d9..0cbfe74ffb31bddf7cf6a014fc1a8621187b7162 100644
--- a/src/plugins/nonterm/nonterm_run.ml
+++ b/src/plugins/nonterm/nonterm_run.ml
@@ -181,7 +181,7 @@ class unreachable_stmt_visitor kf to_ignore = object
 
   method! vstmt stmt =
     if Stmt.Hptset.mem stmt syntactically_reachable &&
-       Db.Value.is_reachable_stmt stmt = false &&
+       not (Eva.Results.is_reachable stmt) &&
        not (Stmt.Hptset.mem stmt !semantically_considered)
     then begin
       (* add node and its reachable successors to the considered statements *)
@@ -197,11 +197,10 @@ end
    1. SyntacticallyUnreachable is disabled (otherwise it already checks them);
    2. No warnings were emitted for the function (otherwise it may be redundant). *)
 let check_unreachable_returns kf =
-  let st = Db.Value.get_initial_state kf in
-  if Db.Value.is_reachable st then begin
+  if Eva.Results.is_called kf then begin
     try
       let ret_stmt = Kernel_function.find_return kf in
-      if not (Db.Value.is_reachable_stmt ret_stmt) then
+      if not (Eva.Results.is_reachable ret_stmt) then
         warn_unreachable_statement ret_stmt
     with
     | Kernel_function.No_Statement -> (* should never happen *)
@@ -221,25 +220,24 @@ let check_unreachable_statements kf ~to_ignore ~dead_code ~warned_kfs =
                 considered as always terminating"
       Kernel_function.pretty kf
   else
-    let st = Db.Value.get_initial_state kf in
-    if Db.Value.is_reachable st then begin
-      try
-        let vis = new unreachable_stmt_visitor kf to_ignore in
+  if Eva.Results.is_called kf then begin
+    try
+      let vis = new unreachable_stmt_visitor kf to_ignore in
+      ignore (Visitor.visitFramacKf (vis :> Visitor.frama_c_visitor) kf);
+      if dead_code then begin
+        (* compute syntactically unreachable statements *)
+        let vis = new dead_cc_collector kf in
         ignore (Visitor.visitFramacKf (vis :> Visitor.frama_c_visitor) kf);
-        if dead_code then begin
-          (* compute syntactically unreachable statements *)
-          let vis = new dead_cc_collector kf in
-          ignore (Visitor.visitFramacKf (vis :> Visitor.frama_c_visitor) kf);
-          let cc_heads = List.map List.hd vis#get in
-          Stmt.Hptset.iter (fun h -> warn_dead_code h) (Stmt.Hptset.of_list cc_heads)
-        end
-        else if not (Kernel_function.Set.mem kf warned_kfs) then
-          check_unreachable_returns kf
-      with
-      | Kernel_function.No_Statement -> (* should never happen *)
-        Self.error "function %a has no return statement, skipping"
-          Kernel_function.pretty kf;
-    end
+        let cc_heads = List.map List.hd vis#get in
+        Stmt.Hptset.iter (fun h -> warn_dead_code h) (Stmt.Hptset.of_list cc_heads)
+      end
+      else if not (Kernel_function.Set.mem kf warned_kfs) then
+        check_unreachable_returns kf
+    with
+    | Kernel_function.No_Statement -> (* should never happen *)
+      Self.error "function %a has no return statement, skipping"
+        Kernel_function.pretty kf;
+  end
 
 (* To avoid redundant warnings, calls to possibly non-terminating functions
    are ignored if:
@@ -281,14 +279,6 @@ class stmt_collector = object
   method get_instr_stmts = List.rev !instr_stmts
 end
 
-let get_callstack_state ~after stmt cs =
-  match Db.Value.get_stmt_state_callstack ~after stmt with
-  | None -> None (* unreachable stmt *)
-  | Some table ->
-    try
-      Some (Value_types.Callstack.Hashtbl.find table cs)
-    with Not_found -> None
-
 (* collects the list of non-terminating instructions *)
 let collect_nonterminating_statements fd nonterm_stacks =
   let vis = new stmt_collector in
@@ -309,40 +299,23 @@ let collect_nonterminating_statements fd nonterm_stacks =
       | _ ->
         let source = fst (Stmt.loc stmt) in
         Self.debug ~source "processing stmt:@ %a" Printer.pp_stmt stmt;
-        match Db.Value.get_stmt_state_callstack ~after:false stmt with
-        | None -> () (* unreachable stmt *)
-        | Some before_table ->
-          Value_types.Callstack.Hashtbl.iter
-            (fun cs before_state ->
-               try
-                 match Db.Value.get_stmt_state_callstack ~after:true stmt with
-                 | None -> (* no after table => non-terminating statement *)
-                   add_stack stmt cs
-                 | Some after_table ->
-                   let after_state =
-                     Value_types.Callstack.Hashtbl.find after_table cs
-                   in
-                   if Cvalue.Model.is_reachable before_state then
-                     if not (Cvalue.Model.is_reachable after_state) then add_stack stmt cs
-                     else if match stmt.skind with Loop _ -> true | _ -> false then begin
-                       (* special treatment for loops: even if their after state
-                          is reachable, we must check that at least one outgoing
-                          edge is reachable *)
-                       let out_edges = Stmts_graph.get_all_stmt_out_edges stmt in
-                       let all_out_edges_unreachable =
-                         List.for_all (fun (_, out_stmt) ->
-                             match get_callstack_state ~after:false out_stmt cs with
-                             | None -> true
-                             | Some state -> not (Cvalue.Model.is_reachable state)
-                           ) out_edges
-                       in
-                       if all_out_edges_unreachable then add_stack stmt cs
-                     end
-               with
-               | Not_found ->
-                 (* in this callstack, the statement is non-terminating *)
-                 add_stack stmt cs
-            ) before_table
+        let process_callstack cs =
+          if Eva.Results.(after stmt |> in_callstack cs |> is_empty) then
+            add_stack stmt cs
+          else if match stmt.skind with Loop _ -> true | _ -> false then begin
+            (* special treatment for loops: even if their after state
+                is reachable, we must check that at least one outgoing
+                edge is reachable *)
+            let out_edges = Stmts_graph.get_all_stmt_out_edges stmt in
+            let all_out_edges_unreachable =
+              List.for_all (fun (_, out_stmt) ->
+                  Eva.Results.(before out_stmt |> in_callstack cs |> is_empty)
+                ) out_edges
+            in
+            if all_out_edges_unreachable then add_stack stmt cs
+          end
+        in
+        List.iter process_callstack Eva.Results.(before stmt |> callstacks)
     ) vis#get_instr_stmts;
   !new_nonterm_stmts
 
@@ -364,7 +337,7 @@ let cmp_callstacks cs1 cs2 =
 let run () =
   if not (Ast.is_computed ()) then
     Self.abort "nonterm requires a computed AST";
-  if not (Db.Value.is_computed ()) then
+  if not (Eva.Analysis.is_computed ()) then
     Self.abort "nonterm requires a computed value analysis";
   Self.debug "Starting analysis...";
   let file = Ast.get () in
@@ -398,7 +371,7 @@ let run () =
   Self.feedback ~level:2 "Analysis done."
 ;;
 
-let run_once, _ = State_builder.apply_once "Nonterm.run" [Db.Value.self] run
+let run_once, _ = State_builder.apply_once "Nonterm.run" [Eva.Analysis.self] run
 
 let main () =
   if Enabled.get () then run_once ()
diff --git a/src/plugins/occurrence/register.ml b/src/plugins/occurrence/register.ml
index 8d9d94741ec37ce7bf37449cc19674c8fc73cc66..5e6922a3562dd445f1ea22a8ace1b3468dfeb956 100644
--- a/src/plugins/occurrence/register.ml
+++ b/src/plugins/occurrence/register.ml
@@ -106,8 +106,8 @@ class occurrence = object (self)
 
   method! vlval lv =
     let ki = self#current_kinstr in
-    if Db.Value.is_accessible ki then begin
-      let z = !Db.Value.lval_to_zone ki lv in
+    begin
+      let z = Eva.Results.(before_kinstr ki |> eval_address lv |> as_zone) in
       try
         Locations.Zone.fold_topset_ok
           (fun b _ () ->
@@ -135,7 +135,7 @@ class occurrence = object (self)
     Db.yield ();
     super#vstmt_aux s
 
-  initializer !Db.Value.compute ()
+  initializer Eva.Analysis.compute ()
 
 end
 
diff --git a/src/plugins/pdg/build.ml b/src/plugins/pdg/build.ml
index e90ada08bba331ce0f7190093d8c7d5c56d9630f..6606cbf535d5975bc4349e6bcb4776f34b94dbba 100644
--- a/src/plugins/pdg/build.ml
+++ b/src/plugins/pdg/build.ml
@@ -1000,7 +1000,7 @@ let degenerated top kf =
   if top then PdgTypes.Pdg.top kf else PdgTypes.Pdg.bottom kf
 
 let compute_pdg kf =
-  if not (Db.Value.is_computed ()) then !Db.Value.compute ();
+  if not (Eva.Analysis.is_computed ()) then Eva.Analysis.compute ();
   Pdg_parameters.feedback "computing for function %a" Kernel_function.pretty kf;
   try
     if is_variadic kf then
diff --git a/src/plugins/pdg/register.ml b/src/plugins/pdg/register.ml
index 5add8915f1cf8f77a1573dab0f468e71c1755c6f..0c1ae27625fcf632d968f3e545e48dc454891480 100644
--- a/src/plugins/pdg/register.ml
+++ b/src/plugins/pdg/register.ml
@@ -127,7 +127,7 @@ let compute_for_kf kf =
   Kernel_function.Set.mem kf (Pdg_parameters.BuildFct.get ())
 
 let compute () =
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   let do_kf_pdg kf =
     if compute_for_kf kf then
       let pdg = !Db.Pdg.get kf in
diff --git a/src/plugins/postdominators/compute.ml b/src/plugins/postdominators/compute.ml
index d0b257ac9a65ef5759a2b9b9e935fca9701bde32..08cb906feaae05998b2d14113dc8195620ee6913 100644
--- a/src/plugins/postdominators/compute.ml
+++ b/src/plugins/postdominators/compute.ml
@@ -255,7 +255,7 @@ let () = Db.Main.extend output
 include
   PostDomDb
     (struct
-      let is_accessible = Db.Value.is_reachable_stmt
+      let is_accessible = Eva.Results.is_reachable
       let dependencies = [ Db.Value.self ]
       let name = "value"
       let eval_cond stmt _e =
diff --git a/src/plugins/reduc/hyp.ml b/src/plugins/reduc/hyp.ml
index fc4fabf2763c7db2b26efafaf8ff26481de7d763..478be2e40ea72324d85484a651060284bec8d474 100644
--- a/src/plugins/reduc/hyp.ml
+++ b/src/plugins/reduc/hyp.ml
@@ -20,9 +20,9 @@
 (*                                                                        *)
 (**************************************************************************)
 
-let pred_opt_from_expr_state state e =
+let pred_opt_from_expr_state stmt e =
   try
-    Value2acsl.lval_to_predicate state e
+    Value2acsl.lval_to_predicate stmt e
   with
   | Cvalue.V.Not_based_on_null ->
     Misc.not_implemented ~what:"Value not based on null";
@@ -36,12 +36,11 @@ class hypotheses_visitor (env: Collect.env) = object(self)
 
   method! vstmt_aux stmt =
     let kf = Option.get (self#current_kf) in
-    let state = Db.Value.get_stmt_state stmt in
     if Collect.should_annotate_stmt env stmt then begin
       let vars = Collect.get_relevant_vars_stmt env kf stmt in
       List.iter
         (fun e ->
-           let p_opt = pred_opt_from_expr_state state e in
+           let p_opt = pred_opt_from_expr_state stmt e in
            Option.iter (Misc.assert_and_validate ~kf stmt) p_opt)
         vars
     end;
diff --git a/src/plugins/reduc/value2acsl.ml b/src/plugins/reduc/value2acsl.ml
index c91d1ba6992418ffebcea1371b2b587aa9d5ea36..e5201a791ccb73bde0919c6831745d8c63026293 100644
--- a/src/plugins/reduc/value2acsl.ml
+++ b/src/plugins/reduc/value2acsl.ml
@@ -165,15 +165,13 @@ let value_to_predicate_opt ?(loc=Location.unknown) t v =
     with
     | Not_based_on_null -> (* base_offsets_to_predicate ~loc t m *) None
 
-let exp_to_predicate ?(loc=Location.unknown) state e =
-  let value = !Db.Value.eval_expr ~with_alarms:CilE.warn_none_mode state e in
+let exp_to_predicate ?(loc=Location.unknown) stmt e =
+  let value = Eva.Results.(before stmt |> eval_exp e |> as_ival) in
   let te = Logic_utils.expr_to_term ~coerce:false e in
-  value_to_predicate_opt ~loc te value
+  Option.bind (Result.to_option value) (ival_to_predicate_opt ~loc te)
 
-let lval_to_predicate ?(loc=Location.unknown) state lv =
-  let value = snd(!Db.Value.eval_lval
-                    ~with_alarms:CilE.warn_none_mode None state lv)
-  in
+let lval_to_predicate ?(loc=Location.unknown) stmt lv =
+  let value = Eva.Results.(before stmt |> eval_lval lv |> as_ival) in
   let e = Cil.new_exp ~loc (Lval lv) in
   let te = Logic_utils.expr_to_term ~coerce:false e in
-  value_to_predicate_opt ~loc te value
+  Option.bind (Result.to_option value) (ival_to_predicate_opt ~loc te)
diff --git a/src/plugins/reduc/value2acsl.mli b/src/plugins/reduc/value2acsl.mli
index 17546299c2191a9c2c5ea076b463904ccd48ed60..e69aca30b89ac9004dd0ffb548e7ec90d547b8a2 100644
--- a/src/plugins/reduc/value2acsl.mli
+++ b/src/plugins/reduc/value2acsl.mli
@@ -27,5 +27,5 @@ open Cil_types
    @return None if no such predicate can be created. *)
 val value_to_predicate_opt: ?loc:location -> term -> Cvalue.V.t -> predicate option
 
-val lval_to_predicate: ?loc:location -> Cvalue.Model.t -> lval -> predicate option
-val exp_to_predicate: ?loc:location -> Cvalue.Model.t -> exp -> predicate option
+val lval_to_predicate: ?loc:location -> stmt -> lval -> predicate option
+val exp_to_predicate: ?loc:location -> stmt -> exp -> predicate option
diff --git a/src/plugins/scope/datascope.ml b/src/plugins/scope/datascope.ml
index 26d5806673e8aca286bbdc294cd813dc5c2202cd..0e73269b8718a1fd4af65e9bbfb5d1a7da83a342 100644
--- a/src/plugins/scope/datascope.ml
+++ b/src/plugins/scope/datascope.ml
@@ -80,53 +80,44 @@ module InitSid = struct
     Format.fprintf fmt "Lmap = %a@\n" LM.pretty lmap
 end
 
-let get_lval_zones ~for_writing stmt lval =
-  let state = Db.Value.get_stmt_state stmt in
-  let dpds, zone, exact =
-    !Db.Value.lval_to_zone_with_deps_state
-      state ~deps:(Some Locations.Zone.bottom) ~for_writing lval
-  in
-  dpds, exact, zone
+let get_writes stmt lval =
+  Eva.Results.(before stmt |> eval_address lval |> as_zone ~access:Write)
 
 (** Add to [stmt] to [lmap] for all the locations modified by the statement.
  * Something to do only for calls and assignments.
  * *)
 let register_modified_zones lmap stmt =
   let register lmap zone = InitSid.add_zone lmap zone stmt in
-  let aux_out kf out =
+  let aux_out out kf =
     let inout= !Db.Operational_inputs.get_internal_precise ~stmt kf in
     Locations.Zone.join out inout.Inout_type.over_outputs
   in
   match stmt.skind with
   | Instr (Set (lval, _, _)) ->
-    let _dpds, _, zone =
-      get_lval_zones ~for_writing:true  stmt lval
-    in
+    let zone = get_writes stmt lval in
     register lmap zone
   | Instr (Local_init(v, i, _)) ->
-    let _, _, zone = get_lval_zones ~for_writing:true stmt (Cil.var v) in
+    let zone = get_writes stmt (Cil.var v) in
     let lmap_init = register lmap zone in
     (match i with
      | AssignInit _ -> lmap_init
      | ConsInit(f,_,_) ->
        let kf = Globals.Functions.get f in
-       let out = aux_out kf Locations.Zone.bottom in
+       let out = aux_out Locations.Zone.bottom kf in
        register lmap_init out)
   | Instr (Call (dst,funcexp,_args,_)) ->
     begin
       let lmap = match dst with
         | None -> lmap
         | Some lval ->
-          let _dpds, _, zone =
-            get_lval_zones ~for_writing:true stmt lval
-          in
+          let zone = get_writes stmt lval in
           register lmap zone
       in
-      let _, kfs =
-        !Db.Value.expr_to_kernel_function ~deps:None (Kstmt stmt) funcexp
+      let kfs =
+        Eva.Results.(before stmt |> eval_callee funcexp |> default [])
       in
       let out =
-        Kernel_function.Hptset.fold aux_out kfs Locations.Zone.bottom
+        List.fold_left aux_out Locations.Zone.bottom kfs
       in
       register lmap out
     end
@@ -141,7 +132,7 @@ let compute kf =
   let f = Kernel_function.get_definition kf in
   let do_stmt lmap s =
     Cil.CurrentLoc.set (Cil_datatype.Stmt.loc s);
-    if Db.Value.is_reachable_stmt s
+    if Eva.Results.is_reachable s
     then register_modified_zones lmap s
     else lmap
   in
@@ -361,7 +352,9 @@ let compute_escaping_zones s1 s2 =
   let bases = List.fold_left filter Base.Hptset.empty locals in
   if Base.Hptset.is_empty bases
   then Locations.Zone.bottom
-  else gather_escaping_zones bases (Db.Value.get_stmt_state s1)
+  else
+    let cvalue_state = Eva.Results.(before s1 |> get_cvalue_model) in
+    gather_escaping_zones bases cvalue_state
 
 (* type pair_stmts = stmt * stmt *)
 module PairStmts =
@@ -392,7 +385,7 @@ module ModifEdge =
   Cil_state_builder.Kernel_function_hashtbl(HashPairStmtsZone)
     (struct
       let name = "Scope.Datatscope.ModifsEdge"
-      let dependencies = [Db.Value.self]
+      let dependencies = [Eva.Analysis.self]
       let size = 16
     end)
 
@@ -410,9 +403,7 @@ let is_modified_by_edge kf z s1 s2 =
  * @raise Kernel_function.No_Definition if [kf] has no definition
 *)
 let get_data_scope_at_stmt kf stmt lval =
-  let dpds, _, zone = get_lval_zones ~for_writing:false stmt lval in
-  (* TODO : is there something to do with 'exact' ? *)
-  let zone = Locations.Zone.join dpds zone in
+  let zone = Eva.Results.(before stmt |> lval_deps lval) in
   let allstmts, info = compute kf in
   let modif_stmts = InitSid.find info zone in
   let modifs_edge = is_modified_by_edge kf zone in
@@ -594,7 +585,7 @@ class check_annot_visitor = object(self)
 
   method! vglob_aux g = match g with
     | GFun (fdec, _loc) when
-        !Db.Value.is_called (Option.get self#current_kf) &&
+        Eva.Results.is_called (Option.get self#current_kf) &&
         not (!Db.Value.no_results fdec)
       ->
       Cil.DoChildren
diff --git a/src/plugins/scope/datascope.mli b/src/plugins/scope/datascope.mli
index b34a8589757f06d20c613002c3b5d11828773d93..9b93221fe4f37e443f12a2981aeb04a80965eb44 100644
--- a/src/plugins/scope/datascope.mli
+++ b/src/plugins/scope/datascope.mli
@@ -37,9 +37,3 @@ val rm_asserts : unit -> unit
 
 (** for internal use *)
 module R: Plugin.General_services
-
-val get_lval_zones:
-  for_writing:bool ->
-  Cil_types.stmt ->
-  Cil_types.lval ->
-  Locations.Zone.t * bool * Locations.Zone.t
diff --git a/src/plugins/scope/defs.ml b/src/plugins/scope/defs.ml
index 565500c763b879c05749244de1dfb148edbbf699..af1e23d78388266822ed34f6e8bbad847c6ef558 100644
--- a/src/plugins/scope/defs.ml
+++ b/src/plugins/scope/defs.ml
@@ -62,10 +62,8 @@ let rec add_callee_nodes z acc nodes =
       (fun node acc2 ->
          match !Db.Pdg.node_key node with
          | PdgIndex.Key.SigCallKey (cid, PdgIndex.Signature.Out out_key) ->
-           let callees =
-             Db.Value.call_to_kernel_function (PdgIndex.Key.call_from_id cid)
-           in
-           Kernel_function.Hptset.fold (fun kf (new_nodes, acc) ->
+           let callees = Eva.Results.callee (PdgIndex.Key.call_from_id cid) in
+           List.fold_left (fun (new_nodes, acc) kf ->
                let callee_pdg = !Db.Pdg.get kf in
                let outputs = match out_key with
                  | PdgIndex.Signature.OutLoc out ->
@@ -78,8 +76,8 @@ let rec add_callee_nodes z acc nodes =
                in
                let outputs = List.map fst outputs in
                add_list_to_set outputs new_nodes, add_list_to_set outputs acc)
-             callees
              acc2
+             callees
          | _ -> acc2)
       nodes
       (NSet.empty, acc)
@@ -134,7 +132,7 @@ let rec add_caller_nodes z kf acc (undef, nodes) =
     let acc_undef, caller_nodes =
       List.fold_left (add_one_call_nodes pdg) (None, NSet.empty) stmts
     in add_caller_nodes z kf (NSet.union caller_nodes acc) (acc_undef, caller_nodes)
-  in List.fold_left add_one_caller_nodes acc (!Db.Value.callers kf)
+  in List.fold_left add_one_caller_nodes acc (Eva.Results.callsites kf)
 
 let compute_aux kf stmt zone =
   debug1 "[Defs.compute] for %a at sid:%d in '%a'@."
@@ -168,9 +166,9 @@ let compute kf stmt lval =
     let defs = NSet.fold add_node nodes Stmt.Hptset.empty in
     (defs, undef)
   in
-  !Db.Value.compute ();
-  let zone = !Db.Value.lval_to_zone (Kstmt stmt) lval in
-  Option.map extract (compute_aux kf stmt zone)
+  Eva.Analysis.compute ();
+  let zone = Eva.Results.(before stmt |> eval_address lval |> as_zone) in
+  compute_aux kf stmt zone |> Option.map extract
 
 (* Variation of the function above. For each PDG node that has been found,
    we find whether it directly modifies [zone] through an affectation
@@ -219,8 +217,10 @@ let compute_with_def_type_zone kf stmt zone =
   Option.map extract (compute_aux kf stmt zone)
 
 let compute_with_def_type kf stmt lval =
-  !Db.Value.compute ();
-  let zone = !Db.Value.lval_to_zone (Kstmt stmt) lval in
+  Eva.Analysis.compute ();
+  let zone =
+    Eva.Results.(before stmt |> eval_address lval |> as_zone)
+  in
   compute_with_def_type_zone kf stmt zone
 
 (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
diff --git a/src/plugins/scope/dpds_gui.ml b/src/plugins/scope/dpds_gui.ml
index d9d87225b1b4a4361133aa4d48040a91fff153fc..b3798da4e558840c00d2d51e005b3c92c503f5b8 100644
--- a/src/plugins/scope/dpds_gui.ml
+++ b/src/plugins/scope/dpds_gui.ml
@@ -114,7 +114,7 @@ struct include State_builder.Ref
     (Stmt.Hptset)
     (struct
       let name = Info.name
-      let dependencies = [ Db.Value.self ]
+      let dependencies = [ Eva.Analysis.self ]
       let default () = Stmt.Hptset.empty
     end)
 
@@ -137,7 +137,7 @@ struct
       (Stmt.Map.Make(Datatype.String.Set))
       (struct
         let name = Info.name
-        let dependencies = [ Db.Value.self ]
+        let dependencies = [ Eva.Analysis.self ]
         let default () = Stmt.Map.empty
       end)
 
@@ -222,7 +222,7 @@ module Pscope (* : (DpdCmdSig with type t_in = code_annotation) *) = struct
       (Code_annotation)
       (struct
         let name = "Dpds_gui.Highlighter.Pscope_warn"
-        let dependencies = [ Db.Value.self ]
+        let dependencies = [ Eva.Analysis.self ]
       end)
 
   let clear () = Pscope.clear(); Pscope_warn.clear()
@@ -323,7 +323,7 @@ module Zones : (DpdCmdSig with type t_in = lval)  = struct
          (Stmt.Hptset))
       (struct
         let name = "Dpds_gui.Highlighter.ZonesState"
-        let dependencies = [ Db.Value.self ]
+        let dependencies = [ Eva.Analysis.self ]
       end)
     let set s =
       set s;
@@ -392,7 +392,7 @@ module DpdsState =
     (Stmt)
     (struct
       let name = "Dpds_gui.Highlighter.DpdsState"
-      let dependencies = [ Db.Value.self ]
+      let dependencies = [ Eva.Analysis.self ]
     end)
 
 let reset () =
@@ -469,7 +469,7 @@ let highlighter (buffer:Design.reactive_buffer) localizable ~start ~stop =
   with Not_found -> ()
 
 let check_value (main_ui:Design.main_window_extension_points) =
-  if Db.Value.is_computed () then true
+  if Eva.Analysis.is_computed () then true
   else
     let answer = GToolbox.question_box
         ~title:("Eva Needed")
@@ -478,7 +478,7 @@ let check_value (main_ui:Design.main_window_extension_points) =
          ^"Do you want to run Eva with its current settings now?")
     in
     if answer = 1 then
-      match main_ui#full_protect ~cancelable:true !Db.Value.compute with
+      match main_ui#full_protect ~cancelable:true Eva.Analysis.compute with
       | Some _ ->
         main_ui#redisplay (); (* New alarms *)
         true
diff --git a/src/plugins/scope/zones.ml b/src/plugins/scope/zones.ml
index 9a9e18e7c26c5060b93725f7bbc5c1ca7964ea13..938b3630758808c5697d4bda0560436832efdff9 100644
--- a/src/plugins/scope/zones.ml
+++ b/src/plugins/scope/zones.ml
@@ -64,6 +64,14 @@ let compute_new_data old_zone l_zone l_dpds exact r_dpds =
     (true, zone)
   else (false, old_zone)
 
+let get_lval_zones ~for_writing stmt lval =
+  let state = Db.Value.get_stmt_state stmt in
+  let dpds, zone, exact =
+    !Db.Value.lval_to_zone_with_deps_state
+      state ~deps:(Some Locations.Zone.bottom) ~for_writing lval
+  in
+  dpds, exact, zone
+
 (* the call result can be processed like a normal assignment *)
 let process_call_res data stmt lvaloption froms =
   let data = match lvaloption with
@@ -73,7 +81,7 @@ let process_call_res data stmt lvaloption froms =
       let r_dpds = Function_Froms.Memory.collapse_return ret_dpds in
       let r_dpds = Function_Froms.Deps.to_zone r_dpds in
       let l_dpds, exact, l_zone =
-        Datascope.get_lval_zones ~for_writing:true  stmt lval in
+        get_lval_zones ~for_writing:true  stmt lval in
       compute_new_data data l_zone l_dpds exact r_dpds
   in data
 
@@ -144,20 +152,20 @@ let process_one_call data stmt lvaloption froms =
   used, data
 
 let process_call data_after stmt lvaloption funcexp args _loc =
-  let funcexp_dpds, called_functions =
-    !Db.Value.expr_to_kernel_function
-      (Kstmt stmt) ~deps:(Some Data.bottom) funcexp
+  let funcexp_dpds = Eva.Results.(before stmt |> expr_deps funcexp)
+  and called_functions =
+    Eva.Results.(before stmt |> eval_callee funcexp |> default [])
   in
   let used, data =
     try
       let froms = !Db.From.Callwise.find (Kstmt stmt) in
       process_one_call data_after stmt lvaloption froms
     with Not_found -> (* don't have callwise (-calldeps option) *)
-      let do_call kf acc =
+      let do_call acc kf =
         (* notice that we use the same old data for each possible call *)
         (process_one_call data_after stmt lvaloption (!Db.From.get kf))::acc
       in
-      let l = Kernel_function.Hptset.fold do_call called_functions [] in
+      let l = List.fold_left do_call [] called_functions in
       (* in l, we have one result for each possible function called *)
       List.fold_left
         (fun (acc_u,acc_d) (u,d) -> (acc_u || u), Data.merge acc_d d)
@@ -167,10 +175,9 @@ let process_call data_after stmt lvaloption funcexp args _loc =
   if used then
     let data =
       (* no problem of order because parameters are disjoint for sure *)
-      Kernel_function.Hptset.fold
-        (fun kf data -> process_call_args data kf stmt args)
-        called_functions
-        data
+      List.fold_left
+        (fun data kf -> process_call_args data kf stmt args)
+        data called_functions
     in
     let data =  Data.merge funcexp_dpds data in
     used, data
@@ -213,7 +220,7 @@ module Computer (Param:sig val states : Ctx.t end) = struct
 
   let do_assign stmt lval exp data =
     let l_dpds, exact, l_zone =
-      Datascope.get_lval_zones ~for_writing:true stmt lval in
+      get_lval_zones ~for_writing:true stmt lval in
     let r_dpds = Data.exp_zone stmt exp in
     let used, data = compute_new_data data l_zone l_dpds exact r_dpds in
     let _ = if used then add_used_stmt stmt in
@@ -299,7 +306,7 @@ let compute_ctrl_info pdg ctrl_part used_stmts =
 let compute kf stmt lval =
   let f = Kernel_function.get_definition kf in
   let dpds, _exact, zone =
-    Datascope.get_lval_zones ~for_writing:false stmt lval in
+    get_lval_zones ~for_writing:false stmt lval in
   let zone = Data.merge dpds zone in
   debug1 "[zones] build for %a before %d in %a@\n"
     Data.pretty zone stmt.sid Kernel_function.pretty kf;
diff --git a/src/plugins/security_slicing/components.ml b/src/plugins/security_slicing/components.ml
index af605036f174476ed91396a80eb74727be868928..4db3c3d87d9f68ba386df5c377ea29bd926f9e78 100644
--- a/src/plugins/security_slicing/components.ml
+++ b/src/plugins/security_slicing/components.ml
@@ -398,7 +398,7 @@ module Component = struct
            todolist
            callsites)
       todolist
-      (!Db.Value.callers kf)
+      (Eva.Results.callsites kf)
 
   let related_nodes_of_nodes kind result nodes =
     let initial_nodes =
@@ -460,7 +460,7 @@ module Component = struct
                   in
                   List.fold_left do_call todolist callsites
                 in
-                List.fold_left do_caller todolist (!Db.Value.callers kf)
+                List.fold_left do_caller todolist (Eva.Results.callsites kf)
               | _ ->
                 todolist
             in
@@ -502,11 +502,7 @@ module Component = struct
                   todolist
                 else
                   let stmt = Key.call_from_id id in
-                  let called_kfs =
-                    Kernel_function.Hptset.elements
-                      (try Db.Value.call_to_kernel_function stmt
-                       with Db.Value.Not_a_call -> assert false)
-                  in
+                  let called_kfs = Eva.Results.callee stmt in
                   let todolist =
                     List.fold_left
                       (fun todolist called_kf ->
@@ -629,7 +625,7 @@ module Component = struct
       ~level:3 "computing initial nodes for %d" stmt.sid;
     let pdg = !Db.Pdg.get kf in
     let nodes =
-      if Db.Value.is_reachable_stmt stmt then
+      if Eva.Results.is_reachable stmt then
         try !Db.Pdg.find_simple_stmt_nodes pdg stmt
         with Not_found -> assert false
       else begin
diff --git a/src/plugins/slicing/api.ml b/src/plugins/slicing/api.ml
index 3ece47ef72315659e3f2c4756382c7912a072c2a..13b39597d7dac0e6acfd53fbd6011bf9679978a6 100644
--- a/src/plugins/slicing/api.ml
+++ b/src/plugins/slicing/api.ml
@@ -413,10 +413,9 @@ module Slice = struct
 
   let get_called_funcs ff stmt =
     match stmt.skind with
-    | Instr (Call (_,expr_f,_,_)) ->
+    | Instr (Call _) ->
       if snd (Fct_slice.get_called_slice ff stmt) then
-        Kernel_function.Hptset.elements
-          (snd (!Db.Value.expr_to_kernel_function (Kstmt stmt) ~deps:None expr_f))
+        Eva.Results.callee stmt
       else
         []
     | Instr (Local_init (_, ConsInit (f, _, _), _)) -> [ Globals.Functions.get f ]
diff --git a/src/plugins/slicing/fct_slice.ml b/src/plugins/slicing/fct_slice.ml
index 47d922e5bb064d78c4ae8b3c1baacae9bf839769..22285f900b9f9a04bf5aa331cdbef9bd32c215b2 100644
--- a/src/plugins/slicing/fct_slice.ml
+++ b/src/plugins/slicing/fct_slice.ml
@@ -54,9 +54,7 @@ let exists_fun_callers fpred kf =
     then false (* no way to call the initial [kf]. *)
     else begin
       table := Kernel_function.Set.add kf !table ;
-      List.exists
-        (fun (kf,_) -> exists_fun_callers kf)
-        (!Db.Value.callers kf)
+      List.exists exists_fun_callers (Eva.Results.callers kf)
     end
   in
   exists_fun_callers kf
@@ -146,16 +144,7 @@ end = struct
 
   let indirectly_called_src_functions call_id =
     let _, stmt = call_id in
-    let funcexp = match stmt.skind with
-      | Instr (Call (_,funcexp,_,_)) -> funcexp
-      | Instr (Local_init (_, ConsInit (f, _, _), _)) -> Cil.evar f
-      | _ -> assert false
-    in
-    let _, called_functions =
-      !Db.Value.expr_to_kernel_function
-        (Kstmt stmt) ~deps:(Some Locations.Zone.bottom) funcexp
-    in
-    Kernel_function.Hptset.elements called_functions
+    Eva.Results.callee stmt
 
   (** [call_id] is a call to [g] in [f].
    * we don't want [f] to call [g] anymore, so we have to update [g] [called_by]
@@ -1463,12 +1452,11 @@ let merge_fun_callers get_list get_value merge is_top acc kf =
           raise StopMerging (* acceleration when top is reached *)
       in
       let rec merge_fun_callers kf =
-        let merge_fun_caller (kf,_) = merge_fun_callers kf in
         let vf = Kernel_function.get_vi kf in
         if not (Cil_datatype.Varinfo.Set.mem vf !table) then begin
           table := Cil_datatype.Varinfo.Set.add vf !table ;
           List.iter (fun x -> merge (get_value x)) (get_list kf) ;
-          List.iter merge_fun_caller (!Db.Value.callers kf)
+          List.iter merge_fun_callers (Eva.Results.callers kf)
         end
         (*  else no way to add something, the [kf] contribution is already
             accumulated. *)
diff --git a/src/plugins/slicing/printSlice.ml b/src/plugins/slicing/printSlice.ml
index 63986e183ebb85760f6c4a16023d4139946f9927..9c5bd9baed6a1c0a0d18839fdf42c04c818018b5 100644
--- a/src/plugins/slicing/printSlice.ml
+++ b/src/plugins/slicing/printSlice.ml
@@ -204,10 +204,10 @@ module PrintProject = struct
   let iter_edges_src_fun f =
     let do_kf_calls kf =
       let fi = SlicingMacros.get_kf_fi kf in
-      let doit (kf_caller,_) =
+      let doit kf_caller =
         let fi_caller = SlicingMacros.get_kf_fi kf_caller in
         f ((Src fi_caller, Src fi), None)
-      in List.iter doit (!Db.Value.callers kf)
+      in List.iter doit (Eva.Results.callers kf)
     in
     Globals.Functions.iter do_kf_calls
 
diff --git a/src/plugins/slicing/register.ml b/src/plugins/slicing/register.ml
index 3f32606a217928ce557bfcc06f7d7b5c98c0dbea..4166762d3cc86694daf02f82b23262376cb39f89 100644
--- a/src/plugins/slicing/register.ml
+++ b/src/plugins/slicing/register.ml
@@ -27,7 +27,7 @@ let main () =
     (* have to do the value analysis before the selections
      * because some functions use its results,
      * and the value analysis is not launched automatically. *)
-    !Db.Value.compute ();
+    Eva.Analysis.compute ();
 
     let project_name = SlicingParameters.ProjectName.get () in
     Api.Project.reset_slicing ();
diff --git a/src/plugins/slicing/register_gui.ml b/src/plugins/slicing/register_gui.ml
index 0650a8a5d7d4ec67b06399f6dc4e4f0420060acc..92251b205bb8a73540f113861d13586c14e7b284 100644
--- a/src/plugins/slicing/register_gui.ml
+++ b/src/plugins/slicing/register_gui.ml
@@ -92,7 +92,7 @@ let msg_help_libraries =
    undefined functions."
 
 let check_value_computed (main_ui:Design.main_window_extension_points) =
-  if Db.Value.is_computed () then true
+  if Eva.Analysis.is_computed () then true
   else
     let answer = GToolbox.question_box
         ~title:("Eva Needed")
@@ -102,7 +102,7 @@ let check_value_computed (main_ui:Design.main_window_extension_points) =
          ^"Do you want to run Eva with its current settings now?")
     in
     if answer = 1 then
-      match main_ui#full_protect ~cancelable:true !Db.Value.compute with
+      match main_ui#full_protect ~cancelable:true Eva.Analysis.compute with
       | Some _ ->
         main_ui#redisplay (); (* New alarms *)
         true
@@ -116,7 +116,7 @@ let gui_apply_action (main_ui:Design.main_window_extension_points) f x ~info =
 
 let slicing_selector (popup_factory:GMenu.menu GMenu.factory)
     (main_ui:Design.main_window_extension_points) ~button localizable =
-  if (not (Db.Value.is_computed ()))
+  if (not (Eva.Analysis.is_computed ()))
   then
     ignore
       (popup_factory#add_item "Enable _slicing"
@@ -126,7 +126,7 @@ let slicing_selector (popup_factory:GMenu.menu GMenu.factory)
                 Enabled.set true;
                 !update_column `Visibility
               in
-              if (not (Db.Value.is_computed ())) then begin
+              if (not (Eva.Analysis.is_computed ())) then begin
                 if check_value_computed main_ui then enable ()
               end
               else enable ()
@@ -344,7 +344,7 @@ let slicing_selector (popup_factory:GMenu.menu GMenu.factory)
     in
     let some_kf_from_vi vi =
       try let kf = Globals.Functions.get vi in
-        if !Db.Value.is_called kf then Some kf else None
+        if Eva.Results.is_called kf then Some kf else None
       with Not_found -> None in
     let some_kf_from_lv  lv =
       match lv with
@@ -352,7 +352,7 @@ let slicing_selector (popup_factory:GMenu.menu GMenu.factory)
       | _ -> None
     in
     let some_kf_ki_lv kf stmt lvopt =
-      if !Db.Value.is_called kf && Db.Value.is_reachable_stmt stmt
+      if Eva.Results.is_called kf && Eva.Results.is_reachable stmt
       then Some (kf, stmt, lvopt) else None
     in
     begin  (* add menu for slicing and scope plug-in *)
@@ -386,7 +386,7 @@ let slicing_highlighter(buffer:Design.reactive_buffer) localizable ~start ~stop=
     let highlight () =
       let buffer = buffer#buffer in
       let ki = Pretty_source.ki_of_localizable localizable in
-      if Db.Value.is_accessible ki then
+      if Eva.Results.is_reachable_kinstr ki then
         let unused_code_area =
           Gtk_helper.make_tag buffer
             ~name:"slicing_unused" [`STRIKETHROUGH true ]
@@ -443,7 +443,7 @@ let slicing_highlighter(buffer:Design.reactive_buffer) localizable ~start ~stop=
           end
         in
         let tag_stmt kf stmt pb pe =
-          assert (Db.Value.is_reachable_stmt stmt) ;
+          assert (Eva.Results.is_reachable stmt) ;
           apply_on_one_project_and_merge_slices
             kf
             pb
@@ -554,7 +554,7 @@ let slicing_panel (main_ui:Design.main_window_extension_points) =
       (gui_set_slicing_level main_ui)
   in
   let refresh () =
-    let value_is_computed = Db.Value.is_computed () in
+    let value_is_computed = Eva.Analysis.is_computed () in
     let enabled = Enabled.get () in
     enabled_button#misc#set_sensitive value_is_computed ;
     slice_undef_button#misc#set_sensitive enabled ;
diff --git a/src/plugins/slicing/slicingCmds.ml b/src/plugins/slicing/slicingCmds.ml
index 79b59cc0fd5ac7c7124e56e0f1517303def29d20..8340d52e18cffd804ca5e09c873a6bfa1d634920 100644
--- a/src/plugins/slicing/slicingCmds.ml
+++ b/src/plugins/slicing/slicingCmds.ml
@@ -55,6 +55,10 @@ let apply_all ~propagate_to_callers =
 
 let get_select_kf (fvar, _select) = Globals.Functions.get fvar
 
+let get_lval_zone ?(access=Locations.Read) stmt lval =
+  let open Eva.Results in
+  before stmt |> eval_address lval |> as_zone ~access
+
 (** Utilities for [kinstr]. *)
 module Kinstr: sig
   val iter_from_func : (stmt -> unit) -> kernel_function -> unit
@@ -71,17 +75,14 @@ struct
     * i.e. directly means when [ki] is a call,
       it doesn't don't look at the assigns clause of the called function. *)
   let get_rw_zone stmt = (* returns [Zone.t read],[Zone.t written] *)
-    assert (Db.Value.is_computed ());
+    assert (Eva.Analysis.is_computed ());
     let lval_process read_zone stmt lv =
       (* returns [read_zone] joined to [Zone.t read] by [lv], [Zone.t written] by [lv] *)
       (* The modified locations are [looking_for], those address are
          function of [deps]. *)
-      let state = Db.Value.get_stmt_state stmt in
-      let deps, zloc, _exact =
-        !Db.Value.lval_to_zone_with_deps_state
-          state ~deps:(Some read_zone) ~for_writing:true lv
-      in
-      deps, zloc
+      let zloc = get_lval_zone ~access:Locations.Write stmt lv in
+      let deps = Eva.Results.(before stmt |> address_deps lv) in
+      Locations.Zone.join read_zone deps, zloc
     in
     let call_process lv f args _loc =
       (* returns  [Zone.t read] by [lv, f, args], [Zone.t written] by [lv] *)
@@ -184,8 +185,8 @@ let select_entry_point_and_some_inputs_outputs set ~mark kf ~return ~outputs ~in
       add_to_selection set selection
   in if ((Locations.Zone.equal Locations.Zone.bottom outputs) && not return) ||
         (try
-           let ki = Kernel_function.find_return kf
-           in if Db.Value.is_reachable_stmt ki then
+           let stmt = Kernel_function.find_return kf
+           in if Eva.Results.is_reachable stmt then
              false
            else
              begin
@@ -210,8 +211,8 @@ let select_entry_point_and_some_inputs_outputs set ~mark kf ~return ~outputs ~in
 (* apply [select ~spare] on each callsite of [kf] and add the returned selection
    to [set]. *)
 let generic_select_func_calls select_stmt set ~spare kf =
-  assert (Db.Value.is_computed ());
-  let callers = !Db.Value.callers kf in
+  assert (Eva.Analysis.is_computed ());
+  let callers = Eva.Results.callsites kf in
   let select_calls acc (caller, stmts) =
     List.fold_left (fun acc s -> select_stmt acc ~spare s caller) acc stmts
   in
@@ -245,7 +246,7 @@ let select_func_calls_to set ~spare kf =
         let nspare = not spare in
         SlicingMarks.mk_user_mark ~data:nspare ~addr:nspare ~ctrl:nspare
       in
-      assert (Db.Value.is_computed ());
+      assert (Eva.Analysis.is_computed ());
       let outputs = !Db.Outputs.get_external kf in
       select_entry_point_and_some_inputs_outputs set ~mark kf
         ~return:true
@@ -308,7 +309,7 @@ let select_stmt_zone set mark zone ~before ki kf =
     or after (c.f. boolean [~before]) the statement [ki].
     Note: add also a transparent selection on the whole statement. *)
 let select_stmt_lval set mark lval_str ~before ki ~eval kf =
-  assert (Db.Value.is_computed ());
+  assert (Eva.Analysis.is_computed ());
   if Datatype.String.Set.is_empty lval_str
   then set
   else
@@ -319,11 +320,7 @@ let select_stmt_lval set mark lval_str ~before ki ~eval kf =
            let lval =
              !Db.Properties.Interp.term_lval_to_lval ~result:None lval_term
            in
-           let state = Db.Value.get_stmt_state eval in
-           let _deps, zone, _exact =
-             !Db.Value.lval_to_zone_with_deps_state
-               ~deps:None ~for_writing:false state lval
-           in
+           let zone = get_lval_zone eval lval in
            Locations.Zone.join zone acc)
         lval_str
         Locations.Zone.bottom
@@ -342,7 +339,7 @@ let select_stmt_lval set mark lval_str ~before ki ~eval kf =
       i.e. when [ki_opt] is a call, the selection doesn't look at the assigns clause
       of a call. *)
 let select_lval_rw set mark ~rd ~wr ~eval kf ki_opt=
-  assert (Db.Value.is_computed ());
+  assert (Eva.Analysis.is_computed ());
   let zone_option ~for_writing lval_str =
     if Datatype.String.Set.is_empty lval_str
     then None
@@ -352,11 +349,8 @@ let select_lval_rw set mark ~rd ~wr ~eval kf ki_opt=
           (fun lval_str acc ->
              let lval_term = !Db.Properties.Interp.term_lval kf lval_str in
              let lval = !Db.Properties.Interp.term_lval_to_lval ~result:None lval_term in
-             let state = Db.Value.get_stmt_state eval in
-             let _deps, zone, _exact =
-               !Db.Value.lval_to_zone_with_deps_state
-                 state ~for_writing ~deps:None lval
-             in
+             let access = if for_writing then Locations.Write else Locations.Read in
+             let zone = get_lval_zone ~access eval lval in
              Locations.Zone.join zone acc)
           lval_str Locations.Zone.bottom
       in SlicingParameters.debug ~level:3
@@ -389,7 +383,7 @@ let select_lval_rw set mark ~rd ~wr ~eval kf ki_opt=
         | None ->
           Globals.Functions.iter
             (fun kf ->
-               if !Db.Value.is_called kf then
+               if Eva.Results.is_called kf then
                  if not (!Db.Value.use_spec_instead_of_definition kf)
                  then (* Called function with source code: just looks at its stmt *)
                    Kinstr.iter_from_func (select_rw_from_stmt kf) kf
@@ -413,7 +407,7 @@ let select_lval_rw set mark ~rd ~wr ~eval kf ki_opt=
                          ~return:false ~inputs ~outputs:Locations.Zone.bottom
 
                    in
-                   assert (!Db.Value.is_called kf) ; (* otherwise [!Db.Outputs.get_external kf] gives weird results *)
+                   assert (Eva.Results.is_called kf) ; (* otherwise [!Db.Outputs.get_external kf] gives weird results *)
                    select_inter_zone select_wr zone_wr_opt (!Db.Outputs.get_external kf) ;
                    select_inter_zone select_rd zone_rd_opt (!Db.Inputs.get_external kf)
                  end
diff --git a/src/plugins/slicing/slicingMacros.ml b/src/plugins/slicing/slicingMacros.ml
index d49a3f596c1632a67974dc3aefcfe1553699c28d..ebb985bc1985e17a25ddb057e273ed32aef42a9c 100644
--- a/src/plugins/slicing/slicingMacros.ml
+++ b/src/plugins/slicing/slicingMacros.ml
@@ -173,12 +173,9 @@ let is_call_stmt stmt =
   | Instr (Call _ | Local_init(_, ConsInit _,_)) -> true | _ -> false
 
 let get_called_kf call_stmt = match call_stmt.skind with
-  | Instr (Call (_, funcexp,_,_)) ->
-    let _funcexp_dpds, called_functions =
-      !Db.Value.expr_to_kernel_function ~deps:None (Kstmt call_stmt) funcexp
-    in
-    (match Kernel_function.Hptset.contains_single_elt called_functions with
-     | Some kf -> kf
+  | Instr (Call _) ->
+    (match Eva.Results.callee call_stmt with
+     | [kf] -> kf
      | _ -> raise SlicingTypes.PtrCallExpr)
   | Instr (Local_init(_, ConsInit (f, _, _), _)) -> Globals.Functions.get f
   | _ -> invalid_arg "Not a call statement !"
diff --git a/src/plugins/slicing/slicingProject.ml b/src/plugins/slicing/slicingProject.ml
index 73532548cc680d1e25e1d22b8fa9a079ccb49a9b..010cbdd86d44d86398a97ab5efe9e2f392998268 100644
--- a/src/plugins/slicing/slicingProject.ml
+++ b/src/plugins/slicing/slicingProject.ml
@@ -222,13 +222,13 @@ let apply_appli_crit appli_crit =
   match appli_crit with
   | T.CaCall fi_to_call ->
     let kf_to_call = M.get_fi_kf fi_to_call in
-    let add_actions actions (kf_caller,_) =
+    let add_actions actions kf_caller =
       let fi_caller = M.get_kf_fi kf_caller in
       let mark = SlicingMarks.mk_user_spare in
       let action =
         SlicingActions.mk_crit_mark_calls fi_caller kf_to_call mark in
       action :: actions
-    in List.fold_left add_actions [] (!Db.Value.callers kf_to_call)
+    in List.fold_left add_actions [] (Eva.Results.callers kf_to_call)
   | _ ->
     SlicingParameters.not_yet_implemented
       "This slicing criterion on application"
diff --git a/src/plugins/slicing/slicingSelect.ml b/src/plugins/slicing/slicingSelect.ml
index 5775c6ecbe4f45d9c3540775f6a1062325efd5a6..b4b331aabe20174accb29534e0e15179b06d3aec 100644
--- a/src/plugins/slicing/slicingSelect.ml
+++ b/src/plugins/slicing/slicingSelect.ml
@@ -105,7 +105,7 @@ let select_stmt_zone kf ?(select=empty_db_select kf) stmt ~before loc mark =
     Locations.Zone.pretty loc
     (if before then "before" else "after") stmt.sid
     SlicingMarks.pretty_mark mark;
-  if not (Db.Value.is_reachable_stmt stmt) then
+  if not (Eva.Results.is_reachable stmt) then
     begin
       SlicingParameters.feedback
         "@[Nothing to select for @[%a@]@ %s unreachable stmt of %a@]"
@@ -194,7 +194,7 @@ let stmt_nodes_to_select pdg stmt =
 
 let select_stmt_computation kf ?(select=empty_db_select kf) stmt mark =
   SlicingParameters.debug ~level:1 "[Register.select_stmt_computation] on stmt %d" stmt.sid;
-  if not (Db.Value.is_reachable_stmt stmt) then
+  if not (Eva.Results.is_reachable stmt) then
     begin
       SlicingParameters.feedback
         "@[Nothing to select for an unreachable stmt of %a@]"
diff --git a/src/plugins/slicing/slicingState.ml b/src/plugins/slicing/slicingState.ml
index 93a4ad676a17dfd508df128dec7f32b16c2fe1b8..4b9a224a47538ed45941692170d9cea09894a585 100644
--- a/src/plugins/slicing/slicingState.ml
+++ b/src/plugins/slicing/slicingState.ml
@@ -49,7 +49,7 @@ let may_map ~none f = match P.get_option () with
   | Some _ -> f ()
 
 let reset_slicing () =
-  !Db.Value.compute () ;
+  Eva.Analysis.compute () ;
   let initialized = match P.get_option () with | None -> false | Some _ -> true in
   if not initialized then
     SlicingParameters.feedback ~level:1 "initializing slicing ..."
diff --git a/src/plugins/slicing/slicingTransform.ml b/src/plugins/slicing/slicingTransform.ml
index c27b8a15e3be1be8bb12135b32ffba67d21e6533..9a4723f972394a8c7158259f38c6a7a6d69e01a6 100644
--- a/src/plugins/slicing/slicingTransform.ml
+++ b/src/plugins/slicing/slicingTransform.ml
@@ -234,7 +234,7 @@ module Visibility (SliceName : sig
   let annotation_visible ff_opt stmt annot =
     SlicingParameters.debug ~current:true ~level:2
       "[SlicingTransform.Visibility.annotation_visible] ?";
-    Db.Value.is_reachable_stmt stmt &&
+    Eva.Results.is_reachable stmt &&
     Alarms.find annot = None && (* Always drop alarms: the alarms table
                                    in the new project is not synchronized *)
     match ff_opt with
diff --git a/src/plugins/sparecode/register.ml b/src/plugins/sparecode/register.ml
index a6c985c0dc8ebfa6dc8f75311a28460c62ad48b9..a6a1fa9a5bfab44f202049b1b4c4b67773b30e78 100644
--- a/src/plugins/sparecode/register.ml
+++ b/src/plugins/sparecode/register.ml
@@ -35,7 +35,7 @@ module Result =
     (struct
       let name = "Sparecode"
       let size = 7
-      let dependencies = [ Ast.self; Db.Value.self ] (* delayed, see below *)
+      let dependencies = [ Ast.self; Eva.Analysis.self ] (* delayed, see below *)
     end)
 
 let () =
diff --git a/src/plugins/sparecode/transform.ml b/src/plugins/sparecode/transform.ml
index ce447c3fb94eecd147f1fd0adf0f111c4854a471..8c9fb9a68f6d4fde5b84a591d0600cfa59161639 100644
--- a/src/plugins/sparecode/transform.ml
+++ b/src/plugins/sparecode/transform.ml
@@ -81,7 +81,7 @@ module BoolInfo = struct
     key_visible "label_visible" fm lab_key
 
   let annotation_visible _ stmt annot =
-    Db.Value.is_reachable_stmt stmt && Alarms.find annot = None
+    Eva.Results.is_reachable stmt && Alarms.find annot = None
   (* Keep annotations on reachable, but not alarms: they can be resynthesized,
      and the alarms table is not synchronized in the new project anyway *)
   (* TODO: does not seem really coherent with the fact that almost everything
@@ -126,13 +126,11 @@ module BoolInfo = struct
   let called_info (project, _fm) call_stmt =
     match call_stmt.skind with
     | Instr (Call (_, _, _, _) | Local_init(_, ConsInit _, _)) ->
-      let called_functions = Db.Value.call_to_kernel_function call_stmt in
+      let called_functions = Eva.Results.callee call_stmt in
       let call_info =
-        match
-          Kernel_function.Hptset.contains_single_elt called_functions
-        with
-        | None -> None
-        | Some kf ->
+        match called_functions with
+        | [] | _ :: _  :: _ -> None
+        | [kf] ->
           match Spare_marks.get_marks project kf with
           | None ->
             if Spare_marks.kf_visible project kf
diff --git a/src/plugins/studia/reads.ml b/src/plugins/studia/reads.ml
index 3685d8cba7b689b4e0ee46f1408db61985065d61..0a432ee23a669275b49c37bbc8324b1974c869c3 100644
--- a/src/plugins/studia/reads.ml
+++ b/src/plugins/studia/reads.ml
@@ -44,15 +44,13 @@ class find_read zlval = object
         let deps = match lvopt with
           | None -> deps
           | Some lv ->
-            let dlv, _ =
-              !Db.Value.lval_to_loc_with_deps (Kstmt stmt) ~deps:Zone.bottom lv
-            in
+            let dlv = Eva.Results.(before stmt |> address_deps lv) in
             Zone.join dlv deps
         in
         let direct = Zone.intersects deps zlval in
         (* now determine if the functions called at [stmt] read directly or
              indirectly [zlval] *)
-        let aux_kf kf effects =
+        let aux_kf effects kf =
           let inputs = !Db.Inputs.get_internal kf in
           (* TODO: change to this once we can get "full" inputs through Inout.
              Currently, non operational inputs disappear, and this function
@@ -68,9 +66,9 @@ class find_read zlval = object
           else
             effects (* this function pointer does not read [zlval] *)
         in
-        let kfs = Db.Value.call_to_kernel_function stmt in
+        let kfs = Eva.Results.callee stmt in
         let effects =
-          Kernel_function.Hptset.fold aux_kf kfs {direct; indirect = false}
+          List.fold_left aux_kf {direct; indirect = false} kfs
         in
         res <- (stmt, effects) :: res
       end
diff --git a/src/plugins/studia/studia_gui.ml b/src/plugins/studia/studia_gui.ml
index 9008db351027fc01dcfd385aba799782e8a4f718..c7b1425c394d7c776424631c55b840ec99640425 100644
--- a/src/plugins/studia/studia_gui.ml
+++ b/src/plugins/studia/studia_gui.ml
@@ -90,7 +90,7 @@ struct
       (Stmt.Map.Make(Datatype.String.Set))
       (struct
         let name = Info.name
-        let dependencies = [ Db.Value.self ]
+        let dependencies = [ Eva.Analysis.self ]
         let default () = Stmt.Map.empty
       end)
 
@@ -184,7 +184,7 @@ module StudiaState =
     (Stmt)
     (struct
       let name = "Studia.Highlighter.StudiaState"
-      let dependencies = [ Db.Value.self ]
+      let dependencies = [ Eva.Analysis.self ]
     end)
 
 let reset () =
@@ -226,7 +226,7 @@ let highlighter (buffer:Design.reactive_buffer) localizable ~start ~stop =
   with Not_found -> ()
 
 let check_value (main_ui:Design.main_window_extension_points) =
-  Db.Value.is_computed () ||
+  Eva.Analysis.is_computed () ||
   let answer = GToolbox.question_box
       ~title:("Eva Needed")
       ~buttons:[ "Run"; "Cancel" ]
@@ -234,7 +234,7 @@ let check_value (main_ui:Design.main_window_extension_points) =
        ^"Do you want to run Eva now ?")
   in
   answer = 1 &&
-  match main_ui#full_protect ~cancelable:true !Db.Value.compute with
+  match main_ui#full_protect ~cancelable:true Eva.Analysis.compute with
   | Some _ -> true
   | None -> false
 
diff --git a/src/plugins/studia/studia_request.ml b/src/plugins/studia/studia_request.ml
index ff3f94c3d1061bc178020507cb565241d5cb20dc..2e44a1b8e8f0d4c9503225954eefa4578b65d3b9 100644
--- a/src/plugins/studia/studia_request.ml
+++ b/src/plugins/studia/studia_request.ml
@@ -81,7 +81,8 @@ let compute kind zone =
   let empty = { direct = []; indirect = []; } in
   List.fold_left add empty stmts
 
-let lval_location kinstr lval = !Db.Value.lval_to_zone kinstr lval
+let lval_location kinstr lval =
+  Eva.Results.(before_kinstr kinstr |> eval_address lval |> as_zone)
 
 let () = Request.register ~package
     ~kind:`GET ~name:"getReadsLval"
diff --git a/src/plugins/studia/writes.ml b/src/plugins/studia/writes.ml
index fa29b18e974c25b9234fa1e95b11f4f3fd8005aa..dbcbcfc04cea20a2596da29b264f3ea0e4b852ee 100644
--- a/src/plugins/studia/writes.ml
+++ b/src/plugins/studia/writes.ml
@@ -35,7 +35,7 @@ type effects = {
 
 (** Does the functions called at [stmt] modify directly or indirectly [zlval] *)
 let effects_of_call stmt zlval effects  =
-  let aux_kf kf effects =
+  let aux_kf effects kf =
     let inout = !Db.Operational_inputs.get_internal_precise ~stmt kf in
     let out = inout.Inout_type.over_outputs in
     if Zone.intersects out zlval then
@@ -47,8 +47,8 @@ let effects_of_call stmt zlval effects  =
     else
       effects
   in
-  let kfs = Db.Value.call_to_kernel_function stmt in
-  Kernel_function.Hptset.fold aux_kf kfs effects
+  let kfs = Eva.Results.callee stmt in
+  List.fold_left aux_kf effects kfs
 
 class find_write zlval = object (self)
   inherit Visitor.frama_c_inplace
@@ -66,8 +66,8 @@ class find_write zlval = object (self)
           let direct_write = match lvopt with
             | None -> false
             | Some lv ->
-              let zlv = !Db.Value.lval_to_zone (Kstmt stmt) lv in
-              Zone.intersects zlv zlval
+              Eva.Results.(before stmt |> eval_address lv |> as_zone_result) |>
+              Result.fold ~ok:(Zone.intersects zlval) ~error:(fun _ -> false)
           in
           let effects =
             effects_of_call stmt zlval {direct = direct_write; indirect =false}
diff --git a/src/plugins/users/users_register.ml b/src/plugins/users/users_register.ml
index f556af9526d47558f4ee79c364b2a0db5cb08162..a57f90f00f611368777176fdc7dc2fd6c41dc995 100644
--- a/src/plugins/users/users_register.ml
+++ b/src/plugins/users/users_register.ml
@@ -79,7 +79,7 @@ let get kf =
   if Users.is_computed () then
     find kf
   else begin
-    if Db.Value.is_computed () then begin
+    if Eva.Analysis.is_computed () then begin
       feedback "requiring again the computation of the value analysis";
       Project.clear
         ~selection:(State_selection.with_dependencies Db.Value.self)
@@ -87,7 +87,7 @@ let get kf =
     end else
       feedback ~level:2 "requiring the computation of the value analysis";
     add_value_hook ();
-    !Db.Value.compute ();
+    Eva.Analysis.compute ();
     find kf
   end
 
diff --git a/src/plugins/value/Eva.mli b/src/plugins/value/Eva.mli
index 74ac173305e0e35d0eecdebbcca95a211bf0a8b4..58006b2c451753ca0a1707acada914bcd5106ac6 100644
--- a/src/plugins/value/Eva.mli
+++ b/src/plugins/value/Eva.mli
@@ -1,38 +1,308 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of Frama-C.                                         *)
-(*                                                                        *)
-(*  Copyright (C) 2007-2021                                               *)
-(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
-(*         alternatives)                                                  *)
-(*                                                                        *)
-(*  you can redistribute it and/or modify it under the terms of the GNU   *)
-(*  Lesser General Public License as published by the Free Software       *)
-(*  Foundation, version 2.1.                                              *)
-(*                                                                        *)
-(*  It is distributed in the hope that it will be useful,                 *)
-(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
-(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
-(*  GNU Lesser General Public License for more details.                   *)
-(*                                                                        *)
-(*  See the GNU Lesser General Public License version 2.1                 *)
-(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
-(*                                                                        *)
-(**************************************************************************)
-
-(** Analysis for values and pointers *)
+(** Eva public API.
 
-module Value_results: sig
-  type results
+   The main modules are:
+   - Analysis: run the analysis.
+   - Results: access analysis results, especially the values of expressions
+      and memory locations of lvalues at each program point.
+
+   The following modules allow configuring the Eva analysis:
+   - Value_parameters: change the configuration of the analysis.
+   - Eva_annotations: add local annotations to guide the analysis.
+   - Builtins: register ocaml builtins to be used by the cvalue domain
+       instead of analysing the body of some C functions.
+
+   Other modules are for internal use only. *)
+
+(* This file is generated. Do not edit. *)
+
+module Analysis: sig
+  val compute : unit -> unit
+  (** Computes the Eva analysis, if not already computed, using the entry point
+      of the current project. You may set it with {!Globals.set_entry_point}.
+      @raise Globals.No_such_entry_point if the entry point is incorrect
+      @raise Db.Value.Incorrect_number_of_arguments if some arguments are
+      specified for the entry point using {!Db.Value.fun_set_args}, and
+      an incorrect number of them is given.
+      @plugin development guide *)
+
+  val is_computed : unit -> bool
+  (** Return [true] iff the Eva analysis has been done. *)
+
+  val self : State.t
+  (** Internal state of Eva analysis from projects viewpoint. *)
+end
+
+module Results: sig
+  (** Eva's result API is a work-in-progress interface to allow accessing the
+      analysis results once its completed. It is experimental and is very likely
+      to change in the future. It aims at replacing [Db.Value] but does not
+      completely covers all its usages yet. As for now, this interface has some
+      advantages over Db's :
+
+      - evaluations uses every available domains and not only Cvalue;
+      - the caller may distinguish failure cases when a request is unsucessful;
+      - working with callstacks is easy;
+      - some common shortcuts are provided (e.g. for extracting ival directly);
+      - overall, individual functions are simpler.
+
+      The idea behind this API is that requests must be decomposed in several
+      steps. For instance, to evaluate an expression :
+
+      1. first, you have to state where you want to evaluate it,
+      2. optionally, you may specify in which callstack,
+      3. you choose the expression to evaluate,
+      4. you require a destination type to evaluate into.
+
+      Usage sketch :
+
+      Eva.Results.(
+        before stmt |> in_callstack cs |>
+        eval_var vi |> as_int |> default 0)
+
+      or equivalently, if you prefer
+
+      Eva.Results.(
+        default O (as_int (eval_var vi (in_callstack cs (before stmt))))
+  *)
+
+
+  type callstack = (Cil_types.kernel_function * Cil_types.kinstr) list
+
+  type request
+
+  type value
+  type address
+  type 'a evaluation
+
+  type error = Bottom | Top | DisabledDomain
+  type 'a result = ('a,error) Result.t
+
+
+  (** Results handling *)
+
+  (** Translates an error to a human readable string. *)
+  val string_of_error : error -> string
+
+  (** Pretty printer for errors. *)
+  val pretty_error : Format.formatter -> error -> unit
+
+  (** Pretty printer for API's results. *)
+  val pretty_result : (Format.formatter -> 'a -> unit) ->
+    Format.formatter -> 'a result -> unit
+
+  (** [default d r] extracts the value of [r] if [r] is Ok,
+      or use the default value [d] otherwise.
+      Equivalent to [Result.value ~default:d r] *)
+  val default : 'a -> 'a result -> 'a
+
+
+  (** Control point selection *)
+
+  (** At the start of the analysis, but after the initialization of globals. *)
+  val at_start : request
+
+  (** At the end of the analysis, after the main function has returned. *)
+  val at_end : unit -> request
+
+  (** At the start of the given function. *)
+  val at_start_of : Cil_types.kernel_function -> request
+
+  (** At the end of the given function.
+      @raises Kernel_function.No_statement if the function has no body. *)
+  val at_end_of : Cil_types.kernel_function -> request
+
+  (** Just before a statement is executed. *)
+  val before : Cil_types.stmt -> request
+
+  (** Just after a statement is executed. *)
+  val after : Cil_types.stmt -> request
+
+  (** Just before a statement or at the start of the analysis. *)
+  val before_kinstr : Cil_types.kinstr -> request
+
+
+  (** Callstack selection *)
+
+  (** Only consider the given callstack.
+      Replaces previous calls to [in_callstack] or [in_callstacks]. *)
+  val in_callstack : callstack -> request -> request
+
+  (** Only consider the callstacks from the given list.
+      Replaces previous calls to [in_callstack] or [in_callstacks]. *)
+  val in_callstacks : callstack list -> request -> request
+
+  (** Only consider callstacks satisfying the given predicate. Several filters
+      can be added. If callstacks are also selected with [in_callstack] or
+      [in_callstacks], only the selected callstacks will be filtered. *)
+  val filter_callstack : (callstack -> bool) -> request -> request
+
+
+  (** Working with callstacks *)
+
+  (** Returns the list of reachable callstacks from the given request.
+      An empty list is returned if the request control point has not been
+      reached by the analysis, or if no information has been saved at this point
+      (for instance with the -eva-no-results option).
+      Use [is_empty request] to distinguish these two cases. *)
+  val callstacks : request -> callstack list
+
+  (** Returns a list of subrequests for each reachable callstack from
+      the given request. *)
+  val by_callstack : request -> (callstack * request) list
+
+
+  (** State requests *)
+
+  (** Returns the list of expressions which have been inferred to be equal to
+      the given expression by the Equality domain. *)
+  val equality_class : Cil_types.exp -> request -> Cil_types.exp list result
+
+  (** Returns the Cvalue state. Error cases are converted into the bottom or top
+      cvalue state accordingly. *)
+  val get_cvalue_model : request -> Cvalue.Model.t
+
+  (** Returns the Cvalue model. *)
+  val get_cvalue_model_result : request -> Cvalue.Model.t result
+
+
+  (** Dependencies *)
+
+  (** Computes (an overapproximation of) the memory zones that must be read to
+      evaluate the given expression, including all adresses computations. *)
+  val expr_deps : Cil_types.exp -> request -> Locations.Zone.t
+
+  (** Computes (an overapproximation of) the memory zones that must be read to
+      evaluate the given lvalue, including the lvalue zone itself. *)
+  val lval_deps : Cil_types.lval -> request -> Locations.Zone.t
+
+  (** Computes (an overapproximation of) the memory zones that must be read to
+      evaluate the given lvalue, excluding the lvalue zone itself. *)
+  val address_deps : Cil_types.lval -> request -> Locations.Zone.t
+
+
+  (** Evaluation *)
+
+  (** Returns (an overapproximation of) the possible values of the variable. *)
+  val eval_var : Cil_types.varinfo -> request -> value evaluation
+
+  (** Returns (an overapproximation of) the possible values of the lvalue. *)
+  val eval_lval : Cil_types.lval -> request -> value evaluation
+
+  (** Returns (an overapproximation of) the possible values of the expression. *)
+  val eval_exp : Cil_types.exp -> request -> value evaluation
+
+
+  (** Returns (an overapproximation of) the possible addresses of the lvalue. *)
+  val eval_address : Cil_types.lval -> request -> address evaluation
+
+
+  (** Returns the kernel functions into which the given expression may evaluate.
+      If the callee expression doesn't always evaluate to a function, those
+      spurious values are ignored. If it always evaluate to a non-function value
+      then the returned list is empty.
+      Raises [Stdlib.Invalid_argument] if the callee expression is not an lvalue
+      without offset.
+      Also see [callee] for a function which applies directly on Call
+      statements. *)
+  val eval_callee : Cil_types.exp -> request -> Kernel_function.t list result
+
+
+  (** Evaluated values conversion *)
+
+  (** In all functions below, if the abstract value inferred by Eva does not fit
+      in the required type, [Error Top] is returned, as Top is the only possible
+      over-approximation of the request. *)
+
+  (** Converts the value into a singleton ocaml int. *)
+  val as_int : value evaluation -> int result
+
+  (** Converts the value into a singleton unbounded integer. *)
+  val as_integer : value evaluation -> Integer.t result
+
+  (** Converts the value into a floating point number. *)
+  val as_float : value evaluation -> float result
+
+  (** Converts the value into a C number abstraction. *)
+  val as_ival : value evaluation -> Ival.t result
+
+  (** Converts the value into a floating point abstraction. *)
+  val as_fval : value evaluation -> Fval.t result
+
+  (** Converts the value into a Cvalue abstraction. Converts error cases
+      into bottom and top values accordingly. *)
+  val as_cvalue : value evaluation -> Cvalue.V.t
+
+  (** Converts the value into a Cvalue abstraction. *)
+  val as_cvalue_result : value evaluation -> Cvalue.V.t result
+
+
+  (** Converts into a C location abstraction. *)
+  val as_location : address evaluation -> Locations.location result
+
+  (** Converts into a Zone. Error cases are converted into bottom or top zones
+      accordingly. *)
+  val as_zone: ?access:Locations.access -> address evaluation ->
+    Locations.Zone.t
+
+  (** Converts into a Zone result. *)
+  val as_zone_result : ?access:Locations.access -> address evaluation ->
+    Locations.Zone.t result
+
+
+  (** Evaluation properties *)
+
+  (** Returns whether the evaluated value is initialized or not. If the value have
+      been evaluated from a Cil expression, it is always initialized. *)
+  val is_initialized : value evaluation -> bool
+
+  (** Returns the set of alarms emitted during the evaluation. *)
+  val alarms : 'a evaluation -> Alarms.t list
+
+
+  (** Reachability *)
+
+  (** Returns true if there are no reachable states for the given request. *)
+  val is_empty : request -> bool
+
+  (** Returns true if an evaluation leads to bottom, i.e. if the given expression
+      or lvalue cannot be evaluated to a valid result for the given request. *)
+  val is_bottom : 'a evaluation -> bool
+
+  (** Returns true if the function has been analyzed. *)
+  val is_called : Cil_types.kernel_function -> bool
+
+  (** Returns true if the statement has been reached by the analysis. *)
+  val is_reachable : Cil_types.stmt -> bool
+
+  (** Returns true if the statement has been reached by the analysis, or if
+      the main function has been analyzed for [Kglobal]. *)
+  val is_reachable_kinstr : Cil_types.kinstr -> bool
+
+
+  (*** Callers / Callees / Callsites *)
+
+  (** Returns the list of inferred callers of the given function. *)
+  val callers : Cil_types.kernel_function -> Cil_types.kernel_function list
+
+  (** Returns the list of inferred callers, and for each of them, the list
+      of callsites (the call statements) inside. *)
+  val callsites : Cil_types.kernel_function ->
+    (Cil_types.kernel_function * Cil_types.stmt list) list
+
+
+  (** Returns the kernel functions called in the given statement.
+      If the callee expression doesn't always evaluate to a function, those
+      spurious values are ignored. If it always evaluate to a non-function value
+      then the returned list is empty.
+      Raises [Stdlib.Invalid_argument] if the statement is not a [Call]
+      instruction or a [Local_init] with [ConsInit] initializer. *)
+  val callee : Cil_types.stmt -> Kernel_function.t list
 
-  val get_results: unit -> results
-  val set_results: results -> unit
-  val merge: results -> results -> results
-  val change_callstacks:
-    (Value_types.callstack -> Value_types.callstack) -> results -> results
 end
 
 module Value_parameters: sig
+  (** Configuration of the analysis. *)
+
   (** Returns the list (name, descr) of currently enabled abstract domains. *)
   val enabled_domains: unit -> (string * string) list
 
@@ -46,36 +316,16 @@ module Value_parameters: sig
   val use_global_value_partitioning: Cil_types.varinfo -> unit
 end
 
-module Eval_terms: sig
-  (** Evaluation environment, built by [env_annot]. *)
-  type eval_env
-
-  (** Dependencies needed to evaluate a term or a predicate. *)
-  type logic_deps = Locations.Zone.t Cil_datatype.Logic_label.Map.t
-
-  type labels_states = Db.Value.state Cil_datatype.Logic_label.Map.t
-
-  val env_annot :
-    ?c_labels:labels_states -> pre:Db.Value.state -> here:Db.Value.state ->
-    unit -> eval_env
-
-  (** [predicate_deps env p] computes the logic dependencies needed to evaluate
-      [p] in the given evaluation environment [env].
-      @return None on either an evaluation error or on unsupported construct. *)
-  val predicate_deps: eval_env -> Cil_types.predicate -> logic_deps option
-end
-
-
-module Unit_tests: sig
-  (** Runs the unit tests of Eva. *)
-  val run: unit -> unit
-end
-
-(** Register special annotations to locally guide the partitioning of states
-    performed by an Eva analysis. *)
 module Eva_annotations: sig
+  (** Register special annotations to locally guide the Eva analysis:
 
-  (** Annotations tweaking the behavior of the -eva-slevel paramter. *)
+      - slevel annotations: "slevel default", "slevel merge" and "slevel i"
+      - loop unroll annotations: "loop unroll term"
+      - value partitioning annotations: "split term" and "merge term"
+      - subdivision annotations: "subdivide i"
+  *)
+
+  (** Annotations tweaking the behavior of the -eva-slevel parameter. *)
   type slevel_annotation =
     | SlevelMerge        (** Join all states separated by slevel. *)
     | SlevelDefault      (** Use the limit defined by -eva-slevel. *)
@@ -88,6 +338,7 @@ module Eva_annotations: sig
     | UnrollFull (** Unroll amount defined by -eva-default-loop-unroll. *)
 
   type split_kind = Static | Dynamic
+
   type split_term =
     | Expression of Cil_types.exp
     | Predicate of Cil_types.predicate
@@ -99,10 +350,13 @@ module Eva_annotations: sig
     | FlowMerge of split_term
     (** Merge states separated by a previous split. *)
 
+  type allocation_kind = By_stack | Fresh | Fresh_weak | Imprecise
+
   val get_slevel_annot : Cil_types.stmt -> slevel_annotation option
   val get_unroll_annot : Cil_types.stmt -> unroll_annotation list
   val get_flow_annot : Cil_types.stmt -> flow_annotation list
   val get_subdivision_annot : Cil_types.stmt -> int list
+  val get_allocation: Cil_types.stmt -> allocation_kind
 
   val add_slevel_annot : emitter:Emitter.t ->
     Cil_types.stmt -> slevel_annotation -> unit
@@ -114,33 +368,105 @@ module Eva_annotations: sig
     Cil_types.stmt -> int -> unit
 end
 
-(** Analysis builtins for the cvalue domain, more efficient than the analysis
-    of the C functions. See {builtins.mli} for more details. *)
+module Eval: sig
+  (** Can the results of a function call be cached with memexec? *)
+  type cacheable =
+    | Cacheable      (** Functions whose result can be safely cached. *)
+    | NoCache        (** Functions whose result should not be cached, but for
+                         which the caller can still be cached. Typically,
+                         functions printing something during the analysis. *)
+    | NoCacheCallers (** Functions for which neither the call, neither the
+                         callers, can be cached. *)
+end
+
 module Builtins: sig
+  (** Eva analysis builtins for the cvalue domain, more efficient than their
+      equivalent in C. *)
+
   open Cil_types
 
   exception Invalid_nb_of_args of int
   exception Outside_builtin_possibilities
 
+  (* Signature of a builtin: type of the result, and type of the arguments. *)
   type builtin_type = unit -> typ * typ list
-  type cacheable = Cacheable | NoCache | NoCacheCallers
+
+  (** Can the results of a builtin be cached? See {eval.mli} for more details.*)
+  type cacheable = Eval.cacheable = Cacheable | NoCache | NoCacheCallers
 
   type full_result = {
     c_values: (Cvalue.V.t option * Cvalue.Model.t) list;
+    (** A list of results, consisting of:
+        - the value returned (ie. what is after the 'return' C keyword)
+        - the memory state after the function has been executed. *)
     c_clobbered: Base.SetLattice.t;
+    (** An over-approximation of the bases in which addresses of local variables
+        might have been written *)
     c_from: (Function_Froms.froms * Locations.Zone.t) option;
+    (** If not None, the froms of the function, and its sure outputs;
+        i.e. the dependencies of the result and of each zone written to. *)
   }
 
+  (** The result of a builtin can be given in different forms. *)
   type call_result =
     | States of Cvalue.Model.t list
+    (** A disjunctive list of post-states at the end of the C function.
+        Can only be used if the C function does not write the address of local
+        variables, does not read other locations than the call arguments, and
+        does not write other locations than the result. *)
     | Result of Cvalue.V.t list
+    (** A disjunctive list of resulting values. The specification is used to
+        compute the post-state, in which the result is replaced by the values
+        computed by the builtin. *)
     | Full of full_result
+    (** See [full_result] type. *)
 
+  (** Type of a cvalue builtin, whose arguments are:
+      - the memory state at the beginning of the function call;
+      - the list of arguments of the function call. *)
   type builtin = Cvalue.Model.t -> (exp * Cvalue.V.t) list -> call_result
 
+  (** [register_builtin name ?replace ?typ cacheable f] registers the function [f]
+      as a builtin to be used instead of the C function of name [name].
+      If [replace] is provided, the builtin is also used instead of the C function
+      of name [replace], unless option -eva-builtin-auto is disabled.
+      If [typ] is provided, consistency between the expected [typ] and the type of
+      the C function is checked before using the builtin.
+      The results of the builtin are cached according to [cacheable]. *)
   val register_builtin:
-    string -> ?replace:string -> ?typ:builtin_type -> cacheable ->
-    builtin -> unit
+    string -> ?replace:string -> ?typ:builtin_type -> cacheable -> builtin -> unit
 
+  (** Has a builtin been registered with the given name? *)
   val is_builtin: string -> bool
 end
+
+module Eval_terms: sig
+  (** [annot_predicate_deps ~pre ~here p] computes the logic dependencies needed
+      to evaluate the predicate [p] in a code annotation in cvalue state [here],
+      in a function whose pre-state is [pre].
+      Returns None on either an evaluation error or on unsupported construct. *)
+  val annot_predicate_deps:
+    pre:Cvalue.Model.t -> here:Cvalue.Model.t ->
+    Cil_types.predicate -> Locations.Zone.t option
+end
+
+module Value_results: sig
+  type results
+
+  val get_results: unit -> results
+  val set_results: results -> unit
+  val merge: results -> results -> results
+  val change_callstacks:
+    (Value_types.callstack -> Value_types.callstack) -> results -> results
+  (** Change the callstacks for the results for which this is meaningful.
+      For technical reasons, the top of the callstack must currently
+      be preserved. *)
+end
+
+module Unit_tests: sig
+  (** Currently tested by this module:
+      - semantics of sign values. *)
+
+  (** Runs some programmatic tests on Eva. *)
+  val run: unit -> unit
+end
diff --git a/src/plugins/value/api/general_requests.ml b/src/plugins/value/api/general_requests.ml
index 1b226d8e8d271a6d3b5a718d3b81e5c33d6c96e8..8d6e48f7301153d4eb7a85c70cb5e87318c433d1 100644
--- a/src/plugins/value/api/general_requests.ml
+++ b/src/plugins/value/api/general_requests.ml
@@ -57,7 +57,7 @@ let _computation_signal =
     ()
 
 let is_computed kf =
-  Db.Value.is_computed () &&
+  Analysis.is_computed () &&
   match kf with
   | { fundec = Definition (fundec, _) } ->
     Mark_noresults.should_memorize_function fundec
@@ -66,7 +66,7 @@ let is_computed kf =
 module CallSite = Data.Jpair (Kernel_ast.Kf) (Kernel_ast.Stmt)
 
 let callers kf =
-  let list = !Db.Value.callers kf in
+  let list = Value_results.callers kf in
   List.concat (List.map (fun (kf, l) -> List.map (fun s -> kf, s) l) list)
 
 let () = Request.register ~package
diff --git a/src/plugins/value/domains/cvalue/builtins.mli b/src/plugins/value/domains/cvalue/builtins.mli
index 353be4b52e81e4b3ef4ee8c9b868a391d0f7f2e8..ac9751b56a819843af15c3d267555c1966c253f9 100644
--- a/src/plugins/value/domains/cvalue/builtins.mli
+++ b/src/plugins/value/domains/cvalue/builtins.mli
@@ -20,6 +20,7 @@
 (*                                                                        *)
 (**************************************************************************)
 
+[@@@ api_start]
 (** Eva analysis builtins for the cvalue domain, more efficient than their
     equivalent in C. *)
 
@@ -78,6 +79,7 @@ val register_builtin:
 
 (** Has a builtin been registered with the given name? *)
 val is_builtin: string -> bool
+[@@@ api_end]
 
 (** Prepares the builtins to be used for an analysis. Must be called at the
     beginning of each Eva analysis. Warns about builtins of incompatible types,
diff --git a/src/plugins/value/domains/equality/equality.mli b/src/plugins/value/domains/equality/equality.mli
index 87ef746f453b17bf99e21e3dfe59610aa01c1a0c..3e92e268f8a59aa7c7364038d0d3ed9e74f985f5 100644
--- a/src/plugins/value/domains/equality/equality.mli
+++ b/src/plugins/value/domains/equality/equality.mli
@@ -88,6 +88,8 @@ module Equality : sig
   val choose: t -> elt
   (** Return the representative of the equality. *)
 
+  val elements: t -> elt list
+  (** Returns the list of all elements of the given set. *)
 end
 
 type equality = Equality.t
diff --git a/src/plugins/value/domains/equality/equality_domain.ml b/src/plugins/value/domains/equality/equality_domain.ml
index 9d0299b703635aeb4146832b5564dc7638a6d753..ddf7bae272b9a77f854c3f3adac277e14ade6602 100644
--- a/src/plugins/value/domains/equality/equality_domain.ml
+++ b/src/plugins/value/domains/equality/equality_domain.ml
@@ -123,9 +123,6 @@ module Internal = struct
 
   let log_category = dkey
 
-  type equalities = Equality.Set.t
-  let project (t, _, _) = t
-
   let pretty fmt (eqs, _, _) = Equality.Set.pretty fmt eqs
 
   let pretty_debug fmt (eqs, deps, modified) =
@@ -170,6 +167,10 @@ end
 
 module Store = Domain_builder.Complete (Internal)
 
+type t = Internal.t
+let key = Store.key
+let project (t, _, _) = t
+
 
 (* ------------------------- Abstract Domain -------------------------------- *)
 
diff --git a/src/plugins/value/domains/equality/equality_domain.mli b/src/plugins/value/domains/equality/equality_domain.mli
index 7adbbb6f9e6e6e267581c54e845c2e79271e92e1..b903b6e82d0b3e4a8112ac574d4307bb32bab492 100644
--- a/src/plugins/value/domains/equality/equality_domain.mli
+++ b/src/plugins/value/domains/equality/equality_domain.mli
@@ -31,12 +31,14 @@ type call_init_state =
   | ISEmpty (** completely empty state, without impact on Memexec. *)
 
 
+type t
+val key: t Abstract_domain.key
+val project: t -> Equality.Set.t
+
 module Make (Value : Abstract.Value.External) : sig
   include Abstract_domain.Leaf with type value = Value.t
                                 and type location = Precise_locs.precise_location
+                                and type state = t
 
   val pretty_debug : Format.formatter -> t -> unit
-
-  type equalities
-  val project : t -> equalities
 end
diff --git a/src/plugins/value/engine/analysis.ml b/src/plugins/value/engine/analysis.ml
index 7fde8c2e3ddfee761223d62b4148c34b596a9994..ada39c5e3fb927d537bc33de14cce090d91f33a9 100644
--- a/src/plugins/value/engine/analysis.ml
+++ b/src/plugins/value/engine/analysis.ml
@@ -28,10 +28,12 @@ module type Results = sig
   type value
   type location
 
+  val get_global_state: unit -> state or_bottom
   val get_stmt_state : after:bool -> stmt -> state or_bottom
-  val get_kinstr_state: after:bool -> kinstr -> state or_bottom
   val get_stmt_state_by_callstack:
     after:bool -> stmt -> state Value_types.Callstack.Hashtbl.t or_top_or_bottom
+  val get_initial_state:
+    kernel_function -> state or_bottom
   val get_initial_state_by_callstack:
     kernel_function -> state Value_types.Callstack.Hashtbl.t or_top_or_bottom
 
@@ -74,13 +76,14 @@ module Make (Abstract: Abstractions.S) = struct
     then Abstract.Dom.Store.get_stmt_state ~after stmt
     else `Value Abstract.Dom.top
 
-  let get_kinstr_state ~after = function
-    | Kglobal -> Abstract.Dom.Store.get_global_state ()
-    | Kstmt stmt -> get_stmt_state ~after stmt
+  let get_global_state = Abstract.Dom.Store.get_global_state
 
   let get_stmt_state_by_callstack =
     Abstract.Dom.Store.get_stmt_state_by_callstack
 
+  let get_initial_state =
+    Abstract.Dom.Store.get_initial_state
+
   let get_initial_state_by_callstack =
     Abstract.Dom.Store.get_initial_state_by_callstack
 
@@ -216,8 +219,18 @@ let force_compute () =
   Analyzer.compute_from_entry_point ~lib_entry kf ;
   ComputationState.set Computed
 
+let is_computed = Db.Value.is_computed
+
+let compute () =
+  (* Nothing to recompute when Value has already been computed. This boolean
+      is automatically cleared when an option of Value changes, because they
+      are registered as dependencies on [Db.Value.self] in {!Value_parameters}.*)
+  if not (is_computed ()) then force_compute ()
+
 (* Resets the Analyzer when the current project is changed. *)
 let () =
   Project.register_after_set_current_hook
     ~user_only:true (fun _ -> reset_analyzer ());
   Project.register_after_global_load_hook reset_analyzer
+
+let self = Db.Value.self
diff --git a/src/plugins/value/engine/analysis.mli b/src/plugins/value/engine/analysis.mli
index 2a6e647e5fc99a01f8172413e7cfa25721fb7b86..7eb2d53ef9b03bc1ace961ebf8be08ed5cd75564 100644
--- a/src/plugins/value/engine/analysis.mli
+++ b/src/plugins/value/engine/analysis.mli
@@ -28,10 +28,12 @@ module type Results = sig
   type value
   type location
 
+  val get_global_state: unit -> state or_bottom
   val get_stmt_state : after:bool -> stmt -> state or_bottom
-  val get_kinstr_state: after:bool -> kinstr -> state or_bottom
   val get_stmt_state_by_callstack:
     after:bool -> stmt -> state Value_types.Callstack.Hashtbl.t or_top_or_bottom
+  val get_initial_state:
+    kernel_function -> state or_bottom
   val get_initial_state_by_callstack:
     kernel_function -> state Value_types.Callstack.Hashtbl.t or_top_or_bottom
 
@@ -86,5 +88,22 @@ val register_computation_hook: ?on:computation_state ->
 val force_compute : unit -> unit
 (** Perform a full analysis, starting from the [main] function. *)
 
+[@@@ api_start]
+val compute : unit -> unit
+(** Computes the Eva analysis, if not already computed, using the entry point
+    of the current project. You may set it with {!Globals.set_entry_point}.
+    @raise Globals.No_such_entry_point if the entry point is incorrect
+    @raise Db.Value.Incorrect_number_of_arguments if some arguments are
+    specified for the entry point using {!Db.Value.fun_set_args}, and
+    an incorrect number of them is given.
+    @plugin development guide *)
+
+val is_computed : unit -> bool
+(** Return [true] iff the Eva analysis has been done. *)
+
+val self : State.t
+(** Internal state of Eva analysis from projects viewpoint. *)
+[@@@ api_end]
+
 val cvalue_initial_state: unit -> Cvalue.Model.t
 (** Return the initial state of the cvalue domain only. *)
diff --git a/src/plugins/value/eval.mli b/src/plugins/value/eval.mli
index 5714172358fc24dfbc4ba07a05c4fe2722fcb2b0..0c7808b6607d3199d63b59b321bb4a686797018f 100644
--- a/src/plugins/value/eval.mli
+++ b/src/plugins/value/eval.mli
@@ -270,15 +270,16 @@ type recursion = {
   (** Same withdrawal as the previous field, for bases. *)
 }
 
+[@@@ api_start]
 (** Can the results of a function call be cached with memexec? *)
 type cacheable =
-  | Cacheable      (** Functions whose result can be safely cached *)
+  | Cacheable      (** Functions whose result can be safely cached. *)
   | NoCache        (** Functions whose result should not be cached, but for
                        which the caller can still be cached. Typically,
                        functions printing something during the analysis. *)
   | NoCacheCallers (** Functions for which neither the call, neither the
-                       callers, can be cached *)
-
+                       callers, can be cached. *)
+[@@@ api_end]
 (*
 Local Variables:
 compile-command: "make -C ../../.."
diff --git a/src/plugins/value/gen-api.sh b/src/plugins/value/gen-api.sh
new file mode 100755
index 0000000000000000000000000000000000000000..82ce513c3bd3a9c39edda6e380afd1dab059e8ca
--- /dev/null
+++ b/src/plugins/value/gen-api.sh
@@ -0,0 +1,27 @@
+#!/bin/bash -eu
+
+printf '(** Eva public API.
+
+   The main modules are:
+   - Analysis: run the analysis.
+   - Results: access analysis results, especially the values of expressions
+      and memory locations of lvalues at each program point.
+
+   The following modules allow configuring the Eva analysis:
+   - Value_parameters: change the configuration of the analysis.
+   - Eva_annotations: add local annotations to guide the analysis.
+   - Builtins: register ocaml builtins to be used by the cvalue domain
+       instead of analysing the body of some C functions.
+
+   Other modules are for internal use only. *)\n'
+
+printf '\n(* This file is generated. Do not edit. *)\n'
+
+for i in "$@"
+do
+    file=$(basename $i)
+    module=${file%.*}
+    printf '\nmodule %s: sig\n' ${module^}
+    awk '/\[@@@ api_start\]/{flag=1;next} /\[@@@ api_end\]/{flag=0} flag{ print (NF ? "  ":"") $0 }' $i
+    printf 'end\n'
+done
diff --git a/src/plugins/value/gui_files/gui_callstacks_manager.ml b/src/plugins/value/gui_files/gui_callstacks_manager.ml
index 9e78d8d54e60d5f8eeddb05bb9ec872bde95b280..c1473fc0604124127c1ec49e0822624511ba7a95 100644
--- a/src/plugins/value/gui_files/gui_callstacks_manager.ml
+++ b/src/plugins/value/gui_files/gui_callstacks_manager.ml
@@ -903,7 +903,7 @@ let make_widget (main_ui:main_ui) ~packing make_panel =
   let tabs =
     GPack.notebook ~scrollable:true ~packing:(vpaned#pack ~expand:true) ()
   in
-  vpaned#misc#set_sensitive (Db.Value.is_computed ());
+  vpaned#misc#set_sensitive (Analysis.is_computed ());
   let pack_tab ?lbl w = ignore (tabs#insert_page ?tab_label:lbl w) in
   let lbl_pane_default = GPack.hbox () in
   let clear_button = new Widget.button ~icon:`CLEAR ~tooltip:"Clear" () in
@@ -1031,7 +1031,7 @@ let make_widget (main_ui:main_ui) ~packing make_panel =
     HWidget.iter (fun w _ -> tabs#remove_page (tabs#page_num w)) hash_tabs;
     HWidget.clear hash_tabs;
     clear_default ();
-    vpaned#misc#set_sensitive (Db.Value.is_computed ());
+    vpaned#misc#set_sensitive (Analysis.is_computed ());
   in
   let display_data_by_callstack loc selection content =
     clear_button#set_enabled true;
diff --git a/src/plugins/value/gui_files/gui_eval.ml b/src/plugins/value/gui_files/gui_eval.ml
index 5888b1bbe9b9c204ecae7582dd2e0eed4c86c9c6..05335f728181d7d09eb7bf714a9070cefb4921f6 100644
--- a/src/plugins/value/gui_files/gui_eval.ml
+++ b/src/plugins/value/gui_files/gui_eval.ml
@@ -24,7 +24,7 @@ open Cil_types
 open Gui_types
 
 let results_kf_computed kf =
-  Db.Value.is_computed () &&
+  Analysis.is_computed () &&
   match kf with
   | { fundec = Definition (fundec, _) } ->
     Mark_noresults.should_memorize_function fundec
diff --git a/src/plugins/value/gui_files/register_gui.ml b/src/plugins/value/gui_files/register_gui.ml
index 3587497948dafbc7d40353138da1651a5b8202c2..e73612e700b95212a5ce4160d64fcef3cd14b9cc 100644
--- a/src/plugins/value/gui_files/register_gui.ml
+++ b/src/plugins/value/gui_files/register_gui.ml
@@ -35,7 +35,7 @@ module UsedVarState =
     (struct
       let size = 17
       let name = "Value.Gui.UsedVarState"
-      let dependencies = [ Db.Value.self ]
+      let dependencies = [ Analysis.self ]
       (* [!Db.Inputs.self_external; !Db.Outputs.self_external] would be better
          dependencies, but this introduces a very problematic recursion between
          Value and Inout *)
@@ -67,7 +67,7 @@ let sync_filetree (filetree:Filetree.t) =
           try
             let vi = Kernel_function.get_vi kf in
             let strikethrough =
-              Db.Value.is_computed () && not (!Db.Value.is_called kf)
+              Analysis.is_computed () && not (Results.is_called kf)
             in
             filetree#set_global_attribute ~strikethrough vi
           with Not_found -> ());
@@ -75,7 +75,7 @@ let sync_filetree (filetree:Filetree.t) =
        (fun vi _ ->
           if vi.vsource = true then
             filetree#set_global_attribute
-              ~strikethrough:(Db.Value.is_computed () && not (used_var vi))
+              ~strikethrough:(Analysis.is_computed () && not (used_var vi))
               vi
        );
      if not (filetree#flat_mode) then
@@ -84,7 +84,7 @@ let sync_filetree (filetree:Filetree.t) =
             (* the display name removes the path *)
             let globals_state = filetree#get_file_globals file in
             filetree#set_file_attribute
-              ~strikethrough:(Db.Value.is_computed () &&
+              ~strikethrough:(Analysis.is_computed () &&
                               List.for_all snd globals_state)
               file
          )
@@ -96,11 +96,11 @@ let sync_filetree (filetree:Filetree.t) =
     ()
 
 let hide_unused_function_or_var g =
-  !hide_unused () && Db.Value.is_computed () &&
+  !hide_unused () && Analysis.is_computed () &&
   (match g with
    | GFun ({svar = vi}, _) | GFunDecl (_, vi, _) ->
      let kf = Globals.Functions.get vi in
-     not (!Db.Value.is_called kf)
+     not (Results.is_called kf)
    | GVarDecl (vi, _) | GVar (vi, _, _)  ->
      not (used_var vi)
    | _ -> false
@@ -144,7 +144,7 @@ let value_panel pack (main_ui:main_ui) =
   ignore (run_button#connect#pressed
             (fun () ->
                main_ui#protect ~cancelable:true
-                 (fun () -> refresh (); !Db.Value.compute (); main_ui#reset ());
+                 (fun () -> refresh (); Analysis.compute (); main_ui#reset ());
             ));
   pack box;
   "Eva", box#coerce, Some refresh
@@ -156,7 +156,7 @@ let active_highlighter buffer localizable ~start ~stop =
   let buffer = buffer#buffer in
   (* highlight dead code areas, non-terminating calls, and degeneration
      points if Value has run.*)
-  if Db.Value.is_computed () then
+  if Analysis.is_computed () then
     match localizable with
     | PStmt (kf, stmt) -> begin
         let degenerate =
@@ -222,7 +222,7 @@ let menu_go_to_fun_definition (main_ui:main_ui) (popup_factory:menu) funs =
   List.iter aux funs
 
 let gui_compute_values (main_ui:main_ui) =
-  if not (Db.Value.is_computed ())
+  if not (Analysis.is_computed ())
   then main_ui#launcher ()
 
 let cleaned_outputs kf s =
@@ -233,7 +233,7 @@ let cleaned_outputs kf s =
 
 let pretty_stmt_info (main_ui:main_ui) kf stmt =
   (* Is it an accessible statement ? *)
-  if Db.Value.is_reachable_stmt stmt then begin
+  if Results.is_reachable stmt then begin
     if Value_results.is_non_terminating_instr stmt then
       match stmt.skind with
       | Instr (Call (_, _, _, _)
@@ -412,7 +412,7 @@ module Select (Eval: Eval) = struct
         (if unfocus <> [] then (kf, unfocus) :: acc_unfocus else acc_unfocus)
       in
       let focused, unfocused =
-        List.fold_left aux_focus ([], []) (!Db.Value.callers kf)
+        List.fold_left aux_focus ([], []) (Results.callsites kf)
       in
       List.iter (aux menu) focused;
       if unfocused <> [] then
@@ -521,7 +521,12 @@ module Select (Eval: Eval) = struct
              (* Function pointers *)
              (* get the list of functions in the values *)
              let e = Value_util.lval_to_exp lv in
-             match Eval.Analysis.get_kinstr_state ~after:false ki with
+             let state =
+               match ki with
+               | Kglobal -> Eval.Analysis.get_global_state ()
+               | Kstmt stmt -> Eval.Analysis.get_stmt_state ~after:false stmt
+             in
+             match state  with
              | `Bottom -> ()
              | `Value state ->
                let funs, _ = Eval.Analysis.eval_function_exp state e in
@@ -555,7 +560,7 @@ let responses_ref = ref (module No_Response: Responses)
 
 let to_do_on_select (menu:menu) (main_ui:main_ui) ~button selected =
   let module Responses = (val !responses_ref) in
-  if Db.Value.is_computed () then
+  if Analysis.is_computed () then
     if button = 1 then
       Responses.left_click_values_computed main_ui selected
     else if button = 3 then
diff --git a/src/plugins/value/legacy/eval_terms.ml b/src/plugins/value/legacy/eval_terms.ml
index c36e84a45b30286e18f983451fdff6d6a4171a81..a75bfed0d139992f8f602c3218285215a1101720 100644
--- a/src/plugins/value/legacy/eval_terms.ml
+++ b/src/plugins/value/legacy/eval_terms.ml
@@ -2745,6 +2745,16 @@ and predicate_deps env pred =
   try Some (do_eval env pred)
   with LogicEvalError _ -> None
 
+let annot_predicate_deps ~pre ~here predicate =
+  let env = env_annot ~pre ~here () in
+  let logic_deps = predicate_deps env predicate in
+  let join logic_deps =
+    Cil_datatype.Logic_label.Map.fold
+      (fun _ -> Locations.Zone.join)
+      logic_deps
+      Locations.Zone.bottom
+  in
+  Option.map join logic_deps
 
 (* -------------------------------------------------------------------------- *)
 (* --- Export                                                             --- *)
diff --git a/src/plugins/value/legacy/eval_terms.mli b/src/plugins/value/legacy/eval_terms.mli
index e63e6a531800d52ccbbbfc1ca29564cb2e27ef70..cff8567815ab453e72462ac147747305a2604fb3 100644
--- a/src/plugins/value/legacy/eval_terms.mli
+++ b/src/plugins/value/legacy/eval_terms.mli
@@ -52,14 +52,15 @@ exception LogicEvalError of logic_evaluation_error
 type labels_states = Cvalue.Model.t Cil_datatype.Logic_label.Map.t
 
 (** Evaluation environment. Currently available are function Pre and Post, or
-    the environment to evaluate an annotation *)
+    the environment to evaluate an annotation. *)
 type eval_env
 
 val make_env: Model.t Abstract_domain.logic_environment -> Model.t -> eval_env
 
 val env_pre_f : pre:Model.t -> unit -> eval_env
 val env_annot :
-  ?c_labels:labels_states -> pre:Model.t -> here:Model.t -> unit -> eval_env
+  ?c_labels:labels_states -> pre:Cvalue.Model.t -> here:Cvalue.Model.t ->
+  unit -> eval_env
 val env_post_f :
   ?c_labels:labels_states -> pre:Model.t -> post:Model.t ->
   result:varinfo option -> unit -> eval_env
@@ -71,7 +72,7 @@ val env_only_here: Model.t -> eval_env
 val env_current_state: eval_env -> Model.t
 
 (** Dependencies needed to evaluate a term or a predicate *)
-type logic_deps = Zone.t Cil_datatype.Logic_label.Map.t
+type logic_deps = Locations.Zone.t Cil_datatype.Logic_label.Map.t
 
 (** Three modes to handle the alarms when evaluating a logical term. *)
 type alarm_mode =
@@ -110,7 +111,22 @@ val eval_tlval_as_zone :
 val eval_predicate :
   eval_env -> predicate -> predicate_status
 
-val predicate_deps: eval_env -> predicate -> logic_deps option
+(** [predicate_deps env p] computes the logic dependencies needed to evaluate
+    [p] in the given evaluation environment [env].
+    Returns None on either an evaluation error or on unsupported construct. *)
+val predicate_deps: eval_env -> Cil_types.predicate -> logic_deps option
 
 val reduce_by_predicate :
   eval_env -> bool -> predicate -> eval_env
+
+
+
+[@@@ api_start]
+(** [annot_predicate_deps ~pre ~here p] computes the logic dependencies needed
+    to evaluate the predicate [p] in a code annotation in cvalue state [here],
+    in a function whose pre-state is [pre].
+    Returns None on either an evaluation error or on unsupported construct. *)
+val annot_predicate_deps:
+  pre:Cvalue.Model.t -> here:Cvalue.Model.t ->
+  Cil_types.predicate -> Locations.Zone.t option
+[@@@ api_end]
diff --git a/src/plugins/value/register.ml b/src/plugins/value/register.ml
index 2e585515cff0920c414234bc28d18bad920f517f..2db4de10b3a0bc336b41126a07a126c0e2a181ae 100644
--- a/src/plugins/value/register.ml
+++ b/src/plugins/value/register.ml
@@ -23,14 +23,9 @@
 open Cil_types
 open Locations
 
-let compute () =
-  (* Nothing to recompute when Value has already been computed. This boolean
-     is automatically cleared when an option of Value changes, because they
-     are registered as dependencies on [Db.Value.self] in {!Value_parameters}.*)
-  if not (Db.Value.is_computed ()) then Analysis.force_compute ()
-
-let _self =
-  Db.register_compute "Value.compute" [ Db.Value.self ] Db.Value.compute compute
+let [@alert "-deprecated"] _self =
+  Db.register_compute "Value.compute" [ Db.Value.self ] Db.Value.compute
+    Analysis.compute
 
 let () = Value_parameters.ForceValues.set_output_dependencies [Db.Value.self]
 
diff --git a/src/plugins/value/register.mli b/src/plugins/value/register.mli
index c27dd17263fd3f5deb3581b5ebdd0f6c3b2674f5..0f54ee776453869a4b44e2675c264a5535429fb9 100644
--- a/src/plugins/value/register.mli
+++ b/src/plugins/value/register.mli
@@ -20,6 +20,9 @@
 (*                                                                        *)
 (**************************************************************************)
 
-(** Functions of the Value plugin registered in {!Db}.
+(** Functions of the Value plugin registered in {!Db}. Only three functions
+    are exported. *)
 
-    Nothing is exported. *)
+val eval_deps : Cvalue_domain.State.t -> Cil_types.exp -> Locations.Zone.t
+val eval_deps_lval : Cvalue_domain.State.t -> Cil_types.lval -> Locations.Zone.t
+val eval_deps_addr : Cvalue_domain.State.t -> Cil_types.lval -> Locations.Zone.t
diff --git a/src/plugins/value/utils/eva_annotations.mli b/src/plugins/value/utils/eva_annotations.mli
index df768e5a1fbb96dc022afa594ca4a5ab9d4fc1a7..5b206536c557f1b287c1c7ea9a76d2759642d370 100644
--- a/src/plugins/value/utils/eva_annotations.mli
+++ b/src/plugins/value/utils/eva_annotations.mli
@@ -20,23 +20,28 @@
 (*                                                                        *)
 (**************************************************************************)
 
-(** Registers Eva annotations:
+(* Note: widen hints annotations are still registered in !{widen_hints_ext.ml}. *)
+
+[@@@ api_start]
+(** Register special annotations to locally guide the Eva analysis:
+
     - slevel annotations: "slevel default", "slevel merge" and "slevel i"
     - loop unroll annotations: "loop unroll term"
     - value partitioning annotations: "split term" and "merge term"
     - subdivision annotations: "subdivide i"
+*)
 
-    Widen hints annotations are still registered in !{widen_hints_ext.ml}. *)
-
+(** Annotations tweaking the behavior of the -eva-slevel parameter. *)
 type slevel_annotation =
-  | SlevelMerge
-  | SlevelDefault
-  | SlevelLocal of int
-  | SlevelFull
+  | SlevelMerge        (** Join all states separated by slevel. *)
+  | SlevelDefault      (** Use the limit defined by -eva-slevel. *)
+  | SlevelLocal of int (** Use the given limit instead of -eva-slevel. *)
+  | SlevelFull         (** Remove the limit of number of separated states. *)
 
+(** Loop unroll annotations. *)
 type unroll_annotation =
-  | UnrollAmount of Cil_types.term
-  | UnrollFull
+  | UnrollAmount of Cil_types.term (** Unroll the n first iterations. *)
+  | UnrollFull (** Unroll amount defined by -eva-default-loop-unroll. *)
 
 type split_kind = Static | Dynamic
 
@@ -44,9 +49,12 @@ type split_term =
   | Expression of Cil_types.exp
   | Predicate of Cil_types.predicate
 
+(** Split/merge annotations for value partitioning.  *)
 type flow_annotation =
   | FlowSplit of split_term * split_kind
+  (** Split states according to a term. *)
   | FlowMerge of split_term
+  (** Merge states separated by a previous split. *)
 
 type allocation_kind = By_stack | Fresh | Fresh_weak | Imprecise
 
@@ -64,3 +72,4 @@ val add_flow_annot : emitter:Emitter.t ->
   Cil_types.stmt -> flow_annotation -> unit
 val add_subdivision_annot : emitter:Emitter.t ->
   Cil_types.stmt -> int -> unit
+[@@@ api_end]
diff --git a/src/plugins/value/utils/results.ml b/src/plugins/value/utils/results.ml
new file mode 100644
index 0000000000000000000000000000000000000000..87a2ee9758f3ede02bd347959d77a58f4da61270
--- /dev/null
+++ b/src/plugins/value/utils/results.ml
@@ -0,0 +1,686 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2021                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It is distributed in the hope that it will be useful,                 *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
+(*  GNU Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+open Bottom.Type
+
+type 'a or_top_bottom = 'a Bottom.Top.or_top_bottom
+
+let (>>>-:) t f = match t with
+  | `Top -> `Top
+  | `Bottom  -> `Bottom
+  | `Value t -> `Value (f t)
+
+module Callstack = Value_types.Callstack
+
+type callstack = Callstack.t
+type 'a by_callstack = (callstack * 'a) list
+
+type control_point =
+  | Initial
+  | Start of Cil_types.kernel_function
+  | Before of Cil_types.stmt
+  | After of Cil_types.stmt
+
+type request = {
+  control_point : control_point;
+  selector : callstack list option;
+  filter: (callstack -> bool) list;
+}
+
+type error = Bottom | Top | DisabledDomain
+type 'a result = ('a,error) Result.t
+
+let string_of_error = function
+  | Bottom -> "The computed state is bottom"
+  | Top -> "The computed state is Top"
+  | DisabledDomain -> "The required domain is disabled"
+
+let pretty_error fmt error =
+  Format.pp_print_string fmt (string_of_error error)
+let pretty_result f fmt r =
+  Result.fold ~ok:(f fmt) ~error:(pretty_error fmt) r
+
+
+(* Building requests *)
+
+let make control_point = {
+  control_point;
+  selector = None;
+  filter = [];
+}
+
+let before stmt = make (Before stmt)
+let after stmt = make (After stmt)
+let at_start_of kf = make (Start kf)
+let at_end_of kf = make (After (Kernel_function.find_return kf))
+let at_start = make Initial
+let at_end () = at_end_of (fst (Globals.entry_point ()))
+
+let before_kinstr = function
+  | Cil_types.Kglobal -> at_start
+  | Kstmt stmt -> before stmt
+
+let in_callstacks l req = { req with selector = Some l }
+let in_callstack cs req = { req with selector = Some [cs] }
+let filter_callstack f req = { req with filter = f :: req.filter }
+
+
+(* Manipulating request results *)
+
+type restricted_to_callstack
+type unrestricted_response
+
+module Response =
+struct
+
+  type ('a, 'callstack) t =
+    | Consolidated : 'a -> ('a, unrestricted_response) t
+    | ByCallstack  : 'a by_callstack -> ('a, 'callstack) t
+    | Top : ('a, 'callstack) t
+    | Bottom : ('a, 'callstack) t
+
+  let coercion : ('a, restricted_to_callstack) t -> ('a, 'c) t = function
+    | ByCallstack c -> ByCallstack c
+    | Top -> Top
+    | Bottom -> Bottom
+
+  let is_bottom = function
+    | ByCallstack [] | Bottom -> true
+    | _ -> false
+
+  (* Constructors *)
+
+  let consolidated =
+    function
+    | `Bottom -> Bottom
+    | `Value state -> Consolidated state
+
+  let singleton cs =
+    function
+    | `Bottom -> Bottom
+    | `Value state -> ByCallstack [cs,state]
+
+  let by_callstack : request ->
+    [< `Bottom | `Top | `Value of 'a Value_types.Callstack.Hashtbl.t ] ->
+    ('a, restricted_to_callstack) t =
+    fun req table ->
+    match table with
+    | `Top -> Top
+    | `Bottom -> Bottom
+    | `Value table ->
+      (* Filter *)
+      let add cs state acc =
+        if List.for_all (fun filter -> filter cs) req.filter
+        then (cs, state) :: acc
+        else acc
+      in
+      (* Selection *)
+      let l =
+        match req.selector with
+        | None -> Callstack.Hashtbl.fold add table []
+        | Some selector ->
+          let add acc cs =
+            match Callstack.Hashtbl.find_opt table cs with
+            | Some state -> add cs state acc
+            | None -> acc
+          in
+          List.fold_left add [] selector
+      in
+      ByCallstack l
+
+  (* Accessors *)
+
+  let callstacks : ('a, restricted_to_callstack) t -> callstack list = function
+    | Top | Bottom -> [] (* What else to do when Top is given ? *)
+    | ByCallstack l -> List.map fst l
+
+  (* Fold *)
+
+  let fold (f  : callstack -> 'a -> 'b -> 'b) (acc : 'b) :
+    ('a, restricted_to_callstack) t -> 'b =
+    function
+    | Top | Bottom -> acc (* What else to do when Top is given ? *)
+    | ByCallstack l -> List.fold_left (fun acc (cs,x) -> f cs x acc) acc l
+
+  (* Map *)
+
+  let map : type c. ('a -> 'b) -> ('a, c) t -> ('b, c) t = fun f -> function
+    | Consolidated v -> Consolidated (f v)
+    | ByCallstack l -> ByCallstack (List.map (fun (cs,x) -> cs,f x) l)
+    | Top -> Top
+    | Bottom -> Bottom
+
+  (* Reduction *)
+
+  let map_reduce : type c. ([`Top | `Bottom] -> 'b) -> ('a -> 'b) ->
+    ('b -> 'b -> 'b) -> ('a, c) t -> 'b =
+    fun default map reduce -> function
+      | Consolidated v -> map v
+      | ByCallstack ((_,h) :: t) ->
+        List.fold_left (fun acc (_,x) -> reduce acc (map x)) (map h) t
+      | ByCallstack [] | Bottom -> default `Bottom
+      | Top -> default `Top
+
+  let default = function
+    | `Bottom -> `Bottom
+    | `Top -> `Top
+
+  let map_join : type c.
+    ('a -> 'b) -> ('b -> 'b -> 'b) -> ('a, c) t -> 'b or_top_bottom =
+    fun map join ->
+    let map' x = `Value (map x) in
+    map_reduce default map' (Bottom.Top.join join)
+
+  let map_join' : type c. ('a -> 'b or_top_bottom) -> ('b -> 'b -> 'b) ->
+    ('a, c) t -> 'b or_top_bottom =
+    fun map join ->
+    map_reduce default map (Bottom.Top.join join)
+end
+
+
+(* Extracting states and values *)
+
+type value
+type address
+
+module Make () =
+struct
+  module A = (val Analysis.current_analyzer ())
+
+  module EvalTypes =
+  struct
+    type valuation = A.Eval.Valuation.t
+    type exp = (valuation * A.Val.t) Eval.evaluated
+    type lval = (valuation * A.Val.t Eval.flagged_value) Eval.evaluated
+    type loc = (valuation * A.Loc.location * Cil_types.typ) Eval.evaluated
+  end
+
+  type ('a,'c) evaluation =
+    | LValue: (EvalTypes.lval, 'c) Response.t -> (value,'c) evaluation
+    | Value: (EvalTypes.exp, 'c) Response.t -> (value,'c) evaluation
+    | Address: (EvalTypes.loc, 'c) Response.t * Cil_types.lval ->
+        (address,'c) evaluation
+
+  let get_by_callstack (req : request) :
+    (_, restricted_to_callstack) Response.t =
+    let open Response in
+    match req.control_point with
+    | Before stmt ->
+      A.get_stmt_state_by_callstack ~after:false stmt |> by_callstack req
+    | After stmt ->
+      A.get_stmt_state_by_callstack ~after:true stmt |> by_callstack req
+    | Initial ->
+      A.get_global_state () |> singleton []
+    | Start kf ->
+      A.get_initial_state_by_callstack kf |> by_callstack req
+
+  let get (req : request) : (_, unrestricted_response) Response.t =
+    if req.filter <> [] || Option.is_some req.selector then
+      Response.coercion @@ get_by_callstack req
+    else
+      let open Response in
+      let state =
+        match req.control_point with
+        | Before stmt -> A.get_stmt_state ~after:false stmt
+        | After stmt -> A.get_stmt_state ~after:true stmt
+        | Start kf -> A.get_initial_state kf
+        | Initial -> A.get_global_state ()
+      in
+      consolidated state
+
+  let convert : 'a or_top_bottom -> 'a result = function
+    | `Top -> Result.error Top
+    | `Bottom -> Result.error Bottom
+    | `Value v -> Result.ok v
+
+  let callstacks req =
+    get_by_callstack req |> Response.callstacks
+
+  let by_callstack req =
+    let f cs _res acc =
+      (cs, in_callstack cs req) :: acc
+    in
+    get_by_callstack req |> Response.fold f []
+
+  let is_reachable req =
+    match get req with
+    | Bottom -> false
+    | _ -> true
+
+  let equality_class exp req =
+    let open Equality in
+    match A.Dom.get Equality_domain.key with
+    | None ->
+      Result.error DisabledDomain
+    | Some extract ->
+      let hce = Hcexprs.HCE.of_exp exp in
+      let extract' state =
+        let equalities = Equality_domain.project (extract state) in
+        try NonTrivial (Set.find hce equalities)
+        with Not_found -> Trivial
+      and reduce e1 e2 =
+        match e1, e2 with
+        | Trivial, _ | _, Trivial -> Trivial
+        | NonTrivial e1, NonTrivial e2 -> Equality.inter e1 e2
+      in
+      let r = match Response.map_join extract' reduce (get req) with
+        | (`Top | `Bottom) as r -> r
+        | `Value Trivial -> `Top
+        | `Value (NonTrivial e) ->
+          let l = Equality.elements e in
+          `Value (List.map Hcexprs.HCE.to_exp l)
+      in
+      convert r
+
+  let get_cvalue_model req =
+    match A.Dom.get_cvalue with
+    | None ->
+      Result.error DisabledDomain
+    | Some extract ->
+      convert (Response.map_join extract Cvalue.Model.join (get req))
+
+  (* Evaluation *)
+
+  let eval_lval lval req =
+    let eval state = A.Eval.copy_lvalue state lval in
+    LValue (Response.map eval (get req))
+
+  let eval_exp exp req =
+    let eval state = A.Eval.evaluate state exp in
+    Value (Response.map eval (get req))
+
+  let eval_address lval req =
+    let eval state = A.Eval.lvaluate ~for_writing:false state lval in
+    Address (Response.map eval (get req), lval)
+
+  let eval_callee exp req =
+    let join = (@)
+    and extract state =
+      let r,_alarms = A.Eval.eval_function_exp exp state in
+      r >>>-: List.map fst
+    in
+    get req |> Response.map_join' extract join |> convert |>
+    Result.map (List.sort_uniq Kernel_function.compare)
+
+
+  (* Conversion *)
+
+  let extract_value :
+    type c. (value, c) evaluation -> (A.Val.t or_bottom, c) Response.t =
+    function
+    | LValue r ->
+      let extract (x, _alarms) = x >>- (fun (_valuation,fv) -> fv.Eval.v) in
+      Response.map extract r
+    | Value r ->
+      let extract (x, _alarms) = x >>-: (fun (_valuation,v) -> v) in
+      Response.map extract r
+
+  let as_cvalue res =
+    match A.Val.get Main_values.CVal.key with
+    | None ->
+      Result.error DisabledDomain
+    | Some get ->
+      let join = Main_values.CVal.join in
+      let extract value =
+        value >>>-: get
+      in
+      extract_value res |> Response.map_join' extract join |> convert
+
+  let extract_loc :
+    type c. (address, c) evaluation ->
+    (A.Loc.location or_bottom, c) Response.t * Cil_types.lval =
+    function
+    | Address (r, lval) ->
+      let extract (x, _alarms) = x >>-: (fun (_valuation,loc,_typ) -> loc) in
+      Response.map extract r, lval
+
+  let as_location res =
+    match A.Loc.get Main_locations.PLoc.key with
+    | None ->
+      Result.error DisabledDomain
+    | Some get ->
+      let join loc1 loc2 =
+        let open Locations in
+        let size = loc1.size
+        and loc = Location_Bits.join loc1.loc loc2.loc in
+        assert (Int_Base.equal loc2.size size);
+        make_loc loc size
+      and extract loc =
+        loc >>>-: get >>>-: Precise_locs.imprecise_location
+      in
+      extract_loc res |> fst |> Response.map_join' extract join |> convert
+
+  let as_zone ~access res =
+    let response_loc, lv = extract_loc res in
+    let is_const_lv = Value_util.is_const_write_invalid (Cil.typeOfLval lv) in
+    (* No write effect if [lv] is const *)
+    if access=Locations.Write && is_const_lv
+    then Result.ok Locations.Zone.bottom
+    else
+      match A.Loc.get Main_locations.PLoc.key with
+      | None ->
+        Result.error DisabledDomain
+      | Some get ->
+        let join = Locations.Zone.join
+        and extract loc =
+          loc  >>>-: get >>>-: Precise_locs.enumerate_valid_bits access
+        in
+        response_loc |> Response.map_join' extract join |> convert
+
+  let is_initialized : type c. (value,c) evaluation -> bool =
+    function
+    | LValue r ->
+      let join = (&&)
+      and extract (x, _alarms) =
+        x >>>-: (fun (_valuation,fv) -> fv.Eval.initialized)
+      in
+      begin match Response.map_join' extract join r with
+        | `Bottom | `Top -> false
+        | `Value v -> v
+      end
+    | Value _ -> true (* computed values are always initialized *)
+
+  let alarms : type a c. (a,c) evaluation -> Alarms.t list =
+    fun res ->
+    let extract (_,v) = `Value v in
+    let r = match res with
+      | LValue r ->
+        Response.map_join' extract Alarmset.union r
+      | Value r ->
+        Response.map_join' extract Alarmset.union r
+      | Address (r, _lval) ->
+        Response.map_join' extract Alarmset.union r
+    in
+    match r with
+    | `Bottom | `Top -> []
+    | `Value alarmset ->
+      let add alarm status acc =
+        if status <> Alarmset.True then alarm :: acc else acc
+      in
+      Alarmset.fold add [] alarmset
+
+  let is_bottom : type a c. (a,c) evaluation -> bool = function
+    | LValue r -> Response.is_bottom r
+    | Value r -> Response.is_bottom r
+    | Address (r, _lval) -> Response.is_bottom r
+
+  (* Dependencies *)
+
+  let compute_deps eval_deps arg req =
+    let error = function
+      | Bottom -> Locations.Zone.bottom
+      | Top | DisabledDomain -> Locations.Zone.top
+    in
+    let compute cvalue =
+      eval_deps (cvalue, Locals_scoping.bottom ()) arg
+    in
+    req |> get_cvalue_model |> Result.fold ~error ~ok:compute
+
+  let lval_deps = compute_deps Register.eval_deps_lval
+  let expr_deps = compute_deps Register.eval_deps
+  let address_deps = compute_deps Register.eval_deps_addr
+end
+
+
+(* Working with callstacks *)
+
+let callstacks req =
+  let module E = Make () in
+  E.callstacks req
+
+let by_callstack req =
+  let module E = Make () in
+  E.by_callstack req
+
+
+(* State requests *)
+
+let equality_class exp req =
+  let module E = Make () in
+  E.equality_class exp req
+
+let get_cvalue_model_result req =
+  let module E = Make () in
+  E.get_cvalue_model req
+
+let get_cvalue_model req =
+  match get_cvalue_model_result req with
+  | Ok state -> state
+  | Error Bottom -> Cvalue.Model.bottom
+  | Error (Top | DisabledDomain) -> Cvalue.Model.top
+
+
+(* Depedencies *)
+
+let expr_deps exp req =
+  let module E = Make () in
+  E.expr_deps exp req
+
+let lval_deps lval req =
+  let module E = Make () in
+  E.lval_deps lval req
+
+let address_deps lval req =
+  let module E = Make () in
+  E.address_deps lval req
+
+
+(* Evaluation *)
+
+module type Lvaluation =
+sig
+  include module type of (Make ())
+  val v : (address, unrestricted_response) evaluation
+end
+
+module type Evaluation =
+sig
+  include module type of (Make ())
+  val v : (value, unrestricted_response) evaluation
+end
+
+type 'a evaluation =
+  | Value: (module Evaluation) -> value evaluation
+  | Address: (module Lvaluation) -> address evaluation
+
+let build_eval_lval_and_exp () =
+  let module M = Make () in
+  let build v =
+    (module struct
+      include M
+      let v = v
+    end : Evaluation)
+  in
+  let eval_lval lval req = build @@ M.eval_lval lval req in
+  let eval_exp exp req = build @@ M.eval_exp exp req in
+  eval_lval, eval_exp
+
+let eval_lval lval req = Value ((fst @@ build_eval_lval_and_exp ()) lval req)
+
+let eval_var vi req = eval_lval (Cil.var vi) req
+
+let eval_exp exp req = Value ((snd @@ build_eval_lval_and_exp ()) exp req)
+
+let eval_address lval req =
+  let module M = Make () in
+  let v = M.eval_address lval req in
+  Address
+    (module struct
+      include M
+      let v = v
+    end : Lvaluation)
+
+let eval_callee exp req =
+  (* Check the validity of exp *)
+  begin match exp with
+    | Cil_types.({ enode = Lval (_, NoOffset) }) -> ()
+    | _ ->
+      invalid_arg "The callee must be an lvalue with no offset"
+  end;
+  let module M = Make () in
+  M.eval_callee exp req
+
+let callee stmt =
+  let callee_exp =
+    match stmt.Cil_types.skind with
+    | Instr (Call (_lval, callee_exp, _args, _loc)) ->
+      callee_exp
+    | Instr (Local_init (_vi, ConsInit (f, _, _), _loc)) ->
+      Cil.evar f
+    | _ ->
+      invalid_arg "Can only evaluate the callee on a statement which is a Call"
+  in
+  before stmt |> eval_callee callee_exp |> Result.value ~default:[]
+
+(* Value conversion *)
+
+let as_cvalue_result (Value evaluation) =
+  let module E = (val evaluation : Evaluation) in
+  E.as_cvalue E.v
+
+let as_cvalue evaluation =
+  match as_cvalue_result evaluation with
+  | Ok v -> v
+  | Error Bottom -> Cvalue.V.bottom
+  | Error (Top | DisabledDomain) -> Cvalue.V.top
+
+let as_ival evaluation =
+  try
+    Result.map Cvalue.V.project_ival (as_cvalue_result evaluation)
+  with Cvalue.V.Not_based_on_null ->
+    Result.error Top
+
+let as_fval evaluation =
+  let f ival =
+    if Ival.is_float ival
+    then Result.ok (Ival.project_float ival)
+    else Result.error Top
+  in
+  Result.bind (as_ival evaluation) f
+
+let as_float evaluation =
+  try
+    as_fval evaluation |>
+    Result.map Fval.project_float |>
+    Result.map Fval.F.to_float
+  with Fval.Not_Singleton_Float ->
+    Result.error Top
+
+let as_integer evaluation =
+  try
+    Result.map Ival.project_int (as_ival evaluation)
+  with Ival.Not_Singleton_Int ->
+    Result.error Top
+
+let as_int evaluation =
+  try
+    Result.map Integer.to_int_exn (as_integer evaluation)
+  with Z.Overflow ->
+    Result.error Top
+
+let as_location (Address lvaluation) =
+  let module E = (val lvaluation : Lvaluation) in
+  E.as_location E.v
+
+let as_zone_result ?(access=Locations.Read) (Address lvaluation) =
+  let module E = (val lvaluation : Lvaluation) in
+  E.as_zone ~access E.v
+
+let as_zone ?access address =
+  match as_zone_result ?access address with
+  | Ok zone -> zone
+  | Error Bottom -> Locations.Zone.bottom
+  | Error (Top | DisabledDomain) -> Locations.Zone.top
+
+(* Evaluation properties *)
+
+let is_initialized (Value evaluation) =
+  let module E = (val evaluation : Evaluation) in
+  E.is_initialized E.v
+
+let alarms : type a. a evaluation -> Alarms.t list =
+  function
+  | Value evaluation ->
+    let module E = (val evaluation : Evaluation) in
+    E.alarms E.v
+  | Address lvaluation ->
+    let module L = (val lvaluation : Lvaluation) in
+    L.alarms L.v
+
+(* Reachability *)
+
+let is_empty rq =
+  let module E = Make () in
+  E.callstacks rq = []
+
+let is_bottom : type a. a evaluation -> bool =
+  function
+  | Value evaluation ->
+    let module E = (val evaluation : Evaluation) in
+    E.is_bottom E.v
+  | Address lvaluation ->
+    let module L = (val lvaluation : Lvaluation) in
+    L.is_bottom L.v
+
+let is_called kf =
+  let module M = Make () in
+  M.is_reachable (at_start_of kf)
+
+let is_reachable stmt =
+  let module M = Make () in
+  M.is_reachable (before stmt)
+
+let is_reachable_kinstr kinstr =
+  let module M = Make () in
+  M.is_reachable (before_kinstr kinstr)
+
+
+(* Callers / callsites *)
+
+let callers kf =
+  let f = function
+    | [] | [_] -> None
+    | _ :: (caller,_) :: _-> Some caller
+  in
+  at_start_of kf |> callstacks |>
+  List.filter_map f |> List.sort_uniq Kernel_function.compare
+
+let uniq_sites = List.sort_uniq Cil_datatype.Stmt.compare
+
+let callsites kf =
+  let module Map = Kernel_function.Map in
+  let f acc = function
+    | [] | (_,Cil_types.Kglobal) :: _ -> acc
+    | [(_,Kstmt _)] -> assert false (* End of callstacks should have no callsite *)
+    | (_kf,Kstmt stmt) :: (caller,_) :: _ -> (* kf = _kf *)
+      Map.update caller
+        (fun old -> Some (stmt :: Option.value ~default:[] old)) acc
+  in
+  at_start_of kf |> callstacks |>
+  List.fold_left f Map.empty |> Map.to_seq |> List.of_seq |>
+  List.map (fun (kf,sites) -> kf, uniq_sites sites)
+
+
+(* Result conversion *)
+
+let default default_value result =
+  Result.value ~default:default_value result
diff --git a/src/plugins/value/utils/results.mli b/src/plugins/value/utils/results.mli
new file mode 100644
index 0000000000000000000000000000000000000000..e24441ccb68a3473d768a8129ee28eb45eb12fe0
--- /dev/null
+++ b/src/plugins/value/utils/results.mli
@@ -0,0 +1,289 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2021                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It is distributed in the hope that it will be useful,                 *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
+(*  GNU Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+[@@@ api_start]
+(** Eva's result API is a work-in-progress interface to allow accessing the
+    analysis results once its completed. It is experimental and is very likely
+    to change in the future. It aims at replacing [Db.Value] but does not
+    completely covers all its usages yet. As for now, this interface has some
+    advantages over Db's :
+
+    - evaluations uses every available domains and not only Cvalue;
+    - the caller may distinguish failure cases when a request is unsucessful;
+    - working with callstacks is easy;
+    - some common shortcuts are provided (e.g. for extracting ival directly);
+    - overall, individual functions are simpler.
+
+    The idea behind this API is that requests must be decomposed in several
+    steps. For instance, to evaluate an expression :
+
+    1. first, you have to state where you want to evaluate it,
+    2. optionally, you may specify in which callstack,
+    3. you choose the expression to evaluate,
+    4. you require a destination type to evaluate into.
+
+    Usage sketch :
+
+    Eva.Results.(
+      before stmt |> in_callstack cs |>
+      eval_var vi |> as_int |> default 0)
+
+    or equivalently, if you prefer
+
+    Eva.Results.(
+      default O (as_int (eval_var vi (in_callstack cs (before stmt))))
+*)
+
+
+type callstack = (Cil_types.kernel_function * Cil_types.kinstr) list
+
+type request
+
+type value
+type address
+type 'a evaluation
+
+type error = Bottom | Top | DisabledDomain
+type 'a result = ('a,error) Result.t
+
+
+(** Results handling *)
+
+(** Translates an error to a human readable string. *)
+val string_of_error : error -> string
+
+(** Pretty printer for errors. *)
+val pretty_error : Format.formatter -> error -> unit
+
+(** Pretty printer for API's results. *)
+val pretty_result : (Format.formatter -> 'a -> unit) ->
+  Format.formatter -> 'a result -> unit
+
+(** [default d r] extracts the value of [r] if [r] is Ok,
+    or use the default value [d] otherwise.
+    Equivalent to [Result.value ~default:d r] *)
+val default : 'a -> 'a result -> 'a
+
+
+(** Control point selection *)
+
+(** At the start of the analysis, but after the initialization of globals. *)
+val at_start : request
+
+(** At the end of the analysis, after the main function has returned. *)
+val at_end : unit -> request
+
+(** At the start of the given function. *)
+val at_start_of : Cil_types.kernel_function -> request
+
+(** At the end of the given function.
+    @raises Kernel_function.No_statement if the function has no body. *)
+val at_end_of : Cil_types.kernel_function -> request
+
+(** Just before a statement is executed. *)
+val before : Cil_types.stmt -> request
+
+(** Just after a statement is executed. *)
+val after : Cil_types.stmt -> request
+
+(** Just before a statement or at the start of the analysis. *)
+val before_kinstr : Cil_types.kinstr -> request
+
+
+(** Callstack selection *)
+
+(** Only consider the given callstack.
+    Replaces previous calls to [in_callstack] or [in_callstacks]. *)
+val in_callstack : callstack -> request -> request
+
+(** Only consider the callstacks from the given list.
+    Replaces previous calls to [in_callstack] or [in_callstacks]. *)
+val in_callstacks : callstack list -> request -> request
+
+(** Only consider callstacks satisfying the given predicate. Several filters
+    can be added. If callstacks are also selected with [in_callstack] or
+    [in_callstacks], only the selected callstacks will be filtered. *)
+val filter_callstack : (callstack -> bool) -> request -> request
+
+
+(** Working with callstacks *)
+
+(** Returns the list of reachable callstacks from the given request.
+    An empty list is returned if the request control point has not been
+    reached by the analysis, or if no information has been saved at this point
+    (for instance with the -eva-no-results option).
+    Use [is_empty request] to distinguish these two cases. *)
+val callstacks : request -> callstack list
+
+(** Returns a list of subrequests for each reachable callstack from
+    the given request. *)
+val by_callstack : request -> (callstack * request) list
+
+
+(** State requests *)
+
+(** Returns the list of expressions which have been inferred to be equal to
+    the given expression by the Equality domain. *)
+val equality_class : Cil_types.exp -> request -> Cil_types.exp list result
+
+(** Returns the Cvalue state. Error cases are converted into the bottom or top
+    cvalue state accordingly. *)
+val get_cvalue_model : request -> Cvalue.Model.t
+
+(** Returns the Cvalue model. *)
+val get_cvalue_model_result : request -> Cvalue.Model.t result
+
+
+(** Dependencies *)
+
+(** Computes (an overapproximation of) the memory zones that must be read to
+    evaluate the given expression, including all adresses computations. *)
+val expr_deps : Cil_types.exp -> request -> Locations.Zone.t
+
+(** Computes (an overapproximation of) the memory zones that must be read to
+    evaluate the given lvalue, including the lvalue zone itself. *)
+val lval_deps : Cil_types.lval -> request -> Locations.Zone.t
+
+(** Computes (an overapproximation of) the memory zones that must be read to
+    evaluate the given lvalue, excluding the lvalue zone itself. *)
+val address_deps : Cil_types.lval -> request -> Locations.Zone.t
+
+
+(** Evaluation *)
+
+(** Returns (an overapproximation of) the possible values of the variable. *)
+val eval_var : Cil_types.varinfo -> request -> value evaluation
+
+(** Returns (an overapproximation of) the possible values of the lvalue. *)
+val eval_lval : Cil_types.lval -> request -> value evaluation
+
+(** Returns (an overapproximation of) the possible values of the expression. *)
+val eval_exp : Cil_types.exp -> request -> value evaluation
+
+
+(** Returns (an overapproximation of) the possible addresses of the lvalue. *)
+val eval_address : Cil_types.lval -> request -> address evaluation
+
+
+(** Returns the kernel functions into which the given expression may evaluate.
+    If the callee expression doesn't always evaluate to a function, those
+    spurious values are ignored. If it always evaluate to a non-function value
+    then the returned list is empty.
+    Raises [Stdlib.Invalid_argument] if the callee expression is not an lvalue
+    without offset.
+    Also see [callee] for a function which applies directly on Call
+    statements. *)
+val eval_callee : Cil_types.exp -> request -> Kernel_function.t list result
+
+
+(** Evaluated values conversion *)
+
+(** In all functions below, if the abstract value inferred by Eva does not fit
+    in the required type, [Error Top] is returned, as Top is the only possible
+    over-approximation of the request. *)
+
+(** Converts the value into a singleton ocaml int. *)
+val as_int : value evaluation -> int result
+
+(** Converts the value into a singleton unbounded integer. *)
+val as_integer : value evaluation -> Integer.t result
+
+(** Converts the value into a floating point number. *)
+val as_float : value evaluation -> float result
+
+(** Converts the value into a C number abstraction. *)
+val as_ival : value evaluation -> Ival.t result
+
+(** Converts the value into a floating point abstraction. *)
+val as_fval : value evaluation -> Fval.t result
+
+(** Converts the value into a Cvalue abstraction. Converts error cases
+    into bottom and top values accordingly. *)
+val as_cvalue : value evaluation -> Cvalue.V.t
+
+(** Converts the value into a Cvalue abstraction. *)
+val as_cvalue_result : value evaluation -> Cvalue.V.t result
+
+
+(** Converts into a C location abstraction. *)
+val as_location : address evaluation -> Locations.location result
+
+(** Converts into a Zone. Error cases are converted into bottom or top zones
+    accordingly. *)
+val as_zone: ?access:Locations.access -> address evaluation ->
+  Locations.Zone.t
+
+(** Converts into a Zone result. *)
+val as_zone_result : ?access:Locations.access -> address evaluation ->
+  Locations.Zone.t result
+
+
+(** Evaluation properties *)
+
+(** Returns whether the evaluated value is initialized or not. If the value have
+    been evaluated from a Cil expression, it is always initialized. *)
+val is_initialized : value evaluation -> bool
+
+(** Returns the set of alarms emitted during the evaluation. *)
+val alarms : 'a evaluation -> Alarms.t list
+
+
+(** Reachability *)
+
+(** Returns true if there are no reachable states for the given request. *)
+val is_empty : request -> bool
+
+(** Returns true if an evaluation leads to bottom, i.e. if the given expression
+    or lvalue cannot be evaluated to a valid result for the given request. *)
+val is_bottom : 'a evaluation -> bool
+
+(** Returns true if the function has been analyzed. *)
+val is_called : Cil_types.kernel_function -> bool
+
+(** Returns true if the statement has been reached by the analysis. *)
+val is_reachable : Cil_types.stmt -> bool
+
+(** Returns true if the statement has been reached by the analysis, or if
+    the main function has been analyzed for [Kglobal]. *)
+val is_reachable_kinstr : Cil_types.kinstr -> bool
+
+
+(*** Callers / Callees / Callsites *)
+
+(** Returns the list of inferred callers of the given function. *)
+val callers : Cil_types.kernel_function -> Cil_types.kernel_function list
+
+(** Returns the list of inferred callers, and for each of them, the list
+    of callsites (the call statements) inside. *)
+val callsites : Cil_types.kernel_function ->
+  (Cil_types.kernel_function * Cil_types.stmt list) list
+
+
+(** Returns the kernel functions called in the given statement.
+    If the callee expression doesn't always evaluate to a function, those
+    spurious values are ignored. If it always evaluate to a non-function value
+    then the returned list is empty.
+    Raises [Stdlib.Invalid_argument] if the statement is not a [Call]
+    instruction or a [Local_init] with [ConsInit] initializer. *)
+val callee : Cil_types.stmt -> Kernel_function.t list
+
+[@@@ api_end]
diff --git a/src/plugins/value/utils/unit_tests.mli b/src/plugins/value/utils/unit_tests.mli
index cf1fae9cef81e5104e4e6cb886c7a5170a7caa51..db0856b3653da1a60e995926306d1ba00e7fdcb2 100644
--- a/src/plugins/value/utils/unit_tests.mli
+++ b/src/plugins/value/utils/unit_tests.mli
@@ -20,8 +20,10 @@
 (*                                                                        *)
 (**************************************************************************)
 
-(** Currently tested by this file:
+[@@@ api_start]
+(** Currently tested by this module:
     - semantics of sign values. *)
 
 (** Runs some programmatic tests on Eva. *)
 val run: unit -> unit
+[@@@ api_end]
diff --git a/src/plugins/value/utils/value_results.mli b/src/plugins/value/utils/value_results.mli
index 9592d1e753f5eda07466e46e263863f903648115..bcfcd175ca6a8f2eb6fcd2612ffd26fbf34f1e50 100644
--- a/src/plugins/value/utils/value_results.mli
+++ b/src/plugins/value/utils/value_results.mli
@@ -20,22 +20,23 @@
 (*                                                                        *)
 (**************************************************************************)
 
-(** This file will ultimately contain all the results computed by Value
-    (which must be moved out of Db.Value), both per stack and globally. *)
-
-
 open Cil_types
 
 val is_called: kernel_function -> bool
 val mark_kf_as_called: kernel_function -> unit
 val add_kf_caller: caller:kernel_function * stmt -> kernel_function -> unit
 
+val callers: kernel_function -> (kernel_function*stmt list) list
+(** @return the list of callers with their call sites. Each function is
+    present only once in the list. *)
+
 val is_non_terminating_instr: stmt -> bool
 (** Returns [true] iff there exists executions of the statement that does
     not always fail/loop (for function calls). Must be called *only* on
     statements that are instructions. *)
 
 (** {2 Results} *)
+[@@@ api_start]
 type results
 
 val get_results: unit -> results
@@ -46,6 +47,7 @@ val change_callstacks:
 (** Change the callstacks for the results for which this is meaningful.
     For technical reasons, the top of the callstack must currently
     be preserved. *)
+[@@@ api_end]
 
 (*
 Local Variables:
diff --git a/src/plugins/value/value_parameters.mli b/src/plugins/value/value_parameters.mli
index a05cde2a46d6bbdf015865524e5dda608eb4d91d..14c4e47e61ae888414a7e61a743f6f1af796a0dc 100644
--- a/src/plugins/value/value_parameters.mli
+++ b/src/plugins/value/value_parameters.mli
@@ -230,16 +230,21 @@ val register_builtin: string -> unit
 (** Registers available domain names for the -eva-domains option. *)
 val register_domain: name:string -> descr:string -> unit
 
-(** Returns the list (name, descr) of currently enabled domains. *)
+[@@@ api_start]
+(** Configuration of the analysis. *)
+
+(** Returns the list (name, descr) of currently enabled abstract domains. *)
 val enabled_domains: unit -> (string * string) list
 
-(** [use_builtin kf b] adds a builtin override for function `kf` to
-    builtin `b`. *)
+(** [use_builtin kf name] instructs the analysis to use the builtin [name]
+    to interpret calls to function [kf].
+    Raises [Not_found] if there is no builtin of name [name]. *)
 val use_builtin: Cil_types.kernel_function -> string -> unit
 
-(** [use_global_value_partitioning vi] enable value partitioning on the global
-    variable `vi`. *)
+(** [use_global_value_partitioning vi] instructs the analysis to use
+    value partitioning on the global variable [vi]. *)
 val use_global_value_partitioning: Cil_types.varinfo -> unit
+[@@@ api_end]
 
 (*
 Local Variables:
diff --git a/tests/crowbar/constfold.ml b/tests/crowbar/constfold.ml
index b98c69153c173ba6dd2cbae5cf252e3459196a44..91de9a16715a5ca908c76349ab5a0cc727b47c78 100644
--- a/tests/crowbar/constfold.ml
+++ b/tests/crowbar/constfold.ml
@@ -206,7 +206,7 @@ let run typ expr =
   end;
   File.prepare_cil_file cil;
   Kernel.MainFunction.set "f";
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   let kf = Globals.Functions.find_by_name "f" in
   let r = Globals.Vars.find_from_astinfo "result" Cil_types.VGlobal in
   let ret = Kernel_function.find_return kf in
diff --git a/tests/misc/bts1201.ml b/tests/misc/bts1201.ml
index 9e3c1b2a3ff07a05ed42787d1bf59decc41dee91..8cb421763f5dc9c46a3c61679a6413b458875578 100644
--- a/tests/misc/bts1201.ml
+++ b/tests/misc/bts1201.ml
@@ -1,7 +1,7 @@
 let main () =
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   Globals.set_entry_point "main2" false;
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
 ;;
 
 let () = Db.Main.extend main
diff --git a/tests/misc/bts1347.ml b/tests/misc/bts1347.ml
index d2319d0f4b81a02e3a66d55474e63ea4e882c3d7..e1336805421fcbd1b834358ed9209b9e67520e53 100644
--- a/tests/misc/bts1347.ml
+++ b/tests/misc/bts1347.ml
@@ -7,7 +7,7 @@ let run () =
     (fun kf ->
       if not (Cil_builtins.is_builtin (Kernel_function.get_vi kf)) then begin
 	Globals.set_entry_point (Kernel_function.get_name kf) true;
-	!Db.Value.compute();
+	Eva.Analysis.compute();
 	let hyps = 
 	  Alarms.fold
 	    (fun _ kf' s ~rank:_ _ a l -> 
diff --git a/tests/misc/ensures.ml b/tests/misc/ensures.ml
index cfe3fc7894196c48711c6dc6031f79ad9ef95d65..a08e28e31b1135d67ab1334b1c307a85b23a855f 100644
--- a/tests/misc/ensures.ml
+++ b/tests/misc/ensures.ml
@@ -2,7 +2,7 @@ open Cil_types
 
 let run () =
   Dynamic.Parameter.Bool.set "-eva-context-valid-pointers" true;
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   Globals.Functions.iter
     (fun kf ->
        let kf_name = Kernel_function.get_name kf in
diff --git a/tests/misc/issue109.ml b/tests/misc/issue109.ml
index 98cc840b15e7d55bbe01e7c1b6083c3bc28c9fbe..fee1af6952d980a7c9c5c14334a6218a2662198b 100644
--- a/tests/misc/issue109.ml
+++ b/tests/misc/issue109.ml
@@ -6,10 +6,10 @@ let ptest_file =
   with Not_found -> fun dir file -> dir ^ file
 
 let main () =
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   Dynamic.Parameter.String.set "" "";
   Dynamic.Parameter.String.set "" (ptest_file "tests/misc/" "issue109.i");
   File.init_from_cmdline ();
-  !Db.Value.compute ()
+  Eva.Analysis.compute ()
 
 let main = Db.Main.extend main
diff --git a/tests/misc/log_twice.ml b/tests/misc/log_twice.ml
index df47c2fe750b3d855d4ec067b48b2cf73f36d42c..15145a121857b9156787d96f5cf526a94f4e308d 100644
--- a/tests/misc/log_twice.ml
+++ b/tests/misc/log_twice.ml
@@ -8,9 +8,9 @@ let run () =
       ~last:false
       "default"
   in
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   Project.set_current p_default;
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   ()
 
 let () = Db.Main.extend run 
diff --git a/tests/misc/well_typed_alarm.ml b/tests/misc/well_typed_alarm.ml
index d0e210e9c00fd3896b37b29a623e123ffa54ead4..6c792a3d3ee8155beb6f9ba3c44e698f5d196a33 100644
--- a/tests/misc/well_typed_alarm.ml
+++ b/tests/misc/well_typed_alarm.ml
@@ -1,5 +1,5 @@
 let main () =
-  !Db.Value.compute();
+  Eva.Analysis.compute();
   Filecheck.check_ast "Check alarm";
   File.pretty_ast ()
 
diff --git a/tests/saveload/load_one.ml b/tests/saveload/load_one.ml
index cef2bc0f80bd94c3a90a943c49997a932664cade..9440328dc2d9b58d99c4f9d5b5f338714f08d6fa 100644
--- a/tests/saveload/load_one.ml
+++ b/tests/saveload/load_one.ml
@@ -18,13 +18,13 @@ let main () =
   Project.save fp;
   Project.remove ~project:p ();
   let p = Project.load fp in
-  Project.on p (fun () -> !Db.Value.compute (); ignore (sparecode ())) ()
+  Project.on p (fun () -> Eva.Analysis.compute (); ignore (sparecode ())) ()
 
 let () = Db.Main.extend main
 
 (* testing Project.create_by_copy *)
 let main2 () =
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   let prj = Project.create_by_copy ~last:false "copy" in
   Format.printf "INIT AST@.";
   File.pretty_ast ();
diff --git a/tests/slicing/combine.ml b/tests/slicing/combine.ml
index 853545c0c4836b84bb3fddd7c429377db2d93c8b..bbe23a110edfb1fe818977e138123364b920b55c 100644
--- a/tests/slicing/combine.ml
+++ b/tests/slicing/combine.ml
@@ -63,7 +63,7 @@ let main _ =
     Cil.visitCilFile infos new_cil_file (* the cil file after slicing *);;
   *)
   Dynamic.Parameter.Bool.set "-eva-show-progress" true;
-  !Db.Value.compute ();
+  Eva.Analysis.compute ();
   let all = Cil_datatype.Fundec.Set.empty in
   let proj3 = Constant_Propagation.Api.get all ~cast_intro:true in
   Project.set_current proj3;
diff --git a/tests/slicing/libSelect.ml b/tests/slicing/libSelect.ml
index 41e55de6abc57f04b210f23b7547f49fa38d0821..309d09278480d329cc4ae0307e2169914d9d6231 100644
--- a/tests/slicing/libSelect.ml
+++ b/tests/slicing/libSelect.ml
@@ -64,7 +64,7 @@ let load_source_file ?entry_point filename  =
   in
   ignore (Db.get_cil_file ());
   let kf = Db.find_function_def_by_name entry_point in
-    ignore (!Db.Value.compute_entry_point kf ~library);
+    ignore (Eva.Analysis.compute_entry_point kf ~library);
   Db.iter_on_functions
     (fun kf -> if Db.is_definition kf && Db.Value.is_called kf
      then !Db.From.compute kf)
diff --git a/tests/syntax/Refresh_visitor.ml b/tests/syntax/Refresh_visitor.ml
index 9a82d0fd6b4635681d12e70869a6769a7fa6283e..d4075698d6899674174c5738c32b5e3eb3a02685 100644
--- a/tests/syntax/Refresh_visitor.ml
+++ b/tests/syntax/Refresh_visitor.ml
@@ -72,7 +72,7 @@ let main () =
   );
   Project.on p (fun () ->
       Dynamic.Parameter.Bool.set "-eva-show-progress" true;
-      !Db.Value.compute ()
+      Eva.Analysis.compute ()
     ) ();
   File.pretty_ast ~prj:p ()
 
diff --git a/tests/value/oracle_equality/struct2.res.oracle b/tests/value/oracle_equality/struct2.res.oracle
index 848a02fcf02af843f93025e3241dc58bfe59ef05..31007513f85ece3f32c1295e5fbaad5985d2f497 100644
--- a/tests/value/oracle_equality/struct2.res.oracle
+++ b/tests/value/oracle_equality/struct2.res.oracle
@@ -11,20 +11,25 @@
 < [scope:rm_asserts] removing 2 assertion(s)
 ---
 > [scope:rm_asserts] removing 1 assertion(s)
-135,137c133,135
+135,137c133,134
 <   tab3[0..1] ∈ [--..--]
 <   tab4[0] ∈ {0; 2}
 <       [1] ∈ {0}
 ---
 >   tab3[0] ∈ {0; 1}
 >       [1] ∈ [--..--]
->   tab4[0..1] ∈ {0}
-140c138,139
+140c137,138
 <   tab6[0..1] ∈ {0; 2}
 ---
 >   tab6[0] ∈ {0}
 >       [1] ∈ {2}
-211c210
+206,207c204,205
+<     s4.e[0].a; s8.b; s7; tab1[0..1]; tab2[0..1]; tab3[0..1]; tab4[0]; tab5[0];
+<     tab6[0..1]; p; p2; p3; p4; p5; p6; p7; q; r; s; t; a; b
+---
+>     s4.e[0].a; s8.b; s7; tab1[0..1]; tab2[0..1]; tab3[0..1]; tab5[0]; tab6[1];
+>     p; p2; p3; p4; p5; p6; p7; q; r; s; t; a; b
+211c209
 <            [9].a}; s1; s2; s5.e[0].b; s6.b; s8; tabl[0..1]; tab1[0..1];
 ---
 >            [9].a}; s1; s2; s5.e[0].b; s6.b; s8; tabl[0..1]; tab1[0];
diff --git a/tests/value/oracle_symblocs/struct2.res.oracle b/tests/value/oracle_symblocs/struct2.res.oracle
index d5341cd37fc34837196ca8c293e4f153c13ae2a0..31bd4583d89f311ca047261d631ffb3fdaed779c 100644
--- a/tests/value/oracle_symblocs/struct2.res.oracle
+++ b/tests/value/oracle_symblocs/struct2.res.oracle
@@ -11,17 +11,21 @@
 < [eva:alarm] struct2.i:185: Warning: 
 98d93
 < [scope:rm_asserts] removing 2 assertion(s)
-136,137c131
+136,137d130
 <   tab4[0] ∈ {0; 2}
 <       [1] ∈ {0}
----
->   tab4[0..1] ∈ {0}
-140c134,135
+140c133,134
 <   tab6[0..1] ∈ {0; 2}
 ---
 >   tab6[0] ∈ {0}
 >       [1] ∈ {2}
-211c206
+206,207c200,201
+<     s4.e[0].a; s8.b; s7; tab1[0..1]; tab2[0..1]; tab3[0..1]; tab4[0]; tab5[0];
+<     tab6[0..1]; p; p2; p3; p4; p5; p6; p7; q; r; s; t; a; b
+---
+>     s4.e[0].a; s8.b; s7; tab1[0..1]; tab2[0..1]; tab3[0..1]; tab5[0]; tab6[1];
+>     p; p2; p3; p4; p5; p6; p7; q; r; s; t; a; b
+211c205
 <            [9].a}; s1; s2; s5.e[0].b; s6.b; s8; tabl[0..1]; tab1[0..1];
 ---
 >            [9].a}; s1; s2; s5.e[0].b; s6.b; s8; tabl[0..1]; tab1[0];