(** 'pahole' output parser. *) (* 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. *) (** This parses the output of the pahole command, allowing us to extract the layout of kernel structures for particular kernel versions. Its primary input is the [*.info] and [*.data*] files found in the [kernels/] subdirectory (ie. the kerneldb). *) (** {2 Types} *) type pathname = string (** Path and filenames. *) type info = { kv_i : int; (** Each kernel is given a unique number. *) kernel_version : string; (** Kernel version that this matches. *) arch : string; (** Architecture, eg. "i686", "ppc64". *) basename : string; (** [basename.info] is the info file and [basename.data*] is the data file. *) } (** Kernel metainformation, extracted from the [*.info] file. *) type structure = { struct_name : string; (** Structure name. *) struct_total_size : int; (** Total size in bytes. *) struct_fields : field list; (** Fields in the structure. *) } (** A kernel structure, eg. [task_struct]. *) and field = { field_name : string; (** Field name. *) field_type : f_type; (** Field type. *) field_offset : int; (** Offset within the structure. *) field_size : int; (** Size of the field (bytes). *) } (** A kernel structure field. Note that nested fields are flattened with single quotes (') between elements, so you get names like [tasks'next]. *) and f_type = | FStructPointer of string (** A pointer to a named struct. *) | FVoidPointer (** A [void*] pointer. *) | FAnonListHeadPointer (** A pointer to an unknown [list_head]. *) | FListHeadPointer of (string * string) option (** A pointer to a [list_head]. If the value is not [None] then this relates to another named struct/field, else it relates to this struct/field. *) | FInteger (** An integer. *) | FString of int (** A char array of given width. *) (** Type of a kernel field. *) val string_of_info : info -> string val string_of_structure : structure -> string val string_of_field : field -> string val string_of_f_type : f_type -> string (** Printing functions. *) (** {2 List kernels in kerneldb} *) val list_kernels : pathname -> info list (** Return a list of all the kernels in the kerneldb at [path]. *) (** {2 Load kernel structures} *) val load_structures : info -> string list -> (string * structure) list (** [load_structures info names] loads the named kernel structures from a particular kernel. The returned list is not necessarily in the same order, or the same length, as the [names] list. Check the first field in each pair for the structure name. Structures which don't actually occur in the given kernel are not loaded and not present in the final list. The fields list in {!structure} is always sorted by field offset. *) (** {2 Transpose and check field types} After we've used {!load_structures} for each kernel, we end up with a list of kernels, and within that a list of structures supported by the kernel. What we really want is to see how each structure changes over time, and also to check if field types have changed between versions (which we currently disallow). The {!transpose} operation transposes the original list of kernels to a list of structures. The {!get_fields} operation gets a complete list of fields and their types, and checks that the types haven't changed over kernel versions. (Note that particular fields can be missing from some kernel version, but that is OK). *) val transpose : string list -> (info * (string * structure) list) list -> (string * (info * structure) list) list (** Transpose list of kernels to list of structures. The result shows, for each structure, how it changed over kernel versions. The first parameter is the list of structure names of interest, and should be the same as was passed to {!load_structures}. *) val get_fields : (info * structure) list -> (string * (f_type * bool)) list (** This gets a complete list of fields which have appeared in any kernel version. The return list contains [(field_name, (field_type, always_present))] where [always_present] is a boolean flag which is true if the field is present in every kernel version we examined. Fields must not change type between kernel versions - if so this function prints an error and exits. (We may support fields which change type in future, but we don't right now). "Type" is quite widely defined here, see {!f_type}, and so certain changes such as between sizes of ints are allowed, but you can't have a field which once was a pointer and then became a string or anything like that. Note that a field may not be present in particular kernel versions, but if it appears at all in any version, then it will be in the result list. *)