diff --git a/Makefile b/Makefile
index e9664546176d1f99637970d4274ede5bfbcf060d..7dd57fbf16620ad4344ab825ae8e30793e42e470 100644
--- a/Makefile
+++ b/Makefile
@@ -829,7 +829,7 @@ PLUGIN_NAME:=Eva
 PLUGIN_DIR:=src/plugins/value
 PLUGIN_EXTRA_DIRS:=engine values domains api domains/cvalue domains/apron \
 	domains/gauges domains/equality legacy partitioning utils gui_files \
-	values/numerors domains/numerors
+	api values/numerors domains/numerors
 PLUGIN_TESTS_DIRS+=value/traces
 
 # Files for the binding to Apron domains. Only available if Apron is available.
@@ -912,6 +912,7 @@ PLUGIN_CMO:= partitioning/split_strategy domains/domain_mode value_parameters \
 	engine/compute_functions engine/analysis register \
 	api/general_requests \
 	utils/unit_tests \
+	api/values_request \
 	$(APRON_CMO) $(NUMERORS_CMO)
 PLUGIN_CMI:= values/abstract_value values/abstract_location \
 	domains/abstract_domain domains/simpler_domains
diff --git a/headers/header_spec.txt b/headers/header_spec.txt
index 5d791ad40ee2ce6301155c602be4b5fb34761a11..a412c54e05be8e26a83069fbe6381e14e0c6e32d 100644
--- a/headers/header_spec.txt
+++ b/headers/header_spec.txt
@@ -1210,6 +1210,8 @@ 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
 src/plugins/value/api/general_requests.mli: CEA_LGPL_OR_PROPRIETARY
+src/plugins/value/api/values_request.ml: CEA_LGPL_OR_PROPRIETARY
+src/plugins/value/api/values_request.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/domains/abstract_domain.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/domains/printer_domain.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/domains/printer_domain.mli: CEA_LGPL_OR_PROPRIETARY
diff --git a/ivette/api/kernel/ast/index.ts b/ivette/api/kernel/ast/index.ts
index 623884b14adfa9242c3387102ec72042534bad37..0b6931ec606e425b8f53499034958425e9f588a8 100644
--- a/ivette/api/kernel/ast/index.ts
+++ b/ivette/api/kernel/ast/index.ts
@@ -43,10 +43,6 @@ export const compute: Server.ExecRequest<null,null>= compute_internal;
 
 /** Marker kind */
 export enum markerKind {
-  /** Variable */
-  variable = 'variable',
-  /** Function */
-  function = 'function',
   /** Expression */
   expression = 'expression',
   /** Lvalue */
@@ -83,12 +79,44 @@ const markerKindTags_internal: Server.GetRequest<null,tag[]> = {
 /** Registered tags for the above type. */
 export const markerKindTags: Server.GetRequest<null,tag[]>= markerKindTags_internal;
 
+/** Marker variable */
+export enum markerVar {
+  /** None */
+  none = 'none',
+  /** Variable */
+  variable = 'variable',
+  /** Function */
+  function = 'function',
+}
+
+/** Loose decoder for `markerVar` */
+export const jMarkerVar: Json.Loose<markerVar> = Json.jEnum(markerVar);
+
+/** Safe decoder for `markerVar` */
+export const jMarkerVarSafe: Json.Safe<markerVar> =
+  Json.jFail(Json.jEnum(markerVar),'kernel.ast.markerVar expected');
+
+/** Natural order for `markerVar` */
+export const byMarkerVar: Compare.Order<markerVar> =
+  Compare.byEnum(markerVar);
+
+const markerVarTags_internal: Server.GetRequest<null,tag[]> = {
+  kind: Server.RqKind.GET,
+  name:   'kernel.ast.markerVarTags',
+  input:  Json.jNull,
+  output: Json.jList(jTag),
+};
+/** Registered tags for the above type. */
+export const markerVarTags: Server.GetRequest<null,tag[]>= markerVarTags_internal;
+
 /** Data for array rows [`markerInfo`](#markerinfo)  */
 export interface markerInfoData {
   /** Entry identifier. */
   key: Json.key<'#markerInfo'>;
   /** Marker kind */
   kind: markerKind;
+  /** Marker variable */
+  var: markerVar;
   /** Marker short name */
   name: string;
   /** Marker declaration or description */
@@ -101,6 +129,7 @@ export const jMarkerInfoData: Json.Loose<markerInfoData> =
     key: Json.jFail(Json.jKey<'#markerInfo'>('#markerInfo'),
            '#markerInfo expected'),
     kind: jMarkerKindSafe,
+    var: jMarkerVarSafe,
     name: Json.jFail(Json.jString,'String expected'),
     descr: Json.jFail(Json.jString,'String expected'),
   });
@@ -112,10 +141,11 @@ export const jMarkerInfoDataSafe: Json.Safe<markerInfoData> =
 /** Natural order for `markerInfoData` */
 export const byMarkerInfoData: Compare.Order<markerInfoData> =
   Compare.byFields
-    <{ key: Json.key<'#markerInfo'>, kind: markerKind, name: string,
-       descr: string }>({
+    <{ key: Json.key<'#markerInfo'>, kind: markerKind, var: markerVar,
+       name: string, descr: string }>({
     key: Compare.string,
     kind: byMarkerKind,
+    var: byMarkerVar,
     name: Compare.alpha,
     descr: Compare.string,
   });
diff --git a/ivette/api/plugins/eva/index.ts b/ivette/api/plugins/eva/general/index.ts
similarity index 92%
rename from ivette/api/plugins/eva/index.ts
rename to ivette/api/plugins/eva/general/index.ts
index 4b46b34354923641cd17852220a4a7ff037b790f..9f77331803e084829e2e0d6ac13847d0f4d7f625 100644
--- a/ivette/api/plugins/eva/index.ts
+++ b/ivette/api/plugins/eva/general/index.ts
@@ -3,7 +3,7 @@
 /**
    Eva General Services
    @packageDocumentation
-   @module api/plugins/eva
+   @module api/plugins/eva/general
 */
 
 //@ts-ignore
@@ -21,7 +21,7 @@ const getCallers_internal: Server.GetRequest<
   [ Json.key<'#fct'>, Json.key<'#stmt'> ][]
   > = {
   kind: Server.RqKind.GET,
-  name:   'plugins.eva.getCallers',
+  name:   'plugins.eva.general.getCallers',
   input:  Json.jKey<'#fct'>('#fct'),
   output: Json.jList(Json.jTry(
                        Json.jPair(
diff --git a/ivette/api/plugins/eva/values/index.ts b/ivette/api/plugins/eva/values/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..22375d253f9b2f0bac5f1242c8cfe80693973c0e
--- /dev/null
+++ b/ivette/api/plugins/eva/values/index.ts
@@ -0,0 +1,154 @@
+/* --- Generated Frama-C Server API --- */
+
+/**
+   Eva Values
+   @packageDocumentation
+   @module api/plugins/eva/values
+*/
+
+//@ts-ignore
+import * as Json from 'dome/data/json';
+//@ts-ignore
+import * as Compare from 'dome/data/compare';
+//@ts-ignore
+import * as Server from 'frama-c/server';
+//@ts-ignore
+import * as State from 'frama-c/states';
+
+//@ts-ignore
+import { byMarker } from 'api/kernel/ast';
+//@ts-ignore
+import { jMarker } from 'api/kernel/ast';
+//@ts-ignore
+import { jMarkerSafe } from 'api/kernel/ast';
+//@ts-ignore
+import { marker } from 'api/kernel/ast';
+
+/** CallStack */
+export interface callstack {
+  /** Callstack id */
+  id: number;
+  /** Short name for the callstack */
+  short: string;
+  /** Full name for the callstack */
+  full: string;
+}
+
+/** Loose decoder for `callstack` */
+export const jCallstack: Json.Loose<callstack> =
+  Json.jObject({
+    id: Json.jFail(Json.jNumber,'Number expected'),
+    short: Json.jFail(Json.jString,'String expected'),
+    full: Json.jFail(Json.jString,'String expected'),
+  });
+
+/** Safe decoder for `callstack` */
+export const jCallstackSafe: Json.Safe<callstack> =
+  Json.jFail(jCallstack,'Callstack expected');
+
+/** Natural order for `callstack` */
+export const byCallstack: Compare.Order<callstack> =
+  Compare.byFields
+    <{ id: number, short: string, full: string }>({
+    id: Compare.number,
+    short: Compare.string,
+    full: Compare.string,
+  });
+
+/** Data for array rows [`values`](#values)  */
+export interface valuesData {
+  /** Entry identifier. */
+  key: Json.key<'#values'>;
+  /** CallStack */
+  callstack: callstack;
+  /** Value inferred just before the selected point */
+  value_before: string;
+  /** Did the evaluation led to an alarm? */
+  alarm: boolean;
+  /** Value inferred just after the selected point */
+  value_after?: string;
+}
+
+/** Loose decoder for `valuesData` */
+export const jValuesData: Json.Loose<valuesData> =
+  Json.jObject({
+    key: Json.jFail(Json.jKey<'#values'>('#values'),'#values expected'),
+    callstack: jCallstackSafe,
+    value_before: Json.jFail(Json.jString,'String expected'),
+    alarm: Json.jFail(Json.jBoolean,'Boolean expected'),
+    value_after: Json.jString,
+  });
+
+/** Safe decoder for `valuesData` */
+export const jValuesDataSafe: Json.Safe<valuesData> =
+  Json.jFail(jValuesData,'ValuesData expected');
+
+/** Natural order for `valuesData` */
+export const byValuesData: Compare.Order<valuesData> =
+  Compare.byFields
+    <{ key: Json.key<'#values'>, callstack: callstack, value_before: string,
+       alarm: boolean, value_after?: string }>({
+    key: Compare.string,
+    callstack: byCallstack,
+    value_before: Compare.string,
+    alarm: Compare.boolean,
+    value_after: Compare.defined(Compare.string),
+  });
+
+/** Signal for array [`values`](#values)  */
+export const signalValues: Server.Signal = {
+  name: 'plugins.eva.values.signalValues',
+};
+
+const reloadValues_internal: Server.GetRequest<null,null> = {
+  kind: Server.RqKind.GET,
+  name:   'plugins.eva.values.reloadValues',
+  input:  Json.jNull,
+  output: Json.jNull,
+};
+/** Force full reload for array [`values`](#values)  */
+export const reloadValues: Server.GetRequest<null,null>= reloadValues_internal;
+
+const fetchValues_internal: Server.GetRequest<
+  number,
+  { pending: number, updated: valuesData[], removed: Json.key<'#values'>[],
+    reload: boolean }
+  > = {
+  kind: Server.RqKind.GET,
+  name:   'plugins.eva.values.fetchValues',
+  input:  Json.jNumber,
+  output: Json.jObject({
+            pending: Json.jFail(Json.jNumber,'Number expected'),
+            updated: Json.jList(jValuesData),
+            removed: Json.jList(Json.jKey<'#values'>('#values')),
+            reload: Json.jFail(Json.jBoolean,'Boolean expected'),
+          }),
+};
+/** Data fetcher for array [`values`](#values)  */
+export const fetchValues: Server.GetRequest<
+  number,
+  { pending: number, updated: valuesData[], removed: Json.key<'#values'>[],
+    reload: boolean }
+  >= fetchValues_internal;
+
+const values_internal: State.Array<Json.key<'#values'>,valuesData> = {
+  name: 'plugins.eva.values.values',
+  getkey: ((d:valuesData) => d.key),
+  signal: signalValues,
+  fetch: fetchValues,
+  reload: reloadValues,
+  order: byValuesData,
+};
+/** Abstract values inferred by the Eva analysis */
+export const values: State.Array<Json.key<'#values'>,valuesData> = values_internal;
+
+const getValues_internal: Server.GetRequest<marker,null> = {
+  kind: Server.RqKind.GET,
+  name:   'plugins.eva.values.getValues',
+  input:  jMarker,
+  output: Json.jNull,
+};
+/** Get the abstract values computed for an expression or lvalue */
+export const getValues: Server.GetRequest<marker,null>= getValues_internal;
+
+/* ------------------------------------- */
diff --git a/ivette/package.json b/ivette/package.json
index c86d31fa83b3763daf8f92c58127c066a9dce062..d496a65fb2830caeadbaab293a543e2abf2a1302 100644
--- a/ivette/package.json
+++ b/ivette/package.json
@@ -33,7 +33,7 @@
     "css-loader": "^3.4.0",
     "electron": "^7",
     "electron-builder": "^22.4.1",
-    "electron-devtools-installer": "^2.2.4",
+    "electron-devtools-installer": "^3.0.0",
     "electron-webpack": "^2.8.2",
     "eslint": "^6.8.0",
     "eslint-config-airbnb": "^18.1.0",
diff --git a/ivette/src/dome/src/main/dome.js b/ivette/src/dome/src/main/dome.js
index cd01363afb0b82961da1f77f1baed2b3865e5b7c..e6291c5e4f94505092119aea4872d1cd07500c02 100644
--- a/ivette/src/dome/src/main/dome.js
+++ b/ivette/src/dome/src/main/dome.js
@@ -392,7 +392,10 @@ function createPrimaryWindow()
 
   // React Developper Tools
   if (DEVEL)
-    installExtension(REACT_DEVELOPER_TOOLS,true);
+    installExtension(REACT_DEVELOPER_TOOLS,true)
+    .catch((err) => {
+      console.error('[Dome] Enable to install React dev-tools',err);
+    });
   const cwd = process.cwd();
   const wdir = cwd === '/' ? app.getPath('home') : cwd ;
   const argv = stripElectronArgv(process.argv);
diff --git a/ivette/src/dome/src/misc/devtools.js b/ivette/src/dome/src/misc/devtools.js
index 222b66d9d3d159ba7703dbf7d822519abc0b5ab8..4c921aa6c9ed956aaa131813074cb4303c6af844 100644
--- a/ivette/src/dome/src/misc/devtools.js
+++ b/ivette/src/dome/src/misc/devtools.js
@@ -8,5 +8,5 @@ export const REACT_DEVELOPER_TOOLS = undefined ;
 
 // Shall not be used in non-development mode
 export default function installExtension(_id) {
-  return Promise.reject();
+  return Promise.resolve();
 }
diff --git a/ivette/src/dome/src/renderer/table/arrays.ts b/ivette/src/dome/src/renderer/table/arrays.ts
index 705ec7fd0d214947bfa69aca49718097b11a21a6..e506d8237fc7e5ff1fdd635a9b0b630e761c5161 100644
--- a/ivette/src/dome/src/renderer/table/arrays.ts
+++ b/ivette/src/dome/src/renderer/table/arrays.ts
@@ -429,7 +429,7 @@ export class ArrayModel<Key, Row>
 // --------------------------------------------------------------------------
 
 /**
-   @template Row - object data that also contains their « key »
+   @template Row - object data that also contains their « key ».
 */
 export class CompactModel<Key, Row> extends ArrayModel<Key, Row> {
 
@@ -460,7 +460,6 @@ export class CompactModel<Key, Row> extends ArrayModel<Key, Row> {
     this.reload();
   }
 
-
 }
 
 // --------------------------------------------------------------------------
diff --git a/ivette/src/dome/src/renderer/table/views.tsx b/ivette/src/dome/src/renderer/table/views.tsx
index 5e7888b7c89035af4b1b8de6cfa738f47a075fdd..3089b35483683f8efa470dc7e241091877333937 100644
--- a/ivette/src/dome/src/renderer/table/views.tsx
+++ b/ivette/src/dome/src/renderer/table/views.tsx
@@ -59,6 +59,14 @@ export type RenderByFields<Row> = {
 export type index = number | number[]
 
 /**
+   Column Properties.
+
+   __Warning:__ callback properties, namely `getter`, `render`
+   and `onContextMenu`, shall be as stable as possible to prevent
+   the table from constantly re-rendering.
+   Use constant callbacks whenever possible, or memoize them with
+   `React.useCallback()` hook.
+
    @template Row - table row data of some table entries
    @template Cell - type of cell data to render in this column
  */
@@ -104,14 +112,17 @@ export interface ColumnProps<Row, Cell> {
   visible?: boolean | 'never' | 'always';
   /**
      Data getter for this column.
+     Shall be constant or protected by `React.useCallback`.
    */
   getter?: (row: Row, dataKey: string) => Cell | undefined;
   /**
      Override table by-fields cell renderers.
+     Shall be constant or protected by `React.useCallback`.
    */
   render?: Renderer<Cell>;
   /**
      Override table right-click callback.
+     Shall be constant or protected by `React.useCallback`.
    */
   onContextMenu?: (row: Row, index: number, dataKey: string) => void;
 }
diff --git a/ivette/src/renderer/ASTview.tsx b/ivette/src/renderer/ASTview.tsx
index f97145728dc4ddb26db0f447df3a9c93aecd843a..ebfcbe4595ad602b0786f1b65ec8395388e81edb 100644
--- a/ivette/src/renderer/ASTview.tsx
+++ b/ivette/src/renderer/ASTview.tsx
@@ -15,7 +15,7 @@ import { IconButton } from 'dome/controls/buttons';
 import { Component, TitleBar } from 'frama-c/LabViews';
 
 import { printFunction, markerInfo } from 'api/kernel/ast';
-import { getCallers } from 'api/plugins/eva';
+import { getCallers } from 'api/plugins/eva/general';
 
 import 'codemirror/mode/clike/clike';
 import 'codemirror/theme/ambiance.css';
@@ -123,7 +123,7 @@ const ASTview = () => {
   const zoomIn = () => fontSize < 48 && setFontSize(fontSize + 2);
   const zoomOut = () => fontSize > 4 && setFontSize(fontSize - 2);
 
-  function onTextSelection(id: key<'#markerIndo'>) {
+  function onTextSelection(id: key<'#markerInfo'>) {
     if (selection.current) {
       const location = { ...selection.current, marker: id };
       updateSelection({ location });
@@ -133,18 +133,8 @@ const ASTview = () => {
   async function onContextMenu(id: key<'#markerInfo'>) {
     const items = [];
     const selectedMarkerInfo = markersInfo.find((e) => e.key === id);
-    switch (selectedMarkerInfo?.kind) {
-      case 'function': {
-        items.push({
-          label: `Go to definition of ${selectedMarkerInfo.name}`,
-          onClick: () => {
-            const location = { function: selectedMarkerInfo.name };
-            updateSelection({ location });
-          },
-        });
-        break;
-      }
-      case 'declaration': {
+    if (selectedMarkerInfo?.var === 'function') {
+      if (selectedMarkerInfo.kind === 'declaration') {
         if (selectedMarkerInfo?.name) {
           const locations = await functionCallers(selectedMarkerInfo.name);
           const locationsByFunction = _.groupBy(locations, (e) => e.function);
@@ -162,10 +152,15 @@ const ASTview = () => {
               });
             });
         }
-        break;
+      } else {
+        items.push({
+          label: `Go to definition of ${selectedMarkerInfo.name}`,
+          onClick: () => {
+            const location = { function: selectedMarkerInfo.name };
+            updateSelection({ location });
+          },
+        });
       }
-      default:
-        break;
     }
     if (items.length > 0)
       Dome.popupMenu(items);
diff --git a/ivette/src/renderer/Application.tsx b/ivette/src/renderer/Application.tsx
index a2d04f1270e603b9f71a4ed6d906a6e32560d109..6b16620df021ded5fade5192c5c733823344f255 100644
--- a/ivette/src/renderer/Application.tsx
+++ b/ivette/src/renderer/Application.tsx
@@ -21,6 +21,7 @@ import ASTinfo from './ASTinfo';
 import Globals from './Globals';
 import Properties from './Properties';
 import Locations from './Locations';
+import Values from './Values';
 
 // --------------------------------------------------------------------------
 // --- Selection Controls
@@ -101,6 +102,7 @@ export default (() => {
             <ASTview />
             <ASTinfo />
             <Locations />
+            <Values />
           </Group>
         </LabView>
       </Splitter>
diff --git a/ivette/src/renderer/Values.tsx b/ivette/src/renderer/Values.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..652f48fc1072c0a0ea7186293fdcaec0504e00c5
--- /dev/null
+++ b/ivette/src/renderer/Values.tsx
@@ -0,0 +1,141 @@
+// --------------------------------------------------------------------------
+// --- Eva Values
+// --------------------------------------------------------------------------
+
+import React from 'react';
+import * as States from 'frama-c/states';
+import * as Json from 'dome/data/json';
+import * as Eva from 'api/plugins/eva/values';
+import * as Ast from 'api/kernel/ast';
+import * as Compare from 'dome/data/compare';
+
+import { Table, Column } from 'dome/table/views';
+import { ArrayModel } from 'dome/table/arrays';
+import { Component } from 'frama-c/LabViews';
+import { Icon } from 'dome/controls/icons';
+import { Label } from 'dome/controls/labels';
+
+// --------------------------------------------------------------------------
+// --- Columns
+// --------------------------------------------------------------------------
+
+const CallstackRenderer = (
+  (cs: Eva.callstack) => <Label label={cs.short} title={cs.full} />
+);
+
+const ColumnCallstack = () => Column({
+  id: 'callstack',
+  label: 'Callstack',
+  title: 'Context of the evaluation',
+  align: 'left',
+  width: 150,
+  render: CallstackRenderer,
+});
+
+const AlarmRenderer = (
+  (alarm: boolean) => <>{alarm && <Icon id="ATTENTION" />}</>
+);
+
+const ColumnAlarm = (props: { visible: boolean }) => Column({
+  id: 'alarm',
+  label: 'Alarm',
+  title: 'Did the evaluation emit an alarm?',
+  align: 'center',
+  width: 26,
+  fixed: true,
+  icon: 'WARNING',
+  visible: props.visible,
+  render: AlarmRenderer,
+});
+
+const byValues: Compare.ByFields<Eva.valuesData> =
+  { callstack: Compare.defined(Compare.byFields({ full: Compare.string })) };
+
+class ValuesModel extends ArrayModel<Json.key<'#values'>, Eva.valuesData> {
+  constructor() {
+    super();
+    this.setOrderingByFields(byValues);
+  }
+}
+
+// --------------------------------------------------------------------------
+// --- Values Panel
+// --------------------------------------------------------------------------
+
+const Values = () => {
+
+  const model = React.useMemo(() => new ValuesModel(), []);
+  const evaValues = States.useSyncArray(Eva.values).getArray();
+  const selectMarker = States.useSelection()[0]?.current?.marker;
+  const markerInfo = States.useSyncArray(Ast.markerInfo).getArray();
+  const [name, setName] = React.useState<string | undefined>(undefined);
+
+  States.useRequest(Eva.getValues, selectMarker);
+
+  React.useEffect(() => {
+    model.removeAllData();
+    if (selectMarker && evaValues) {
+      const selectMarkerInfo = markerInfo.find((e) => e.key === selectMarker);
+      if (selectMarkerInfo && selectMarkerInfo.var !== 'function') {
+        switch (selectMarkerInfo.kind) {
+          case 'expression':
+          case 'lvalue':
+            evaValues.forEach((i) => model.setData(i.key, i));
+            setName(selectMarkerInfo.descr);
+            break;
+          case 'declaration':
+            evaValues.forEach((i) => model.setData(i.key, i));
+            setName(selectMarkerInfo.name);
+            break;
+          default:
+            setName(undefined);
+        }
+      }
+    } else {
+      setName(undefined);
+    }
+    model.reload();
+  }, [evaValues, selectMarker, markerInfo, model]);
+
+  // Component
+  return (
+    <>
+      <Table model={model}>
+        <ColumnCallstack />
+        <Column
+          id="value_before"
+          visible={!!name}
+          label={name && `${name} (before)`}
+          title="Values inferred by Eva just before the selected point"
+          disableSort
+          width={300}
+        />
+        <ColumnAlarm visible={!!name} />
+        <Column
+          id="value_after"
+          visible={!!name}
+          label={name && `${name} (after)`}
+          title="Values inferred by Eva just after the selected point"
+          disableSort
+          width={300}
+        />
+      </Table>
+    </>
+  );
+};
+
+// --------------------------------------------------------------------------
+// --- Export Component
+// --------------------------------------------------------------------------
+
+export default () => (
+  <Component
+    id="frama-c.values"
+    label="Eva Values"
+    title="Values inferred by the Eva analysis"
+  >
+    <Values />
+  </Component>
+);
+
+// --------------------------------------------------------------------------
diff --git a/ivette/tests/eva-2.i b/ivette/tests/eva-2.i
new file mode 100644
index 0000000000000000000000000000000000000000..8b0998c24954c340558942ef8f4bf7e1c66205da
--- /dev/null
+++ b/ivette/tests/eva-2.i
@@ -0,0 +1,20 @@
+volatile int nondet;
+
+void fun () {
+  int x = nondet;
+  x = -x;
+}
+
+void yet_another () {
+  int x = nondet;
+  fun ();
+  int y = 100 / x;
+}
+
+void main () {
+  fun ();
+  /*@ assert boh: 1 == 1; */
+  yet_another ();
+  int i = 0;
+  /*@ assert user: i == 0; */
+}
diff --git a/ivette/yarn.lock b/ivette/yarn.lock
index 326cb44b75057094cf39c1457749096978a8f9f6..014efd5cfda84900de0d0ebb570171ce8c6ac593 100644
--- a/ivette/yarn.lock
+++ b/ivette/yarn.lock
@@ -3337,6 +3337,15 @@ electron-devtools-installer@^2.2.4:
     rimraf "^2.5.2"
     semver "^5.3.0"
 
+electron-devtools-installer@^3.0.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-3.1.1.tgz#7b56c8c86475c5e4e10de6917d150c53c9ceb55e"
+  integrity sha512-g2D4J6APbpsiIcnLkFMyKZ6bOpEJ0Ltcc2m66F7oKUymyGAt628OWeU9nRZoh1cNmUs/a6Cls2UfOmsZtE496Q==
+  dependencies:
+    rimraf "^3.0.2"
+    semver "^7.2.1"
+    unzip-crx-3 "^0.2.0"
+
 electron-publish@22.4.1:
   version "22.4.1"
   resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-22.4.1.tgz#a7fcf166786f7d5957f19a70ee8389f219769ba5"
@@ -4813,6 +4822,11 @@ ignore@^4.0.6:
   resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
   integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
 
+immediate@~3.0.5:
+  version "3.0.6"
+  resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
+  integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
+
 immutable@^4.0.0-rc.12:
   version "4.0.0-rc.12"
   resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217"
@@ -5393,6 +5407,16 @@ jsx-ast-utils@^2.4.1:
     array-includes "^3.1.1"
     object.assign "^4.1.0"
 
+jszip@^3.1.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.5.0.tgz#b4fd1f368245346658e781fec9675802489e15f6"
+  integrity sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==
+  dependencies:
+    lie "~3.3.0"
+    pako "~1.0.2"
+    readable-stream "~2.3.6"
+    set-immediate-shim "~1.0.1"
+
 keyv@^3.0.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
@@ -5487,6 +5511,13 @@ levn@^0.3.0, levn@~0.3.0:
     prelude-ls "~1.1.2"
     type-check "~0.3.2"
 
+lie@~3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"
+  integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
+  dependencies:
+    immediate "~3.0.5"
+
 linkify-it@^2.0.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf"
@@ -6411,7 +6442,7 @@ package-json@^6.3.0:
     registry-url "^5.0.0"
     semver "^6.2.0"
 
-pako@~1.0.5:
+pako@~1.0.2, pako@~1.0.5:
   version "1.0.11"
   resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
   integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
@@ -7576,6 +7607,13 @@ rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.3, rimraf@^2.7.1:
   dependencies:
     glob "^7.1.3"
 
+rimraf@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+  integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+  dependencies:
+    glob "^7.1.3"
+
 ripemd160@^2.0.0, ripemd160@^2.0.1:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
@@ -7723,7 +7761,7 @@ semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
   resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
   integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
 
-semver@^7.1.1:
+semver@^7.1.1, semver@^7.2.1:
   version "7.3.2"
   resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
   integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
@@ -7821,6 +7859,11 @@ set-blocking@^2.0.0:
   resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
   integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
 
+set-immediate-shim@~1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+  integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=
+
 set-value@^2.0.0, set-value@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
@@ -8761,6 +8804,15 @@ unset-value@^1.0.0:
     has-value "^0.3.1"
     isobject "^3.0.0"
 
+unzip-crx-3@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz#d5324147b104a8aed9ae8639c95521f6f7cda292"
+  integrity sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==
+  dependencies:
+    jszip "^3.1.0"
+    mkdirp "^0.5.1"
+    yaku "^0.16.6"
+
 upath@^1.1.1:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
@@ -9209,6 +9261,11 @@ xtend@^4.0.0, xtend@~4.0.1:
   resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
   integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
 
+yaku@^0.16.6:
+  version "0.16.7"
+  resolved "https://registry.yarnpkg.com/yaku/-/yaku-0.16.7.tgz#1d195c78aa9b5bf8479c895b9504fd4f0847984e"
+  integrity sha1-HRlceKqbW/hHnIlblQT9TwhHmE4=
+
 yallist@^2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
diff --git a/src/libraries/utils/utf8_logic.ml b/src/libraries/utils/utf8_logic.ml
index 1c2f3a6ddf068d4d24cec065a1d52cbad7f28301..92f594e89998bdcfad518673c529275de25a26e6 100644
--- a/src/libraries/utils/utf8_logic.ml
+++ b/src/libraries/utils/utf8_logic.ml
@@ -78,6 +78,9 @@ let integer = from_unichar 0x2124
 let real = from_unichar 0x211D
 
 let pi = from_unichar 0x3C0
+
+let infinity = from_unichar 0x221E
+
 (*
 Local Variables:
 compile-command: "make -C ../../.."
diff --git a/src/libraries/utils/utf8_logic.mli b/src/libraries/utils/utf8_logic.mli
index 449e20476bd3f55a53b09dd0cf143395d1ce5fad..7b6ea13a0da7362607108c23d890ca96d5f34184 100644
--- a/src/libraries/utils/utf8_logic.mli
+++ b/src/libraries/utils/utf8_logic.mli
@@ -49,6 +49,7 @@ val boolean: string
 val integer: string
 val real: string
 val pi: string
+val infinity: string
 
 (*
 Local Variables:
diff --git a/src/plugins/server/kernel_ast.ml b/src/plugins/server/kernel_ast.ml
index 7c18b2b5e3c00b3b5d0847da68dc9c91e6caedac..c9e03ae607829bb4f3833ff2a5a1bf98bbe49414 100644
--- a/src/plugins/server/kernel_ast.ml
+++ b/src/plugins/server/kernel_ast.ml
@@ -46,11 +46,12 @@ module MarkerKind = struct
 
   let kinds = Enum.dictionary ()
 
-  let kind name = Enum.tag ~name
-      ~descr:(Md.plain (String.capitalize_ascii name)) kinds
+  let kind name =
+    Enum.tag
+      ~name
+      ~descr:(Md.plain (String.capitalize_ascii name))
+      kinds
 
-  let var  = kind "variable"
-  let fct  = kind "function"
   let expr = kind "expression"
   let lval = kind "lvalue"
   let decl = kind "declaration"
@@ -59,24 +60,65 @@ module MarkerKind = struct
   let term = kind "term"
   let prop = kind "property"
 
-  let () = Enum.set_lookup kinds
-      begin
-        let open Printer_tag in
-        function
-        | PStmt _ -> stmt
-        | PStmtStart _ -> stmt
-        | PVDecl _ -> decl
-        | PLval (_, _, (Var vi, NoOffset)) ->
-          if Cil.isFunctionType vi.vtype then fct else var
-        | PLval _ -> lval
-        | PExp _ -> expr
-        | PTermLval _ -> term
-        | PGlobal _ -> glob
-        | PIP _ -> prop
-      end
-
-  let data = Request.dictionary ~package
-      ~name:"markerKind" ~descr:(Md.plain "Marker kind") kinds
+  let () =
+    Enum.set_lookup
+      kinds
+      (fun localizable ->
+         let open Printer_tag in
+         match localizable with
+         | PStmt _ -> stmt
+         | PStmtStart _ -> stmt
+         | PVDecl _ -> decl
+         | PLval _ -> lval
+         | PExp _ -> expr
+         | PTermLval _ -> term
+         | PGlobal _ -> glob
+         | PIP _ -> prop)
+
+  let data =
+    Request.dictionary
+      ~package
+      ~name:"markerKind"
+      ~descr:(Md.plain "Marker kind")
+      kinds
+
+  include (val data : S with type t = Printer_tag.localizable)
+end
+
+module MarkerVar = struct
+
+  let vars = Enum.dictionary ()
+
+  let kind name =
+    Enum.tag
+      ~name
+      ~descr:(Md.plain (String.capitalize_ascii name))
+      vars
+
+  let none = kind "none"
+  let var = kind "variable"
+  let fct = kind "function"
+
+  let () =
+    Enum.set_lookup
+      vars
+      (fun localizable ->
+         let open Printer_tag in
+         match localizable with
+         | PLval (_, _, (Var vi, NoOffset))
+         | PVDecl (_, _, vi)
+         | PGlobal (GVar (vi, _, _)  | GVarDecl (vi, _)) ->
+           if Cil.isFunctionType vi.vtype then fct else var
+         | PGlobal (GFun _ | GFunDecl _) -> fct
+         | PLval _ | PStmt _ | PStmtStart _
+         | PExp _ | PTermLval _ | PGlobal _ | PIP _ -> none)
+
+  let data =
+    Request.dictionary
+      ~package
+      ~name:"markerVar"
+      ~descr:(Md.plain "Marker variable")
+      vars
 
   include (val data : S with type t = Printer_tag.localizable)
 end
@@ -122,8 +164,18 @@ struct
     let model = States.model () in
     let () =
       States.column
-        ~name:"kind" ~descr:(Md.plain "Marker kind")
-        ~data:(module MarkerKind) ~get:fst
+        ~name:"kind"
+        ~descr:(Md.plain "Marker kind")
+        ~data:(module MarkerKind)
+        ~get:fst
+        model
+    in
+    let () =
+      States.column
+        ~name:"var"
+        ~descr:(Md.plain "Marker variable")
+        ~data:(module MarkerVar)
+        ~get:fst
         model
     in
     let () =
diff --git a/src/plugins/value/api/general_requests.ml b/src/plugins/value/api/general_requests.ml
index 5c30a704fbcb1fc5e59c9b7bbcf611adc6091460..09877676a76673136ad2b7a7f7f179ec8cadfbdd 100644
--- a/src/plugins/value/api/general_requests.ml
+++ b/src/plugins/value/api/general_requests.ml
@@ -22,8 +22,13 @@
 
 open Server
 
-let package = Package.package ~plugin:"eva"
-    ~title:"Eva General Services" ~readme:"eva.md" ()
+let package =
+  Package.package
+    ~plugin:"eva"
+    ~name:"general"
+    ~title:"Eva General Services"
+    ~readme:"eva.md"
+    ()
 
 module CallSite = Data.Jpair (Kernel_ast.Kf) (Kernel_ast.Stmt)
 
diff --git a/src/plugins/value/api/values_request.ml b/src/plugins/value/api/values_request.ml
new file mode 100644
index 0000000000000000000000000000000000000000..85d2df413cded868f8088cdb2d72602a095ca4ac
--- /dev/null
+++ b/src/plugins/value/api/values_request.ml
@@ -0,0 +1,366 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2020                                               *)
+(*    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 Server
+open Data
+open Cil_types
+module Md = Markdown
+
+let package =
+  Package.package
+    ~plugin:"eva"
+    ~name:"values"
+    ~title:"Eva Values"
+    ~readme:"eva.md"
+    ()
+
+type value =
+  { value: string;
+    alarm: bool; }
+
+type evaluation =
+  | Unreachable
+  | Evaluation of value
+
+type after =
+  | Unchanged
+  | Reduced of evaluation
+
+type before_after =
+  { before: evaluation;
+    after_instr: after option;
+    after_then: after option;
+    after_else: after option; }
+
+type values =
+  { values: before_after;
+    callstack: (Value_util.callstack * before_after) list option; }
+
+let get_value = function
+  | Unreachable -> "Unreachable"
+  | Evaluation { value } -> value
+
+let get_alarm = function
+  | Unreachable -> false
+  | Evaluation { alarm } -> alarm
+
+let get_after_value =
+  Extlib.opt_map
+    (function Unchanged -> "unchanged" | Reduced eval -> get_value eval)
+
+module CallStackId =
+  Data.Index
+    (Value_types.Callstack.Map)
+    (struct
+      let name = "eva-callstack-id"
+    end)
+
+(* This pretty-printer drops the toplevel kf, which is always the function
+   in which we are pretty-printing the expression/term *)
+let pretty_callstack fmt cs =
+  match cs with
+  | [_, Kglobal] -> ()
+  | (_kf_cur, Kstmt callsite) :: q -> begin
+      let rec aux callsite = function
+        | (kf, callsite') :: q -> begin
+            Format.fprintf fmt "%a (%a)"
+              Kernel_function.pretty kf
+              Cil_datatype.Location.pretty (Cil_datatype.Stmt.loc callsite);
+            match callsite' with
+            | Kglobal -> ()
+            | Kstmt callsite' ->
+              Format.fprintf fmt " ←@ ";
+              aux callsite' q
+          end
+        | _ -> assert false
+      in
+      Format.fprintf fmt "@[<hv>%a" Value_types.Callstack.pretty_hash cs;
+      aux callsite q;
+      Format.fprintf fmt "@]"
+    end
+  | _ -> assert false
+
+(* This pretty-printer prints only the lists of the functions, not
+   the locations. *)
+let pretty_callstack_short fmt cs =
+  match cs with
+  | [_, Kglobal] -> ()
+  | (_kf_cur, Kstmt _callsite) :: q ->
+    Format.fprintf fmt "%a" Value_types.Callstack.pretty_hash cs;
+    Pretty_utils.pp_flowlist ~left:"@[" ~sep:" ←@ " ~right:"@]"
+      (fun fmt (kf, _) -> Kernel_function.pretty fmt kf) fmt q
+  | _ -> assert false
+
+module CallStack = struct
+  type record
+
+  let record: record Record.signature = Record.signature ()
+
+  let id = Record.field record ~name:"id"
+      ~descr:(Md.plain "Callstack id") (module Jint)
+  let short = Record.field record ~name:"short"
+      ~descr:(Md.plain "Short name for the callstack") (module Jstring)
+  let full = Record.field record ~name:"full"
+      ~descr:(Md.plain "Full name for the callstack") (module Jstring)
+
+  module R =
+    (val
+      (Record.publish
+         ~package
+         ~name:"callstack"
+         ~descr:(Md.plain "CallStack")
+         record) : Record.S with type r = record)
+
+  type t = Value_types.callstack option
+
+  let jtype = R.jtype
+
+  let pp_callstack ~short = function
+    | None -> if short then "all" else ""
+    | Some callstack ->
+      let pp_text =
+        if short
+        then Pretty_utils.to_string ~margin:50 pretty_callstack_short
+        else Pretty_utils.to_string pretty_callstack
+      in
+      (pp_text callstack)
+
+  let id_callstack = function
+    | None -> -1
+    | Some callstack -> CallStackId.get callstack
+
+  let to_json callstack =
+    R.default |>
+    R.set id (id_callstack callstack) |>
+    R.set short (pp_callstack ~short:true callstack) |>
+    R.set full (pp_callstack ~short:false callstack) |>
+    R.to_json
+
+  let key = function
+    | None -> "all"
+    | Some callstack -> string_of_int (CallStackId.get callstack)
+end
+
+
+let consolidated = ref None
+let table = Hashtbl.create 100
+
+let iter f =
+  if Hashtbl.length table > 1
+  then Extlib.may (fun values -> f (None, values)) !consolidated;
+  Hashtbl.iter (fun key data -> f (Some key, data)) table
+
+let array =
+  let model = States.model () in
+  let () =
+    States.column
+      ~name:"callstack"
+      ~descr:(Md.plain "CallStack")
+      ~data:(module CallStack)
+      ~get:fst
+      model
+  in
+  let () =
+    States.column
+      ~name:"value_before"
+      ~descr:(Md.plain "Value inferred just before the selected point")
+      ~data:(module Jstring)
+      ~get:(fun (_, e) -> get_value e.before)
+      model
+  in
+  let () =
+    States.column
+      ~name:"alarm"
+      ~descr:(Md.plain "Did the evaluation led to an alarm?")
+      ~data:(module Jbool)
+      ~get:(fun (_, e) -> get_alarm e.before)
+      model
+  in
+  let () =
+    States.column
+      ~name:"value_after"
+      ~descr:(Md.plain "Value inferred just after the selected point")
+      ~data:(module Joption(Jstring))
+      ~get:(fun (_, e) -> get_after_value e.after_instr)
+      model
+  in
+  States.register_array
+    ~package
+    ~name:"values"
+    ~descr:(Md.plain "Abstract values inferred by the Eva analysis")
+    ~key:(fun (cs, _) -> CallStack.key cs)
+    ~iter
+    model
+
+let update_values values =
+  Hashtbl.clear table;
+  consolidated := Some values.values;
+  let () =
+    match values.callstack with
+    | None -> ()
+    | Some by_callstack ->
+      List.iter
+        (fun (callstack, before_after) ->
+           Hashtbl.add table callstack before_after)
+        by_callstack
+  in
+  States.reload array
+
+module type S = sig
+  val evaluate: kinstr -> exp -> values
+  val lvaluate: kinstr -> lval -> values
+end
+
+module Make (Eva: Analysis.S) : S = struct
+
+  let make_before eval before =
+    let before =
+      match before with
+      | `Bottom -> Unreachable
+      | `Value state -> Evaluation (eval state)
+    in
+    { before; after_instr = None; after_then = None; after_else = None; }
+
+  let make_callstack stmt eval =
+    let before = Eva.get_stmt_state_by_callstack ~after:false stmt in
+    match before with
+    | (`Bottom | `Top) -> []
+    | `Value before ->
+      let aux callstack before acc =
+        let before_after = make_before eval (`Value before) in
+        (callstack, before_after) :: acc
+      in
+      Value_types.Callstack.Hashtbl.fold aux before []
+
+  let make_before_after eval ~before ~after =
+    match before with
+    | `Bottom ->
+      { before = Unreachable;
+        after_instr = None;
+        after_then = None;
+        after_else = None; }
+    | `Value before ->
+      let before = eval before in
+      let after_instr =
+        match after with
+        | `Bottom -> Some (Reduced Unreachable)
+        | `Value after ->
+          let after = eval after in
+          if String.equal before.value after.value
+          then Some Unchanged
+          else Some (Reduced (Evaluation after))
+      in
+      { before = Evaluation before;
+        after_instr; after_then = None; after_else = None; }
+
+  let make_instr_callstack stmt eval =
+    let before = Eva.get_stmt_state_by_callstack ~after:false stmt in
+    let after = Eva.get_stmt_state_by_callstack ~after:true stmt in
+    match before, after with
+    | (`Bottom | `Top), _
+    | _, (`Bottom | `Top) -> []
+    | `Value before, `Value after ->
+      let aux callstack before acc =
+        let before = `Value before in
+        let after =
+          try `Value (Value_types.Callstack.Hashtbl.find after callstack)
+          with Not_found -> `Bottom
+        in
+        let before_after = make_before_after eval ~before ~after in
+        (callstack, before_after) :: acc
+      in
+      Value_types.Callstack.Hashtbl.fold aux before []
+
+  let make eval kinstr =
+    let before = Eva.get_kinstr_state ~after:false kinstr in
+    let values, callstack =
+      match kinstr with
+      | Cil_types.Kglobal ->
+        make_before eval before, None
+      | Cil_types.Kstmt stmt ->
+        match stmt.skind with
+        | Instr _ ->
+          let after = Eva.get_kinstr_state ~after:true kinstr in
+          let values = make_before_after eval ~before ~after in
+          let callstack = make_instr_callstack stmt eval in
+          values, Some callstack
+        | _ ->
+          make_before eval before, Some (make_callstack stmt eval)
+    in
+    { values; callstack; }
+
+
+  let evaluate kinstr expr =
+    let eval state =
+      let value, alarms = Eva.eval_expr state expr in
+      let alarm = not (Alarmset.is_empty alarms) in
+      let str = Format.asprintf "%a" (Bottom.pretty Eva.Val.pretty) value in
+      { value = str; alarm }
+    in
+    make eval kinstr
+
+  let lvaluate kinstr lval =
+    let eval state =
+      let value, alarms = Eva.copy_lvalue state lval in
+      let alarm = not (Alarmset.is_empty alarms) in
+      let flagged_value = match value with
+        | `Bottom -> Eval.Flagged_Value.bottom
+        | `Value v -> v
+      in
+      let pretty = Eval.Flagged_Value.pretty Eva.Val.pretty in
+      let str = Format.asprintf "%a" pretty flagged_value in
+      { value = str; alarm }
+    in
+    make eval kinstr
+end
+
+
+let ref_request =
+  let module Analyzer = (val Analysis.current_analyzer ()) in
+  ref (module Make (Analyzer) : S)
+
+let hook (module Analyzer: Analysis.S) =
+  ref_request := (module Make (Analyzer) : S)
+
+let () = Analysis.register_hook hook
+
+
+let update tag =
+  let module Request = (val !ref_request) in
+  match tag with
+  | Printer_tag.PExp (_kf, kinstr, expr) ->
+    update_values (Request.evaluate kinstr expr)
+  | Printer_tag.PLval (_kf, kinstr, lval) ->
+    update_values (Request.lvaluate kinstr lval)
+  | PVDecl (_kf, kinstr, varinfo) ->
+    update_values (Request.lvaluate kinstr (Var varinfo, NoOffset))
+  | _ -> ()
+
+let () =
+  Server.Request.register
+    ~package
+    ~kind:`GET
+    ~name:"getValues"
+    ~descr:(Md.plain "Get the abstract values computed for an expression or lvalue")
+    ~input:(module Kernel_ast.Marker)
+    ~output:(module Junit)
+    update
diff --git a/src/plugins/value/api/values_request.mli b/src/plugins/value/api/values_request.mli
new file mode 100644
index 0000000000000000000000000000000000000000..182bc40a8e1af00f6d1329952d449d0f2e6808e1
--- /dev/null
+++ b/src/plugins/value/api/values_request.mli
@@ -0,0 +1,21 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2020                                               *)
+(*    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).            *)
+(*                                                                        *)
+(**************************************************************************)