module PP = Pahole_parser
module SC = Struct_classify
+let rec uniq ?(cmp = Pervasives.compare) = function
+ [] -> []
+ | [x] -> [x]
+ | x :: y :: xs when cmp x y = 0 ->
+ uniq (x :: xs)
+ | x :: y :: xs ->
+ x :: uniq (y :: xs)
+
+let sort_uniq ?cmp xs =
+ let xs = List.sort ?cmp xs in
+ let xs = uniq ?cmp xs in
+ xs
+
(* We don't care about locations when generating code, so it's
* useful to just have a single global _loc.
*)
Ast.ExTup (_loc,
List.fold_left (fun xs x -> Ast.ExCom (_loc, x, xs)) x xs)
+type code = Ast.str_item * Ast.sig_item
+
let ocaml_type_of_field_type = function
| PP.FInteger -> <:ctyp< int64 >>
| PP.FString _ -> <:ctyp< string >>
concat_str_items strs, concat_sig_items sigs
+let generate_offsets xs =
+ (* Only need to generate the offset_of_* functions for fields
+ * which are cross-referenced from another field. Which
+ * ones are those?
+ *)
+ let fields =
+ List.concat (
+ List.map (
+ fun (_, (_, all_fields)) ->
+ List.filter_map (
+ function
+ | (_,
+ PP.FListHeadPointer ((Some (struct_name, field_name)) as f)) ->
+ f
+ | _ ->
+ None
+ ) all_fields
+ ) xs
+ ) in
+
+ let fields = sort_uniq fields in
+
+ let strs =
+ List.map (
+ fun (struct_name, field_name) ->
+ let kernels, _ =
+ try List.assoc struct_name xs
+ with Not_found ->
+ failwith (
+ sprintf "generate_offsets: structure %s not found. This is probably a list_head-related bug."
+ struct_name
+ ) in
+ (* Find the offset of this field in each kernel version. *)
+ let offsets =
+ List.filter_map (
+ fun ({ PP.kernel_version = version },
+ { PP.struct_fields = fields }) ->
+ try
+ let field =
+ List.find (fun { PP.field_name = name } -> field_name = name)
+ fields in
+ let offset = field.PP.field_offset in
+ Some (version, offset)
+ with Not_found -> None
+ ) kernels in
+
+ if offsets = [] then
+ failwith (
+ sprintf "generate_offsets: field %s.%s not found in any kernel. This is probably a list_head-related bug."
+ struct_name field_name
+ );
+
+ (* Generate a map of kernel version to offset. *)
+ let map = List.fold_left (
+ fun map (version, offset) ->
+ <:expr< StringMap.add $str:version$ $`int:offset$ $map$ >>
+ ) <:expr< StringMap.empty >> offsets in
+
+ let code =
+ <:str_item<
+ let $lid:"offset_of_"^struct_name^"_"^field_name$ =
+ let map = $map$ in
+ fun kernel_version -> StringMap.find kernel_version map
+ >> in
+ code
+ ) fields in
+
+ let strs = concat_str_items strs in
+ let strs =
+ <:str_item<
+ module StringMap = Map.Make (String) ;;
+ $strs$
+ >> in
+
+ strs, <:sig_item< >>
+
let generate_parsers xs =
let strs =
List.map (
let palist =
List.map (
fun { SC.pa_name = pa_name } ->
- <:str_item< let $lid:pa_name$ bits = $str:pa_name$ >>
+ <:str_item<
+ let $lid:pa_name$ kernel_version bits = $str:pa_name$
+ >>
) palist in
concat_str_items palist
) xs in
sprintf "%s_%s = Int64.sub %s %dL"
sf.SC.sf_name field_name field_name offset
- | PP.FListHeadPointer (Some (other_struct_name, other_field_name)) ->
- let other_offset = 666 in
- sprintf "%s_%s = Int64.sub %s %dL"
- sf.SC.sf_name field_name field_name other_offset
-
+ | PP.FListHeadPointer (Some (other_struct_name,
+ other_field_name)) ->
+ (* A reference to a field in another structure. We don't
+ * know the offset until runtime, so we have to call
+ * offset_of_<struct>_<field> to find it.
+ *)
+ sprintf "%s_%s = (
+ let offset = offset_of_%s_%s kernel_version in
+ let offset = Int64.of_int offset in
+ Int64.sub %s offset
+ )"
+ sf.SC.sf_name field_name
+ other_struct_name other_field_name
+ field_name
| _ ->
sprintf "%s_%s = %s" sf.SC.sf_name field_name field_name
) sf.SC.sf_fields in
) palist;
) xs;
- strs, <:sig_item< >>, subs
+ (strs, <:sig_item< >>), subs
-let output_interf ~output_file types parsers =
- let sigs = concat_sig_items [ types; parsers ] in
+let output_interf ~output_file types offsets parsers =
+ let sigs = concat_sig_items [ types; offsets; parsers ] in
Printers.OCaml.print_interf ~output_file sigs
(* Finally generate the output files. *)
let re_subst = Pcre.regexp "^(.*)\"(\\w+_parser_\\d+)\"(.*)$"
-let output_implem ~output_file types parsers parser_subs =
+let output_implem ~output_file types offsets parsers parser_subs =
let new_output_file = output_file ^ ".new" in
- let strs = concat_str_items [ types; parsers ] in
+ let strs = concat_str_items [ types; offsets; parsers ] in
Printers.OCaml.print_implem ~output_file:new_output_file strs;
(* Substitute the parser bodies in the output file. *)
type inet6_ifaddr_content_fields_47 =
{ inet6_ifaddr_content_fields_47_prefix_len : int64
};;
+module StringMap = Map.Make(String);;
+let offset_of_net_device_dev_list'next =
+ let map =
+ StringMap.add "2.6.27-0.226.rc1.git5.fc10.ppc" 48
+ (StringMap.add "2.6.26.1-9.fc9.ppc64" 72
+ (StringMap.add "2.6.25.14-69.fc8.x86_64" 72
+ (StringMap.add "2.6.24-0.167.rc8.git4.fc9.ppc64" 72
+ (StringMap.add "2.6.22-0.23.rc7.git6.fc8.ppc" 48 StringMap.
+ empty))))
+ in fun kernel_version -> StringMap.find kernel_version map;;
let match_err = "failed to match kernel structure";;
let zero = 0;;
-let task_struct_parser_4 bits =
+let task_struct_parser_4 kernel_version bits =
bitmatch bits with
| { state : zero+32 : offset(0), littleendian;
prio : zero+32 : offset(192), littleendian;
{ task_struct_shape = shape; task_struct_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("task_struct", "task_struct_parser_4", match_err));;
-let task_struct_parser_5 bits =
+let task_struct_parser_5 kernel_version bits =
bitmatch bits with
| { state : zero+64 : offset(0), bigendian;
prio : zero+32 : offset(320), bigendian;
{ task_struct_shape = shape; task_struct_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("task_struct", "task_struct_parser_5", match_err));;
-let task_struct_parser_6 bits =
+let task_struct_parser_6 kernel_version bits =
bitmatch bits with
| { state : zero+64 : offset(0), littleendian;
prio : zero+32 : offset(320), littleendian;
{ task_struct_shape = shape; task_struct_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("task_struct", "task_struct_parser_6", match_err));;
-let task_struct_parser_7 bits =
+let task_struct_parser_7 kernel_version bits =
bitmatch bits with
| { state : zero+32 : offset(0), bigendian;
prio : zero+32 : offset(160), bigendian;
{ task_struct_shape = shape; task_struct_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("task_struct", "task_struct_parser_7", match_err));;
-let task_struct_parser_8 bits =
+let task_struct_parser_8 kernel_version bits =
bitmatch bits with
| { state : zero+64 : offset(0), bigendian;
prio : zero+32 : offset(224), bigendian;
{ task_struct_shape = shape; task_struct_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("task_struct", "task_struct_parser_8", match_err));;
-let task_struct_parser_9 bits =
+let task_struct_parser_9 kernel_version bits =
bitmatch bits with
| { state : zero+64 : offset(0), littleendian;
prio : zero+32 : offset(224), littleendian;
{ task_struct_shape = shape; task_struct_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("task_struct", "task_struct_parser_9", match_err));;
-let task_struct_parser_10 bits =
+let task_struct_parser_10 kernel_version bits =
bitmatch bits with
| { state : zero+64 : offset(0), bigendian;
prio : zero+32 : offset(256), bigendian;
{ task_struct_shape = shape; task_struct_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("task_struct", "task_struct_parser_10", match_err));;
-let task_struct_parser_11 bits =
+let task_struct_parser_11 kernel_version bits =
bitmatch bits with
| { state : zero+32 : offset(0), bigendian;
prio : zero+32 : offset(192), bigendian;
{ task_struct_shape = shape; task_struct_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("task_struct", "task_struct_parser_11", match_err));;
-let net_device_parser_15 bits =
+let net_device_parser_15 kernel_version bits =
bitmatch bits with
| { name : 128 : offset(0), string;
next : zero+32 : offset(384), littleendian;
{ net_device_shape = shape; net_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net_device", "net_device_parser_15", match_err));;
-let net_device_parser_16 bits =
+let net_device_parser_16 kernel_version bits =
bitmatch bits with
| { name : 128 : offset(0), string;
next : zero+64 : offset(576), bigendian;
{ net_device_shape = shape; net_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net_device", "net_device_parser_16", match_err));;
-let net_device_parser_17 bits =
+let net_device_parser_17 kernel_version bits =
bitmatch bits with
| { name : 128 : offset(0), string;
next : zero+64 : offset(576), littleendian;
{ net_device_shape = shape; net_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net_device", "net_device_parser_17", match_err));;
-let net_device_parser_18 bits =
+let net_device_parser_18 kernel_version bits =
bitmatch bits with
| { name : 128 : offset(0), string;
dev_list'next : zero+32 : offset(384), bigendian;
{ net_device_shape = shape; net_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net_device", "net_device_parser_18", match_err));;
-let net_device_parser_19 bits =
+let net_device_parser_19 kernel_version bits =
bitmatch bits with
| { name : 128 : offset(0), string;
dev_list'next : zero+64 : offset(576), bigendian;
{ net_device_shape = shape; net_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net_device", "net_device_parser_19", match_err));;
-let net_device_parser_20 bits =
+let net_device_parser_20 kernel_version bits =
bitmatch bits with
| { name : 128 : offset(0), string;
dev_list'next : zero+64 : offset(576), littleendian;
{ net_device_shape = shape; net_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net_device", "net_device_parser_20", match_err));;
-let net_device_parser_21 bits =
+let net_device_parser_21 kernel_version bits =
bitmatch bits with
| { name : 128 : offset(0), string;
dev_list'next : zero+32 : offset(384), bigendian;
{ net_device_shape = shape; net_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net_device", "net_device_parser_21", match_err));;
-let net_parser_24 bits =
+let net_parser_24 kernel_version bits =
bitmatch bits with
| { dev_base_head'next : zero+64 : offset(704), bigendian;
dev_base_head'prev : zero+64 : offset(768), bigendian } ->
let shape =
- { net_shape_fields_22_dev_base_head'next = Int64.sub dev_base_head'next 666L;
- net_shape_fields_22_dev_base_head'prev = Int64.sub dev_base_head'prev 666L } in
+ { net_shape_fields_22_dev_base_head'next = (
+ let offset = offset_of_net_device_dev_list'next kernel_version in
+ let offset = Int64.of_int offset in
+ Int64.sub dev_base_head'next offset
+ );
+ net_shape_fields_22_dev_base_head'prev = (
+ let offset = offset_of_net_device_dev_list'next kernel_version in
+ let offset = Int64.of_int offset in
+ Int64.sub dev_base_head'prev offset
+ ) } in
let content =
{ net_shape_fields_22_dev_base_head'next = dev_base_head'next;
net_shape_fields_22_dev_base_head'prev = dev_base_head'prev } in
{ net_shape = shape; net_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net", "net_parser_24", match_err));;
-let net_parser_25 bits =
+let net_parser_25 kernel_version bits =
bitmatch bits with
| { dev_base_head'next : zero+64 : offset(768), littleendian;
dev_base_head'prev : zero+64 : offset(832), littleendian } ->
let shape =
- { net_shape_fields_22_dev_base_head'next = Int64.sub dev_base_head'next 666L;
- net_shape_fields_22_dev_base_head'prev = Int64.sub dev_base_head'prev 666L } in
+ { net_shape_fields_22_dev_base_head'next = (
+ let offset = offset_of_net_device_dev_list'next kernel_version in
+ let offset = Int64.of_int offset in
+ Int64.sub dev_base_head'next offset
+ );
+ net_shape_fields_22_dev_base_head'prev = (
+ let offset = offset_of_net_device_dev_list'next kernel_version in
+ let offset = Int64.of_int offset in
+ Int64.sub dev_base_head'prev offset
+ ) } in
let content =
{ net_shape_fields_22_dev_base_head'next = dev_base_head'next;
net_shape_fields_22_dev_base_head'prev = dev_base_head'prev } in
{ net_shape = shape; net_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net", "net_parser_25", match_err));;
-let net_parser_26 bits =
+let net_parser_26 kernel_version bits =
bitmatch bits with
| { dev_base_head'next : zero+64 : offset(768), bigendian;
dev_base_head'prev : zero+64 : offset(832), bigendian } ->
let shape =
- { net_shape_fields_22_dev_base_head'next = Int64.sub dev_base_head'next 666L;
- net_shape_fields_22_dev_base_head'prev = Int64.sub dev_base_head'prev 666L } in
+ { net_shape_fields_22_dev_base_head'next = (
+ let offset = offset_of_net_device_dev_list'next kernel_version in
+ let offset = Int64.of_int offset in
+ Int64.sub dev_base_head'next offset
+ );
+ net_shape_fields_22_dev_base_head'prev = (
+ let offset = offset_of_net_device_dev_list'next kernel_version in
+ let offset = Int64.of_int offset in
+ Int64.sub dev_base_head'prev offset
+ ) } in
let content =
{ net_shape_fields_22_dev_base_head'next = dev_base_head'next;
net_shape_fields_22_dev_base_head'prev = dev_base_head'prev } in
{ net_shape = shape; net_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net", "net_parser_26", match_err));;
-let net_parser_27 bits =
+let net_parser_27 kernel_version bits =
bitmatch bits with
| { dev_base_head'next : zero+32 : offset(448), bigendian;
dev_base_head'prev : zero+32 : offset(480), bigendian } ->
let shape =
- { net_shape_fields_22_dev_base_head'next = Int64.sub dev_base_head'next 666L;
- net_shape_fields_22_dev_base_head'prev = Int64.sub dev_base_head'prev 666L } in
+ { net_shape_fields_22_dev_base_head'next = (
+ let offset = offset_of_net_device_dev_list'next kernel_version in
+ let offset = Int64.of_int offset in
+ Int64.sub dev_base_head'next offset
+ );
+ net_shape_fields_22_dev_base_head'prev = (
+ let offset = offset_of_net_device_dev_list'next kernel_version in
+ let offset = Int64.of_int offset in
+ Int64.sub dev_base_head'prev offset
+ ) } in
let content =
{ net_shape_fields_22_dev_base_head'next = dev_base_head'next;
net_shape_fields_22_dev_base_head'prev = dev_base_head'prev } in
{ net_shape = shape; net_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("net", "net_parser_27", match_err));;
-let in_device_parser_30 bits =
+let in_device_parser_30 kernel_version bits =
bitmatch bits with
| { ifa_list : zero+32 : offset(96), littleendian } ->
let shape =
{ in_device_shape = shape; in_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("in_device", "in_device_parser_30", match_err));;
-let in_device_parser_33 bits =
+let in_device_parser_33 kernel_version bits =
bitmatch bits with
| { ifa_list : zero+32 : offset(96), bigendian } ->
let shape =
{ in_device_shape = shape; in_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("in_device", "in_device_parser_33", match_err));;
-let in_device_parser_32 bits =
+let in_device_parser_32 kernel_version bits =
bitmatch bits with
| { ifa_list : zero+64 : offset(128), littleendian } ->
let shape =
{ in_device_shape = shape; in_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("in_device", "in_device_parser_32", match_err));;
-let in_device_parser_31 bits =
+let in_device_parser_31 kernel_version bits =
bitmatch bits with
| { ifa_list : zero+64 : offset(128), bigendian } ->
let shape =
{ in_device_shape = shape; in_device_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("in_device", "in_device_parser_31", match_err));;
-let inet6_dev_parser_36 bits =
+let inet6_dev_parser_36 kernel_version bits =
bitmatch bits with
| { addr_list : zero+32 : offset(32), littleendian } ->
let shape =
{ inet6_dev_shape = shape; inet6_dev_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("inet6_dev", "inet6_dev_parser_36", match_err));;
-let inet6_dev_parser_39 bits =
+let inet6_dev_parser_39 kernel_version bits =
bitmatch bits with
| { addr_list : zero+32 : offset(32), bigendian } ->
let shape =
{ inet6_dev_shape = shape; inet6_dev_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("inet6_dev", "inet6_dev_parser_39", match_err));;
-let inet6_dev_parser_38 bits =
+let inet6_dev_parser_38 kernel_version bits =
bitmatch bits with
| { addr_list : zero+64 : offset(64), littleendian } ->
let shape =
{ inet6_dev_shape = shape; inet6_dev_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("inet6_dev", "inet6_dev_parser_38", match_err));;
-let inet6_dev_parser_37 bits =
+let inet6_dev_parser_37 kernel_version bits =
bitmatch bits with
| { addr_list : zero+64 : offset(64), bigendian } ->
let shape =
{ inet6_dev_shape = shape; inet6_dev_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("inet6_dev", "inet6_dev_parser_37", match_err));;
-let in_ifaddr_parser_42 bits =
+let in_ifaddr_parser_42 kernel_version bits =
bitmatch bits with
| { ifa_next : zero+32 : offset(0), littleendian;
ifa_local : zero+32 : offset(128), littleendian;
{ in_ifaddr_shape = shape; in_ifaddr_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("in_ifaddr", "in_ifaddr_parser_42", match_err));;
-let in_ifaddr_parser_45 bits =
+let in_ifaddr_parser_45 kernel_version bits =
bitmatch bits with
| { ifa_next : zero+32 : offset(0), bigendian;
ifa_local : zero+32 : offset(128), bigendian;
{ in_ifaddr_shape = shape; in_ifaddr_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("in_ifaddr", "in_ifaddr_parser_45", match_err));;
-let in_ifaddr_parser_43 bits =
+let in_ifaddr_parser_43 kernel_version bits =
bitmatch bits with
| { ifa_next : zero+64 : offset(0), bigendian;
ifa_local : zero+32 : offset(256), bigendian;
{ in_ifaddr_shape = shape; in_ifaddr_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("in_ifaddr", "in_ifaddr_parser_43", match_err));;
-let in_ifaddr_parser_44 bits =
+let in_ifaddr_parser_44 kernel_version bits =
bitmatch bits with
| { ifa_next : zero+64 : offset(0), littleendian;
ifa_local : zero+32 : offset(256), littleendian;
{ in_ifaddr_shape = shape; in_ifaddr_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("in_ifaddr", "in_ifaddr_parser_44", match_err));;
-let inet6_ifaddr_parser_48 bits =
+let inet6_ifaddr_parser_48 kernel_version bits =
bitmatch bits with
| { prefix_len : zero+32 : offset(128), littleendian;
lst_next : zero+32 : offset(1024), littleendian } ->
{ inet6_ifaddr_shape = shape; inet6_ifaddr_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("inet6_ifaddr", "inet6_ifaddr_parser_48", match_err));;
-let inet6_ifaddr_parser_50 bits =
+let inet6_ifaddr_parser_50 kernel_version bits =
bitmatch bits with
| { prefix_len : zero+32 : offset(128), littleendian;
lst_next : zero+64 : offset(1856), littleendian } ->
{ inet6_ifaddr_shape = shape; inet6_ifaddr_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("inet6_ifaddr", "inet6_ifaddr_parser_50", match_err));;
-let inet6_ifaddr_parser_49 bits =
+let inet6_ifaddr_parser_49 kernel_version bits =
bitmatch bits with
| { prefix_len : zero+32 : offset(128), bigendian;
lst_next : zero+64 : offset(1472), bigendian } ->
{ inet6_ifaddr_shape = shape; inet6_ifaddr_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("inet6_ifaddr", "inet6_ifaddr_parser_49", match_err));;
-let inet6_ifaddr_parser_51 bits =
+let inet6_ifaddr_parser_51 kernel_version bits =
bitmatch bits with
| { prefix_len : zero+32 : offset(128), littleendian;
lst_next : zero+64 : offset(1472), littleendian } ->
{ inet6_ifaddr_shape = shape; inet6_ifaddr_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("inet6_ifaddr", "inet6_ifaddr_parser_51", match_err));;
-let inet6_ifaddr_parser_52 bits =
+let inet6_ifaddr_parser_52 kernel_version bits =
bitmatch bits with
| { prefix_len : zero+32 : offset(128), bigendian;
lst_next : zero+32 : offset(928), bigendian } ->
{ inet6_ifaddr_shape = shape; inet6_ifaddr_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("inet6_ifaddr", "inet6_ifaddr_parser_52", match_err));;
-let inet6_ifaddr_parser_53 bits =
+let inet6_ifaddr_parser_53 kernel_version bits =
bitmatch bits with
| { prefix_len : zero+32 : offset(128), littleendian;
lst_next : zero+64 : offset(1280), littleendian } ->
{ inet6_ifaddr_shape = shape; inet6_ifaddr_content = content }
| { _ } ->
raise (Virt_mem_types.ParseError ("inet6_ifaddr", "inet6_ifaddr_parser_53", match_err));;
-let inet6_ifaddr_parser_54 bits =
+let inet6_ifaddr_parser_54 kernel_version bits =
bitmatch bits with
| { prefix_len : zero+32 : offset(128), bigendian;
lst_next : zero+64 : offset(1280), bigendian } ->