Script to generate the parsing code from kernel database.
authorRichard W.M. Jones <rjones@redhat.com>
Tue, 5 Aug 2008 17:44:31 +0000 (18:44 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Tue, 5 Aug 2008 17:44:31 +0000 (18:44 +0100)
HACKING
configure.ac
extract/README
extract/codegen/Makefile.in [new file with mode: 0644]
extract/codegen/kerneldb_to_parser.ml [new file with mode: 0644]

diff --git a/HACKING b/HACKING
index 26e5ffe..a9b1b71 100644 (file)
--- a/HACKING
+++ b/HACKING
@@ -34,6 +34,11 @@ extract/
    subdirectories here correspond to the different Linux distributions
    and methods of getting at their kernels.
 
+extract/codegen/
+
+ - Tools to turn the kernel database into generated code which parses
+   the kernel structures.
+
 General structure of lib/virt_mem.ml
 ------------------------------------
 
index 336a672..c045865 100644 (file)
@@ -157,5 +157,6 @@ AC_CONFIG_FILES([Makefile
        mem/Makefile
        po/Makefile
        extract/fedora-koji/Makefile
+       extract/codegen/Makefile
        ])
 AC_OUTPUT
index f19fc7c..06d6636 100644 (file)
@@ -5,3 +5,9 @@ and extracting the information we need from them.
 fedora-koji/
 
  - For recent Fedora kernels built at http://koji.fedoraproject.org/
+
+
+codegen/
+
+ - This contains tools which turn the kernels database (in ../kernels/)
+   into parsing code.
diff --git a/extract/codegen/Makefile.in b/extract/codegen/Makefile.in
new file mode 100644 (file)
index 0000000..4643f13
--- /dev/null
@@ -0,0 +1,46 @@
+# virt-mem
+# @configure_input@
+# Copyright (C) 2008 Red Hat Inc., Richard W.M. Jones
+#
+# This library is free software; 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; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+
+PACKAGE                = @PACKAGE_NAME@
+VERSION                = @PACKAGE_VERSION@
+
+INSTALL                = @INSTALL@
+MKDIR_P                = @MKDIR_P@
+bindir         = @bindir@
+
+OCAMLCPACKAGES = -package extlib,pcre
+
+OCAMLCFLAGS    = @OCAMLCFLAGS@
+OCAMLCLIBS     = -linkpkg
+
+OCAMLOPTFLAGS  = @OCAMLOPTFLAGS@
+OCAMLOPTPACKAGES = $(OCAMLCPACKAGES)
+OCAMLOPTLIBS   = -linkpkg
+
+TARGETS                = kerneldb-to-parser.opt
+
+OBJS           = kerneldb_to_parser.cmo
+XOBJS          = $(OBJS:.cmo=.cmx)
+
+all:   $(TARGETS)
+
+kerneldb-to-parser.opt: $(XOBJS)
+       ocamlfind ocamlopt \
+         $(OCAMLOPTFLAGS) $(OCAMLOPTPACKAGES) $(OCAMLOPTLIBS) $(XOBJS) -o $@
+
+include ../../Make.rules
\ No newline at end of file
diff --git a/extract/codegen/kerneldb_to_parser.ml b/extract/codegen/kerneldb_to_parser.ml
new file mode 100644 (file)
index 0000000..6b64786
--- /dev/null
@@ -0,0 +1,129 @@
+(* Memory info for virtual domains.
+   (C) Copyright 2008 Richard W.M. Jones, Red Hat Inc.
+   http://libvirt.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*)
+
+(* This program takes the kernel database (in kernels/ in toplevel
+   directory) and generates parsing code for the various structures
+   in the kernel that we are interested in.
+
+   The output programs -- *.ml, *.mli files of generated code -- go
+   into lib/ at the toplevel, eg. lib/kernel_task_struct.ml
+
+   The stuff at the top of this file determine what structures
+   and fields we try to parse.
+*)
+
+let what = [
+  "task_struct", (
+    "struct task_struct",
+    [ "state"; "prio"; "normal_prio"; "static_prio"; "tasks"; "comm"]
+  );
+]
+
+open ExtList
+open ExtString
+open Printf
+
+let (//) = Filename.concat
+
+let () =
+  let args = Array.to_list Sys.argv in
+
+  let kernelsdir, outputdir =
+    match args with
+    | [_;kd;od] -> kd,od
+    | _ ->
+       let arg0 = Filename.basename Sys.executable_name in
+       eprintf "%s - Turn kernels database into code modules.
+
+Usage:
+  %s <kernelsdir> <outputdir>
+
+Example (from toplevel of virt-mem source tree):
+  %s kernels/ lib/
+" arg0 arg0 arg0;
+       exit 2 in
+
+  (* Get the *.info files from the kernels database. *)
+  let infos = Sys.readdir kernelsdir in
+  let infos = Array.to_list infos in
+  let infos = List.filter (fun name -> String.ends_with name ".info") infos in
+  let infos = List.map ((//) kernelsdir) infos in
+
+  (* Regular expressions.  We really really should use ocaml-mikmatch ... *)
+  let re_oldformat = Pcre.regexp "^RPM: \\d+: \\(build \\d+\\) ([-\\w]+) ([\\w.]+) ([\\w.]+) \\(.*?\\) (\\w+)" in
+  let re_keyvalue = Pcre.regexp "^(\\w+): (.*)" in
+
+  (* Parse in the *.info files.  These have historically had a few different
+   * formats that we need to support.
+   *)
+  let infos = List.map (
+    fun filename ->
+      (* Get the basename (for getting the .data file later on). *)
+      let basename = Filename.chop_suffix filename ".info" in
+
+      let chan = open_in filename in
+      let line = input_line chan in
+
+      let name, version =
+       if Pcre.pmatch ~rex:re_oldformat line then (
+         (* If the file starts with "RPM: \d+: ..." then it's the original
+          * format.  Everything in one line.
+          *)
+         let subs = Pcre.exec ~rex:re_oldformat line in
+         let name = Pcre.get_substring subs 1 in
+         let version = Pcre.get_substring subs 2 in
+         let release = Pcre.get_substring subs 3 in
+         let arch = Pcre.get_substring subs 4 in
+         close_in chan;
+         name, sprintf "%s-%s.%s" version release arch
+       ) else (
+         (* New-style "key: value" entries, up to end of file or the first
+          * blank line.
+          *)
+         let name, version, release, arch =
+           ref "", ref "", ref "", ref "" in
+         let rec loop line =
+           try
+             let subs = Pcre.exec ~rex:re_keyvalue line in
+             let key = Pcre.get_substring subs 1 in
+             let value = Pcre.get_substring subs 2 in
+             if key = "Name" then name := value
+             else if key = "Version" then version := value
+             else if key = "Release" then release := value
+             else if key = "Architecture" then arch := value;
+             let line = input_line chan in
+             loop line
+           with
+             Not_found | End_of_file ->
+               close_in chan
+         in
+         loop line;
+         let name, version, release, arch =
+           !name, !version, !release, !arch in
+         if name = "" || version = "" || release = "" || arch = "" then
+           failwith (sprintf "%s: missing Name, Version, Release or Architecture key" filename);
+         name, sprintf "%s-%s.%s" version release arch
+       ) in
+
+      printf "%s -> %s, %s\n" basename name version;
+
+      (basename, name, version)
+  ) infos in
+
+  ()