diff --git a/Makefile b/Makefile
index 0f4ac62279f4715a7f850cb5d9d89fd0c3de60d9..73227de03b3dd9af4d1808ff412231d0d104fe56 100644
--- a/Makefile
+++ b/Makefile
@@ -268,6 +268,7 @@ DISTRIB_FILES:=\
       share/analysis-scripts/function_finder.py                         \
       share/analysis-scripts/git_utils.py                               \
       share/analysis-scripts/list_files.py                              \
+      share/analysis-scripts/list_functions.ml                          \
       share/analysis-scripts/make_template.py                           \
       share/analysis-scripts/make_wrapper.py                            \
       share/analysis-scripts/normalize_jcdb.py                          \
@@ -1934,6 +1935,7 @@ install:: install-lib-$(OCAMLBEST)
 	  share/analysis-scripts/function_finder.py \
 	  share/analysis-scripts/git_utils.py \
 	  share/analysis-scripts/list_files.py \
+	  share/analysis-scripts/list_functions.ml \
 	  share/analysis-scripts/make_template.py \
 	  share/analysis-scripts/make_wrapper.py \
 	  share/analysis-scripts/normalize_jcdb.py \
diff --git a/bin/frama-c-script b/bin/frama-c-script
index 8ff07f4647a65df4d4b3da0193357f9bdc06a09c..aef3ebe68fb1c7a081f4277d7d70778f88426ec8 100755
--- a/bin/frama-c-script
+++ b/bin/frama-c-script
@@ -44,6 +44,11 @@ usage() {
    echo "      Also lists files defining a 'main' function"
    echo "      (heuristics-based; neither correct nor complete)."
    echo ""
+   echo "  - list-functions [files] [Frama-C options]"
+   echo "      Parses all sources in [files] and lists all function"
+   echo "      definitions, with source location and number of statements."
+   echo "      Accepts Frama-C options (e.g. -cpp-extra-args for parsing)."
+   echo ""
    echo "  - flamegraph flamegraph.txt [dir]"
    echo "      Generates flamegraph.svg and flamegraph.html in dir"
    echo "      [default: FRAMAC_SESSION]."
@@ -191,6 +196,13 @@ case "$command" in
         shift;
         ${FRAMAC_SHARE}/analysis-scripts/list_files.py "$@";
         ;;
+    "list-functions")
+        shift;
+        # to avoid a slow startup, we only load plugins which perform syntactic
+        # transformations. This may trigger annotation errors due to missing
+        # plugins, so we disable those
+        ${DIR}/frama-c "$@" -no-autoload-plugins -load-module variadic,instantiate,${FRAMAC_SHARE}/analysis-scripts/list_functions.ml -kernel-warn-key annot-error=inactive -kernel-verbose 0;
+        ;;
     "find-fun")
         shift;
         ${FRAMAC_SHARE}/analysis-scripts/find_fun.py "$@";
diff --git a/headers/header_spec.txt b/headers/header_spec.txt
index d1b383e76b2d8a39234b67339deb1984c7ad12b3..fd4e1e3307f1c10e1f9d928437902baed317192d 100644
--- a/headers/header_spec.txt
+++ b/headers/header_spec.txt
@@ -126,6 +126,7 @@ share/analysis-scripts/flamegraph.pl: CDDL
 share/analysis-scripts/function_finder.py: .ignore
 share/analysis-scripts/git_utils.py: .ignore
 share/analysis-scripts/list_files.py: .ignore
+share/analysis-scripts/list_functions.ml: .ignore
 share/analysis-scripts/make_template.py: .ignore
 share/analysis-scripts/make_wrapper.py: .ignore
 share/analysis-scripts/normalize_jcdb.py: .ignore
diff --git a/share/analysis-scripts/list_functions.ml b/share/analysis-scripts/list_functions.ml
new file mode 100644
index 0000000000000000000000000000000000000000..4393ee3f414b9655b2282d482776b1203297a662
--- /dev/null
+++ b/share/analysis-scripts/list_functions.ml
@@ -0,0 +1,282 @@
+(* To avoid listing declarations several times, we use their locations
+   as proxies. However, we cannot directly compare locations, since static
+   (re-)definitions, as well as prototypes included several times,
+   have locations which are physically different (pos_cnum)
+   despite being semantically identical (same file/line/column).
+   The module below provides a hash table using the equality function
+   corresponding to our needs.
+*)
+module SemanticLocs : sig
+  include Hashtbl.S with type key = Cil_datatype.Location.t
+  val is_empty: 'a t -> bool
+  val keys: 'a t -> key list (* sorted w.r.t. cmp_start_semantic *)
+  val elements: 'a t -> (key * 'a) list (* sorted w.r.t. cmp_start_semantic *)
+end =
+struct
+  include
+    Hashtbl.Make(struct
+      type t = Cil_datatype.Location.t
+      let equal = Cil_datatype.Location.equal_start_semantic
+      let hash (b, _e) = Hashtbl.hash (b.Filepath.pos_path, b.Filepath.pos_lnum)
+    end)
+  let is_empty tbl = length tbl = 0
+  let keys tbl =
+    let l = fold (fun loc _ acc -> loc :: acc) tbl [] in
+    List.sort Cil_datatype.Location.compare_start_semantic l
+  let elements tbl =
+    let l = fold (fun loc v acc -> (loc, v) :: acc) tbl [] in
+    List.sort (fun (l1, _v1) (l2, _v2) ->
+        Cil_datatype.Location.compare_start_semantic l1 l2) l
+end
+
+module Self = Plugin.Register
+    (struct
+      let name = "list-functions"
+      let shortname = "list-functions"
+      let help = "prints the list of function definitions and declarations, \
+                  along with their locations and number of statements, \
+                  in text or JSON format"
+    end)
+
+module PrintLibc =
+  Self.False
+    (struct
+      let option_name = "-list-functions-libc"
+      let help = "whether to print functions located within Frama-C's libc \
+                  directory. Default: false"
+    end)
+
+module PrintDeclarations =
+  Self.False
+    (struct
+      let option_name = "-list-functions-declarations"
+      let help = "whether to print function declarations. Default: false"
+    end)
+
+module Output =
+  Self.Filepath
+    (struct
+      let option_name = "-list-functions-output"
+      let arg_name = "filename"
+      let existence = Filepath.Indifferent
+      let file_kind = "json"
+      let help = "where to save the output, in JSON format. If omitted', \
+                  then output to stdout in text format instead"
+    end)
+
+type funinfo = {
+  name : string;
+  declarations : unit SemanticLocs.t;
+  definitions : int (*number of statements*) SemanticLocs.t;
+  (* Note: only static functions can have multiple definitions *)
+}
+
+class stmt_count_visitor =
+  object
+    inherit Visitor.frama_c_inplace
+    val count = ref 0
+    method! vstmt_aux _s =
+      incr count;
+      Cil.DoChildren
+    method get = !count
+  end
+
+(* To find good locations for declarations and definitions, we use different
+   methods:
+   - For declarations, the Cabs AST information is much better than the Cil
+     one, which erases declarations when a definition is found;
+   - For definitions, the information seems to be equivalent, so we use the
+     one in Kernel_function.
+*)
+
+(* Due to the fact that the Cabs AST contains no fc_stdlib attributes, we use a
+   location-based approach. *)
+let located_within_framac_libc loc =
+  let pos = fst loc in
+  let file = (pos.Filepath.pos_path :> string) in
+  Filepath.is_relative ~base_name:Fc_config.framac_libc file
+
+class fun_cabs_visitor print_libc = object(self)
+  inherit Cabsvisit.nopCabsVisitor
+
+  val decls : (string, 'a SemanticLocs.t) Hashtbl.t = Hashtbl.create 7
+  method get_decls = decls
+
+  method private get_single_name (_spec, (name, _, _, _)) = name
+  method private get_name (name, _, _, _) = name
+
+  method private add_loc table name loc =
+    if print_libc || not (located_within_framac_libc loc) then
+      let locs_table =
+        try
+          Hashtbl.find table name
+        with
+        | Not_found ->
+          let t = SemanticLocs.create 1 in
+          Hashtbl.replace table name t;
+          t
+      in
+      SemanticLocs.replace locs_table loc ()
+
+  method! vdef def =
+    let open Cabs in
+    match def with
+    | FUNDEF _ ->
+      (* we will use Cil information anyway *)
+      Cil.SkipChildren
+    | DECDEF (_, (_, name_list), loc) ->
+      List.iter
+        (function
+          | ((name, PROTO _, _, _), _) ->
+            self#add_loc decls name loc
+          | _ -> ()
+        ) name_list;
+      Cil.SkipChildren
+    | _ ->
+      Cil.DoChildren
+
+end
+
+let print_json (fp : Filepath.Normalized.t) funinfos_json =
+  try
+    let oc = open_out (fp:>string) in
+    let fmt = Format.formatter_of_out_channel oc in
+    Json.pp fmt funinfos_json;
+    Format.fprintf fmt "@.";
+    close_out oc;
+    Self.debug "List written to: %a" Filepath.Normalized.pretty fp
+  with Sys_error msg ->
+    Self.abort "cannot write JSON to %a: %s"
+      Filepath.Normalized.pretty fp msg
+
+let pp_semlocs fmt t =
+  Format.fprintf fmt "%a"
+    (Pretty_utils.pp_list ~sep:", " Cil_datatype.Location.pretty)
+    (SemanticLocs.keys t)
+
+let pp_loc_size fmt loc_size =
+  let (loc, size) = loc_size in
+  Format.fprintf fmt "%a (%d statement%s)"
+    Cil_datatype.Location.pretty loc size (if size <> 1 then "s" else "")
+
+let pp_definitions fmt defs =
+  Format.fprintf fmt "%a"
+    (Pretty_utils.pp_list ~sep:", " pp_loc_size)
+    (SemanticLocs.elements defs)
+
+let print_text funinfos =
+  List.iter (fun fi ->
+      if PrintDeclarations.get () ||
+         not (SemanticLocs.is_empty fi.definitions) then
+        begin
+          Format.printf "%s:" fi.name;
+          begin
+            if not (SemanticLocs.is_empty fi.definitions) then
+              Format.printf " defined at %a;"
+                pp_definitions fi.definitions
+          end;
+          if PrintDeclarations.get () &&
+             not (SemanticLocs.is_empty fi.declarations) then
+            Format.printf " declared at %a" pp_semlocs fi.declarations;
+          if SemanticLocs.(is_empty fi.definitions && is_empty fi.declarations)
+          then
+            Format.printf " called but never declared nor defined";
+          Format.printf "@."
+        end
+    ) funinfos
+
+let get_size kf =
+  let stmt_count_vis = new stmt_count_visitor in
+  ignore Visitor.(visitFramacKf (stmt_count_vis :> frama_c_inplace) kf);
+  stmt_count_vis#get
+
+let definitions_with_size name =
+  let kfs =
+    List.filter Kernel_function.is_definition
+      (Globals.Functions.find_all_by_orig_name name)
+  in
+  let defs_with_size = SemanticLocs.create (List.length kfs) in
+  List.iter (fun kf ->
+      let n = get_size kf in
+      let loc = Kernel_function.get_location kf in
+      SemanticLocs.add defs_with_size loc n
+    ) kfs;
+  defs_with_size
+
+let json_string_of_loc loc =
+  `String (Format.asprintf "%a" Cil_datatype.Location.pretty loc)
+
+let json_list_of_loc_tbl tbl =
+  let keys = SemanticLocs.keys tbl in
+  `List (List.map json_string_of_loc keys)
+
+let json_array_of_loc_size (loc, size) =
+  `Assoc [("location", json_string_of_loc loc); ("statements", `Int size)]
+
+let json_list_of_loc_size_tbl tbl =
+  let elements = SemanticLocs.elements tbl in
+  `List (List.map json_array_of_loc_size elements)
+
+let run () =
+  if List.length (File.get_all ()) < 1 then begin
+    Self.abort "no input files";
+  end;
+  let cabs_files = Ast.UntypedFiles.get () in
+  let vis = new fun_cabs_visitor (PrintLibc.get ()) in
+  List.iter (fun file ->
+      ignore Cabsvisit.(visitCabsFile (vis :> nopCabsVisitor) file)
+    ) cabs_files;
+  let decls = vis#get_decls in
+  let defs_without_decls = Globals.Functions.fold (fun kf acc ->
+      if Kernel_function.is_definition kf then begin
+        let orig_name = (Kernel_function.get_vi kf).vorig_name in
+        if Hashtbl.mem decls orig_name then acc
+        else Datatype.String.Set.add orig_name acc
+      end
+      else acc
+    ) Datatype.String.Set.empty
+  in
+  let funinfos =
+    Hashtbl.fold (fun name declarations acc ->
+        let definitions = definitions_with_size name in
+        let fi = { name; definitions; declarations } in
+        fi :: acc
+      ) decls []
+  in
+  (* add data for defined functions not present in 'decls' *)
+  let funinfos =
+    Datatype.String.Set.fold (fun orig_name acc ->
+        if not (Hashtbl.mem decls orig_name) then begin
+          let definitions = definitions_with_size orig_name in
+          let fi = { name = orig_name; definitions;
+                     declarations = SemanticLocs.create 0 }
+          in
+          fi :: acc
+        end else
+          acc
+      ) defs_without_decls funinfos
+  in
+  let funinfos = List.sort
+      (fun fi1 fi2 -> Extlib.compare_ignore_case fi1.name fi2.name) funinfos
+  in
+  let outfp = Output.get () in
+  if Filepath.Normalized.is_unknown outfp then
+    print_text funinfos
+  else
+    let funinfos_json = `List (List.map (fun fi ->
+        let definitions =
+          if SemanticLocs.is_empty fi.definitions then []
+          else
+            [("definitions", json_list_of_loc_size_tbl fi.definitions)]
+        in
+        let declarations =
+          if SemanticLocs.is_empty fi.declarations then []
+          else
+            [("declarations", json_list_of_loc_tbl fi.declarations)]
+        in
+        `Assoc [(fi.name, `Assoc (definitions @ declarations))]
+      ) funinfos)
+    in
+    print_json outfp funinfos_json
+
+let () = Db.Main.extend run
diff --git a/src/kernel_services/ast_data/globals.ml b/src/kernel_services/ast_data/globals.ml
index a88e444703a4b42a6e31ee16441763906e6bc61a..a2b09e2c8cf30738dd74c3f82d08e258bb87cb21 100644
--- a/src/kernel_services/ast_data/globals.ml
+++ b/src/kernel_services/ast_data/globals.ml
@@ -343,6 +343,17 @@ module Functions = struct
     let vi = Datatype.String.Map.find fct_name (Iterator.State.get ()) in
     State.find vi
 
+  let find_all_by_orig_name ?cmp fct_name =
+    let l =
+      Datatype.String.Map.fold (fun _ vi acc ->
+          if vi.vorig_name = fct_name then (State.find vi) :: acc
+          else acc
+        ) (Iterator.State.get ()) []
+    in
+    match cmp with
+    | None -> l
+    | Some cmp -> List.sort cmp l
+
   let find_def_by_name fct_name =
     let vi = Datatype.String.Map.find fct_name (Iterator.State.get ()) in
     let res = State.find vi in
diff --git a/src/kernel_services/ast_data/globals.mli b/src/kernel_services/ast_data/globals.mli
index b3f359ffbc8507182062c6876f840e6835056682..3487374d4a48b46f2e2692335acf4b9ba848659f 100644
--- a/src/kernel_services/ast_data/globals.mli
+++ b/src/kernel_services/ast_data/globals.mli
@@ -122,6 +122,16 @@ module Functions: sig
   val find_by_name : string -> kernel_function
   (** @raise Not_found if there is no function of this name. *)
 
+  val find_all_by_orig_name : ?cmp:(kernel_function -> kernel_function -> int) ->
+    string -> kernel_function list
+  (**
+     [find_all_by_orig_name ?cmp name] returns the list of functions whose original
+     name is [name], sorted according to [cmp]. If [cmp] is [None],
+     the resulting order is unspecified.
+
+     @since Frama-C+dev
+  *)
+
   val find_def_by_name : string -> kernel_function
   (** @raise Not_found if there is no function definition of this name. *)
 
diff --git a/src/kernel_services/ast_queries/cil_datatype.ml b/src/kernel_services/ast_queries/cil_datatype.ml
index 882c494bce29891729f876f88bc199d62ae6f864..f27558077f9ddebcab77d30c9a157432fcdc3a33 100644
--- a/src/kernel_services/ast_queries/cil_datatype.ml
+++ b/src/kernel_services/ast_queries/cil_datatype.ml
@@ -226,10 +226,15 @@ module Location = struct
   let to_lexing_loc (pos1, pos2) =
     Position.to_lexing_pos pos1, Position.to_lexing_pos pos2
 
-  let equal_start_semantic (pos1, _) (pos2, _) =
-    Filepath.(Datatype.Filepath.equal pos1.pos_path pos2.pos_path
-              && pos1.pos_lnum = pos2.pos_lnum
-              && pos1.pos_cnum - pos1.pos_bol = pos2.pos_cnum - pos2.pos_bol)
+  let compare_start_semantic (pos1, _) (pos2, _) =
+    let open Filepath in
+    let c = Datatype.Filepath.compare pos1.pos_path pos2.pos_path in
+    if c <> 0 then c else
+      let c = pos1.pos_lnum - pos2.pos_lnum in
+      if c <> 0 then c else
+        (pos1.pos_cnum - pos1.pos_bol) - (pos2.pos_cnum - pos2.pos_bol)
+
+  let equal_start_semantic l1 l2 = compare_start_semantic l1 l2 = 0
 
 end
 
diff --git a/src/kernel_services/ast_queries/cil_datatype.mli b/src/kernel_services/ast_queries/cil_datatype.mli
index 3370462e56180d807ee10c44c8fc415b29a801eb..4460eed18fe18b6adf899e6e63a5c7bf12869d1b 100644
--- a/src/kernel_services/ast_queries/cil_datatype.mli
+++ b/src/kernel_services/ast_queries/cil_datatype.mli
@@ -85,10 +85,15 @@ module Location: sig
       starting position. Compares normalized filenames, lines and columns,
       but no absolute character offsets.
 
+      @since Frama-C+dev
+   *)
+  val compare_start_semantic : location -> location -> int
+
+  (** Equality using [compare_start_semantic].
+
       @since 22.0-Titanium
    *)
   val equal_start_semantic : location -> location -> bool
-
 end
 
 module Localisation: Datatype.S with type t = localisation
diff --git a/tests/fc_script/for-find-fun2.c b/tests/fc_script/for-find-fun2.c
index 3cef634fc5b462b9892fc5f66510594e8a81ed58..45c8130a3683d16398c6bb839f3344fa151c9ce7 100644
--- a/tests/fc_script/for-find-fun2.c
+++ b/tests/fc_script/for-find-fun2.c
@@ -24,3 +24,8 @@ void h() {
 
  void false_positive(); // this is a "voluntary" false negative (space before):
                         // it allows us to avoid false positives more easily
+
+static int static_fun() {
+  static int init = 0;
+  return init;
+}
diff --git a/tests/fc_script/for-list-functions.c b/tests/fc_script/for-list-functions.c
new file mode 100644
index 0000000000000000000000000000000000000000..44ec1ad26863049872816ce4d4003b21e56693de
--- /dev/null
+++ b/tests/fc_script/for-list-functions.c
@@ -0,0 +1,22 @@
+/* run.config
+   DONTRUN: test run by main.c
+*/
+
+#include "for-list-functions2.h"
+#include "for-list-functions.h"
+
+static int static_fun() {
+  static int init = 0;
+  if (!init) {
+    init = 1;
+    return 2;
+  }
+  return 4;
+}
+
+void k() {
+  /*@ loop unroll 10; */ // Eva is not loaded, so we must ignore the annotation
+  for (int i = 0; i < 10; i++) {
+    extf();
+  }
+}
diff --git a/tests/fc_script/for-list-functions.h b/tests/fc_script/for-list-functions.h
new file mode 100644
index 0000000000000000000000000000000000000000..5bafea75c4645ebf8dc819c9ddee29931891d2cf
--- /dev/null
+++ b/tests/fc_script/for-list-functions.h
@@ -0,0 +1 @@
+#include "for-list-functions2.h"
diff --git a/tests/fc_script/for-list-functions2.h b/tests/fc_script/for-list-functions2.h
new file mode 100644
index 0000000000000000000000000000000000000000..7338669a3ed39623e9a31ad38ce5716178fcfd5f
--- /dev/null
+++ b/tests/fc_script/for-list-functions2.h
@@ -0,0 +1 @@
+extern void extf(void);
diff --git a/tests/fc_script/main.c b/tests/fc_script/main.c
index 288eaca6d5fbf66399f5cd29fddd152438d69f17..9b26d5592ce3a64f3b8fc228cbc79d62de0ab25f 100644
--- a/tests/fc_script/main.c
+++ b/tests/fc_script/main.c
@@ -5,6 +5,8 @@
    EXECNOW: LOG find_fun1.res LOG find_fun1.err bin/frama-c-script find-fun main2 @PTEST_DIR@ > @PTEST_DIR@/result/find_fun1.res 2> @PTEST_DIR@/result/find_fun1.err
    EXECNOW: LOG find_fun2.res LOG find_fun2.err bin/frama-c-script find-fun main3 @PTEST_DIR@ > @PTEST_DIR@/result/find_fun2.res 2> @PTEST_DIR@/result/find_fun2.err
    EXECNOW: LOG find_fun3.res LOG find_fun3.err bin/frama-c-script find-fun false_positive @PTEST_DIR@ > @PTEST_DIR@/result/find_fun3.res 2> @PTEST_DIR@/result/find_fun3.err
+   EXECNOW: LOG list_functions.res LOG list_functions.err bin/frama-c-script list-functions @PTEST_DIR@/for-find-fun2.c @PTEST_DIR@/for-list-functions.c > @PTEST_DIR@/result/list_functions.res 2> @PTEST_DIR@/result/list_functions.err
+   EXECNOW: LOG list_functions2.res LOG list_functions2.err LOG list_functions2.json bin/frama-c-script list-functions @PTEST_DIR@/for-find-fun2.c @PTEST_DIR@/for-list-functions.c -list-functions-declarations -list-functions-output @PTEST_DIR@/result/list_functions2.json -list-functions-debug 1 > @PTEST_DIR@/result/list_functions2.res 2> @PTEST_DIR@/result/list_functions2.err
  */
 
 void main() {
diff --git a/tests/fc_script/oracle/find_fun1.res b/tests/fc_script/oracle/find_fun1.res
index 3e35782af42a6f5546e034e026a63d09df5ac934..0ceb3c8c68b411868c7fd156287a3c668e09466c 100644
--- a/tests/fc_script/oracle/find_fun1.res
+++ b/tests/fc_script/oracle/find_fun1.res
@@ -1,4 +1,4 @@
-Looking for 'main2' inside 8 file(s)...
+Looking for 'main2' inside 11 file(s)...
 Possible declarations for function 'main2' in the following file(s):
   tests/fc_script/for-find-fun.c
 Possible definitions for function 'main2' in the following file(s):
diff --git a/tests/fc_script/oracle/find_fun2.res b/tests/fc_script/oracle/find_fun2.res
index e9f42fdf76a5d227ee458abdc59e3370a26d57d1..e59924a72f49f8278f2ff8fcec02062b9c68b2e3 100644
--- a/tests/fc_script/oracle/find_fun2.res
+++ b/tests/fc_script/oracle/find_fun2.res
@@ -1,4 +1,4 @@
-Looking for 'main3' inside 8 file(s)...
+Looking for 'main3' inside 11 file(s)...
 Possible declarations for function 'main3' in the following file(s):
   tests/fc_script/for-find-fun2.c
 Possible definitions for function 'main3' in the following file(s):
diff --git a/tests/fc_script/oracle/find_fun3.res b/tests/fc_script/oracle/find_fun3.res
index 65fc349325d2406ea212025ed38e51347b09217f..6d151d463efe8d8df1a1ac874653880564ee4eb1 100644
--- a/tests/fc_script/oracle/find_fun3.res
+++ b/tests/fc_script/oracle/find_fun3.res
@@ -1,2 +1,2 @@
-Looking for 'false_positive' inside 8 file(s)...
+Looking for 'false_positive' inside 11 file(s)...
 No declaration/definition found for function 'false_positive'
diff --git a/tests/fc_script/oracle/list_functions.err b/tests/fc_script/oracle/list_functions.err
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/fc_script/oracle/list_functions.res b/tests/fc_script/oracle/list_functions.res
new file mode 100644
index 0000000000000000000000000000000000000000..66661be089b1c3567da7838716c258edf2ac59bf
--- /dev/null
+++ b/tests/fc_script/oracle/list_functions.res
@@ -0,0 +1,7 @@
+[kernel:typing:implicit-function-declaration] tests/fc_script/for-find-fun2.c:16: Warning: 
+  Calling undeclared function false_positive. Old style K&R code?
+f: defined at tests/fc_script/for-find-fun2.c:10 (1 statement);
+g: defined at tests/fc_script/for-find-fun2.c:14 (3 statements);
+h: defined at tests/fc_script/for-find-fun2.c:19 (2 statements);
+k: defined at tests/fc_script/for-list-functions.c:17 (8 statements);
+static_fun: defined at tests/fc_script/for-find-fun2.c:28 (1 statement), tests/fc_script/for-list-functions.c:8 (7 statements);
diff --git a/tests/fc_script/oracle/list_functions2.err b/tests/fc_script/oracle/list_functions2.err
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/fc_script/oracle/list_functions2.json b/tests/fc_script/oracle/list_functions2.json
new file mode 100644
index 0000000000000000000000000000000000000000..7025402b87ea99196790c62e74432f85e5b8ac6d
--- /dev/null
+++ b/tests/fc_script/oracle/list_functions2.json
@@ -0,0 +1,14 @@
+[ { "extf": { "declarations": [ "tests/fc_script/for-list-functions2.h:1" ] } },
+  { "f": { "definitions": [ { "location": "tests/fc_script/for-find-fun2.c:10",
+                              "statements": 1 } ] } },
+  { "false_positive": { "declarations": [ "tests/fc_script/for-find-fun2.c:25" ] } },
+  { "g": { "definitions": [ { "location": "tests/fc_script/for-find-fun2.c:14",
+                              "statements": 3 } ] } },
+  { "h": { "definitions": [ { "location": "tests/fc_script/for-find-fun2.c:19",
+                              "statements": 2 } ] } },
+  { "k": { "definitions": [ { "location": "tests/fc_script/for-list-functions.c:17",
+                              "statements": 8 } ] } },
+  { "static_fun": { "definitions": [ { "location": "tests/fc_script/for-find-fun2.c:28",
+                                       "statements": 1 },
+                                     { "location": "tests/fc_script/for-list-functions.c:8",
+                                       "statements": 7 } ] } } ]
diff --git a/tests/fc_script/oracle/list_functions2.res b/tests/fc_script/oracle/list_functions2.res
new file mode 100644
index 0000000000000000000000000000000000000000..935425e8f69630f7d96101cf0193acff6d738412
--- /dev/null
+++ b/tests/fc_script/oracle/list_functions2.res
@@ -0,0 +1,3 @@
+[kernel:typing:implicit-function-declaration] tests/fc_script/for-find-fun2.c:16: Warning: 
+  Calling undeclared function false_positive. Old style K&R code?
+[list-functions] List written to: tests/fc_script/result/list_functions2.json