New kernel database parser *NOT WORKING YET*.
[virt-mem.git] / extract / codegen / struct_classify.ml
diff --git a/extract/codegen/struct_classify.ml b/extract/codegen/struct_classify.ml
new file mode 100644 (file)
index 0000000..506d783
--- /dev/null
@@ -0,0 +1,185 @@
+(* Memory info command 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.
+ *)
+
+open ExtList
+open ExtString
+
+open Printf
+
+module PP = Pahole_parser
+
+type f_class = ShapeField | ContentField
+
+let classify_field names = function
+  | (PP.FStructPointer struct_name | PP.FListHeadPointer struct_name)
+      when List.mem struct_name names -> ShapeField
+    (* .. anything else is a content field: *)
+  | PP.FStructPointer _
+  | PP.FListHeadPointer _
+  | PP.FVoidPointer
+  | PP.FAnonListHeadPointer
+  | PP.FInteger
+  | PP.FString _ -> ContentField
+
+type shape_field_struct = {
+  sf_i : int;
+  sf_name : string;
+  sf_fields : PP.field list;
+}
+
+and content_field_struct = {
+  cf_i : int;
+  cf_name : string;
+  cf_fields : PP.field list;
+}
+
+and parser_ = {
+  pa_i : int;
+  pa_name : string;
+  pa_endian : Bitstring.endian;
+  pa_fields : Pahole_parser.field list;
+  pa_shape_field_struct : shape_field_struct;
+  pa_content_field_struct : content_field_struct;
+}
+
+let endian_of_architecture arch =
+  if String.starts_with arch "i386" ||
+    String.starts_with arch "i486" ||
+    String.starts_with arch "i586" ||
+    String.starts_with arch "i686" ||
+    String.starts_with arch "x86_64" ||
+    String.starts_with arch "x86-64" then
+      Bitstring.LittleEndian
+  else if String.starts_with arch "ia64" then
+    Bitstring.LittleEndian (* XXX usually? *)
+  else if String.starts_with arch "ppc" then
+    Bitstring.BigEndian
+  else if String.starts_with arch "sparc" then
+    Bitstring.BigEndian
+  else
+    failwith (sprintf "endian_of_architecture: cannot parse %S" arch)
+
+let unique =
+  let i = ref 0 in
+  fun () ->
+    incr i; !i
+
+(* Minimization of shape fields & content fields. *)
+
+let cmp { PP.field_name = n1 } { PP.field_name = n2 } = compare n1 n2
+
+let hash_values h = Hashtbl.fold (fun _ v vs -> v :: vs) h []
+
+let minimize_shape_field_structs struct_name names kernels =
+  let h = Hashtbl.create 13 in
+  let rh = Hashtbl.create 13 in
+
+  let only_shape_fields =
+    List.filter (
+      fun { PP.field_type = typ } ->
+       classify_field names typ = ShapeField
+    )
+  in
+
+  let name_of i = sprintf "%s_shape_fields_%d" struct_name i in
+
+  List.iter (
+    fun ({ PP.kernel_version = version },
+        { PP.struct_fields = fields; struct_name = name_check }) ->
+      assert (struct_name = name_check);
+      let fields = List.sort ~cmp (only_shape_fields fields) in
+      let key = List.map (fun { PP.field_name = name } -> name) fields in
+      let sf =
+       try Hashtbl.find h key
+       with Not_found ->
+         let i = unique () in
+         let sf = { sf_i = i; sf_name = name_of i; sf_fields = fields } in
+         Hashtbl.add h key sf;
+         sf in
+      Hashtbl.add rh version sf
+  ) kernels;
+
+  let sfs = hash_values h in
+  sfs, rh
+
+let minimize_content_field_structs struct_name names kernels =
+  let h = Hashtbl.create 13 in
+  let rh = Hashtbl.create 13 in
+
+  let only_content_fields =
+    List.filter (
+      fun { PP.field_type = typ } ->
+       classify_field names typ = ContentField
+    )
+  in
+
+  let name_of i = sprintf "%s_content_fields_%d" struct_name i in
+
+  List.iter (
+    fun ({ PP.kernel_version = version },
+        { PP.struct_fields = fields; struct_name = name_check }) ->
+      assert (struct_name = name_check);
+      let fields = List.sort ~cmp (only_content_fields fields) in
+      let key = List.map (fun { PP.field_name = name } -> name) fields in
+      let cf =
+       try Hashtbl.find h key
+       with Not_found ->
+         let i = unique () in
+         let cf = { cf_i = i; cf_name = name_of i; cf_fields = fields } in
+         Hashtbl.add h key cf;
+         cf in
+      Hashtbl.add rh version cf
+  ) kernels;
+
+  let cfs = hash_values h in
+  cfs, rh
+
+let minimize_parsers struct_name kernels sfhash cfhash =
+  let h = Hashtbl.create 13 in
+  let rh = Hashtbl.create 13 in
+
+  let name_of i = sprintf "%s_parser_%d" struct_name i in
+
+  List.iter (
+    fun ({ PP.kernel_version = version; arch = arch },
+        { PP.struct_fields = fields; struct_name = name_check }) ->
+      assert (struct_name = name_check);
+      let endian = endian_of_architecture arch in
+      let key = endian, fields in
+      let pa =
+       try Hashtbl.find h key
+       with Not_found ->
+         let i = unique () in
+         let sf =
+           try Hashtbl.find sfhash version
+           with Not_found -> assert false in
+         let cf =
+           try Hashtbl.find cfhash version
+           with Not_found -> assert false in
+         let pa = { pa_i = i; pa_name = name_of i; pa_fields = fields;
+                    pa_endian = endian;
+                    pa_shape_field_struct = sf;
+                    pa_content_field_struct = cf } in
+         Hashtbl.add h key pa;
+         pa in
+      Hashtbl.add rh version pa
+  ) kernels;
+
+  let pas = hash_values h in
+  pas, rh