type pathname = string
type info = {
+ kv_i : int;
kernel_version : string;
arch : string;
basename : string;
and f_type =
| FStructPointer of string
| FVoidPointer
- | FListHeadPointer
+ | FAnonListHeadPointer
+ | FListHeadPointer of (string * string) option
| FInteger
| FString of int
let string_of_info i =
- sprintf "%s: %s %s" i.basename i.kernel_version i.arch
+ sprintf "%s: %s (%d) %s" i.basename i.kernel_version i.kv_i i.arch
let rec string_of_structure s =
let fields = List.map string_of_field s.struct_fields in
and string_of_field f =
sprintf "%s %s; /* offset = %d, size = %d */"
- f.field_name (string_of_f_type f.field_type)
+ (string_of_f_type f.field_type) f.field_name
f.field_offset f.field_size
and string_of_f_type = function
- | FStructPointer struct_name -> sprintf "struct %s*" struct_name
+ | FStructPointer struct_name -> sprintf "struct %s *" struct_name
| FVoidPointer -> "void *"
- | FListHeadPointer -> "struct list_head *"
+ | FAnonListHeadPointer -> "struct list_head *"
+ | FListHeadPointer None ->
+ sprintf "struct /* self */ list_head *"
+ | FListHeadPointer (Some (struct_name, field_name)) ->
+ sprintf "struct /* to %s.%s */ list_head *" struct_name field_name
| FInteger -> "int"
| FString width -> sprintf "char[%d]" width
(* Parse in the *.info files. These have historically had a few different
* formats that we need to support.
*)
- let infos = List.map (
- fun filename ->
+ let infos = List.mapi (
+ fun i filename ->
(* Get the basename (for getting the .data file later on). *)
let basename = Filename.chop_suffix filename ".info" in
(*printf "%s -> %s %s\n%!" basename version arch;*)
- { basename = basename; arch = arch;
+ { kv_i = i;
+ basename = basename; arch = arch;
kernel_version = version }
) infos in
infos
if struct_name <> "list_head" then
FStructPointer struct_name
else
- FListHeadPointer in
+ FAnonListHeadPointer in
let field =
{ field_name = name; field_type = field_type;
field_offset = offset; field_size = size } in
) fields in
List.fold_left max 0 fields in
- Some { struct_name = struct_name;
- struct_fields = fields;
- struct_total_size = total_size }
+ (* Sort the structure fields by field offset. They are
+ * probably already in this order, but just make sure.
+ *)
+ let cmp { field_offset = o1 } { field_offset = o2 } = compare o1 o2 in
+ let fields = List.sort ~cmp fields in
+
+ Some (
+ struct_name,
+ { struct_name = struct_name;
+ struct_fields = fields;
+ struct_total_size = total_size }
+ )
) struct_names in
structures
+
+(* XXX This loop is O(n^3), luckily n is small! *)
+let transpose good_struct_names kernels =
+ List.map (
+ fun struct_name ->
+ let kernels =
+ List.filter_map (
+ fun (info, structures) ->
+ try
+ let s = List.assoc struct_name structures in
+ Some (info, s)
+ with
+ Not_found -> None
+ ) kernels in
+
+ (* Sort the kernels, which makes the generated output more stable
+ * and makes patches more useful.
+ *)
+ let kernels = List.sort kernels in
+
+ struct_name, kernels
+ ) good_struct_names
+
+let get_fields structures =
+ (* Use a hash table to accumulate the fields as we find them.
+ * The key is the field name. The value is the field type and the
+ * kernel version where first seen (for error reporting). If
+ * we meet the field again, we check its type hasn't changed.
+ * Finally, we can use the hash to pull out all field names and
+ * types.
+ *)
+ let h = Hashtbl.create 13 in
+
+ (* A hash to check for fields which aren't always available by
+ * counting the number of times we see each field.
+ *)
+ let count, get =
+ let h = Hashtbl.create 13 in
+ let count field_name =
+ let r =
+ try Hashtbl.find h field_name
+ with Not_found -> let r = ref 0 in Hashtbl.add h field_name r; r in
+ incr r
+ in
+ let get field_name = try !(Hashtbl.find h field_name) with Not_found -> 0 in
+ count, get
+ in
+
+ List.iter (
+ fun ({kernel_version = version},
+ {struct_name = struct_name; struct_fields = fields}) ->
+ List.iter (
+ fun {field_name = name; field_type = typ} ->
+ count name;
+ try
+ let (field_type, version_first_seen) = Hashtbl.find h name in
+ if typ <> field_type then (
+ eprintf "Error: %s.%s: field changed type between kernel versions.\n"
+ struct_name name;
+ eprintf "In version %s it had type %s.\n"
+ version_first_seen (string_of_f_type field_type);
+ eprintf "In version %s it had type %s.\n"
+ version (string_of_f_type typ);
+ eprintf "The code cannot handle fields which change type like this.\n";
+ eprintf "See extract/codegen/pahole_parser.mli for more details.\n";
+ exit 1
+ )
+ with Not_found ->
+ Hashtbl.add h name (typ, version)
+ ) fields
+ ) structures;
+
+ let nr_kernels = List.length structures in
+
+ let fields =
+ Hashtbl.fold (
+ fun name (typ, _) fields ->
+ let always_available = get name = nr_kernels in
+ (name, (typ, always_available)) :: fields
+ ) h [] in
+
+ List.sort fields