1 (* Memory info command for virtual domains.
2 (C) Copyright 2008 Richard W.M. Jones, Red Hat Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 module PP = Pahole_parser
29 module SC = Struct_classify
31 (* We don't care about locations when generating code, so it's
32 * useful to just have a single global _loc.
36 (* Some handy camlp4 construction functions which do some
37 * things that ought to be easy/obvious but aren't.
39 * 'concat_str_items' concatenates a list of str_item together into
42 * 'concat_record_fields' concatenates a list of records fields into
43 * a record. The list must have at least one element.
45 * 'build_record' builds a record out of record fields.
47 * 'build_tuple_from_exprs' builds an arbitrary length tuple from
48 * a list of expressions of length >= 2.
50 * Thanks to bluestorm on #ocaml for getting these working.
52 let concat_str_items items =
54 | [] -> <:str_item< >>
56 List.fold_left (fun xs x -> <:str_item< $xs$ $x$ >>) x xs
58 let concat_sig_items items =
60 | [] -> <:sig_item< >>
62 List.fold_left (fun xs x -> <:sig_item< $xs$ $x$ >>) x xs
64 let concat_record_fields fields =
68 List.fold_left (fun fs f -> <:ctyp< $fs$ ; $f$ >>) f fs
70 let concat_record_bindings rbs =
74 List.fold_left (fun rbs rb -> <:rec_binding< $rbs$ ; $rb$ >>) rb rbs
76 let build_record rbs =
77 Ast.ExRec (_loc, rbs, Ast.ExNil _loc)
79 let build_tuple_from_exprs exprs =
81 | [] | [_] -> assert false
84 List.fold_left (fun xs x -> Ast.ExCom (_loc, x, xs)) x xs)
86 let ocaml_type_of_field_type = function
87 | PP.FInteger -> <:ctyp< int64 >>
88 | PP.FString _ -> <:ctyp< string >>
89 | PP.FStructPointer _ | PP.FVoidPointer
90 | PP.FAnonListHeadPointer | PP.FListHeadPointer _ ->
91 <:ctyp< Virt_mem_mmap.addr >>
93 let generate_types xs =
95 fun (struct_name, sflist, cflist) ->
96 let sflist = List.map (
97 fun { SC.sf_name = sf_name; sf_fields = fields } ->
98 if fields <> [] then (
99 let fields = List.map (
100 fun { PP.field_name = name; PP.field_type = t } ->
101 let t = ocaml_type_of_field_type t in
102 <:ctyp< $lid:sf_name^"_"^name$ : $t$ >>
104 let fields = concat_record_fields fields in
107 type $lid:sf_name$ = { $fields$ }
110 <:str_item< type $lid:sf_name$ = unit >>
112 let sflist = concat_str_items sflist in
114 let cflist = List.map (
115 fun { SC.cf_name = cf_name; cf_fields = fields } ->
116 if fields <> [] then (
117 let fields = List.map (
118 fun { PP.field_name = name; PP.field_type = t } ->
119 let t = ocaml_type_of_field_type t in
120 <:ctyp< $lid:cf_name^"_"^name$ : $t$ >>
122 let fields = concat_record_fields fields in
125 type $lid:cf_name$ = { $fields$ }
128 <:str_item< type $lid:cf_name$ = unit >>
130 let cflist = concat_str_items cflist in
133 type ('a, 'b) $lid:struct_name$ = {
134 $lid:struct_name^"_shape"$ : 'a;
135 $lid:struct_name^"_content"$ : 'b;
144 fun (struct_name, _, _) ->
146 type ('a, 'b) $lid:struct_name$
150 concat_str_items strs, concat_sig_items sigs
152 let generate_parsers xs =
155 fun (struct_name, palist) ->
158 fun { SC.pa_name = pa_name } ->
159 <:str_item< let $lid:pa_name$ bits = $str:pa_name$ >>
161 concat_str_items palist
164 let strs = concat_str_items strs in
167 let match_err = "failed to match kernel structure" ;;
172 (* The shared parser functions.
174 * We could include bitmatch statements directly in here, but
175 * what happens is that the macros get expanded here, resulting
176 * in (even more) unreadable generated code. So instead just
177 * do a textual substitution later by post-processing the
178 * generated files. Not type-safe, but we can't have
181 let subs = Hashtbl.create 13 in
183 fun (struct_name, palist) ->
185 fun ({ SC.pa_name = pa_name;
186 pa_endian = endian; pa_structure = structure;
187 pa_shape_field_struct = sf;
188 pa_content_field_struct = cf }) ->
189 (* Generate the code to match this structure. *)
192 | Bitstring.LittleEndian -> "littleendian"
193 | Bitstring.BigEndian -> "bigendian"
194 | _ -> assert false in
196 String.concat ";\n " (
199 | { PP.field_name = field_name;
200 field_type = PP.FInteger;
201 field_offset = offset;
202 field_size = size } ->
203 (* 'zero+' is a hack to force the type to int64. *)
204 sprintf "%s : zero+%d : offset(%d), %s"
205 field_name (size*8) (offset*8) endian
207 | { PP.field_name = field_name;
208 field_type = (PP.FStructPointer _
210 | PP.FAnonListHeadPointer
211 | PP.FListHeadPointer _);
212 field_offset = offset;
213 field_size = size } ->
214 sprintf "%s : zero+%d : offset(%d), %s"
215 field_name (size*8) (offset*8) endian
217 | { PP.field_name = field_name;
218 field_type = PP.FString width;
219 field_offset = offset;
220 field_size = size } ->
221 sprintf "%s : %d : offset(%d), string"
222 field_name (width*8) (offset*8)
223 ) structure.PP.struct_fields
226 let shape_assignments =
228 fun { PP.field_name = field_name;
229 field_type = field_type;
230 field_offset = offset } ->
232 match field_type with
233 | PP.FListHeadPointer None ->
234 sprintf "%s_%s = Int64.sub %s %dL"
235 sf.SC.sf_name field_name field_name offset
237 | PP.FListHeadPointer (Some (other_struct_name, other_field_name)) ->
238 let other_offset = 666 in
239 sprintf "%s_%s = Int64.sub %s %dL"
240 sf.SC.sf_name field_name field_name other_offset
243 sprintf "%s_%s = %s" sf.SC.sf_name field_name field_name
246 let shape_assignments =
247 String.concat ";\n " shape_assignments in
249 let content_assignments =
251 fun { PP.field_name = field_name } ->
252 sprintf "%s_%s = %s" sf.SC.sf_name field_name field_name
255 let content_assignments =
256 String.concat ";\n " content_assignments in
266 { %s_shape = shape; %s_content = content }
268 raise (Virt_mem_types.ParseError (%S, %S, match_err))"
269 patterns shape_assignments content_assignments
270 struct_name struct_name
271 struct_name pa_name in
273 Hashtbl.add subs pa_name code
277 strs, <:sig_item< >>, subs
279 let output_interf ~output_file types parsers =
280 let sigs = concat_sig_items [ types; parsers ] in
281 Printers.OCaml.print_interf ~output_file sigs
283 (* Finally generate the output files. *)
284 let re_subst = Pcre.regexp "^(.*)\"(\\w+_parser_\\d+)\"(.*)$"
286 let output_implem ~output_file types parsers parser_subs =
287 let new_output_file = output_file ^ ".new" in
289 let strs = concat_str_items [ types; parsers ] in
290 Printers.OCaml.print_implem ~output_file:new_output_file strs;
292 (* Substitute the parser bodies in the output file. *)
293 let ichan = open_in new_output_file in
294 let ochan = open_out output_file in
296 output_string ochan "\
297 (* WARNING: This file and the corresponding mli (interface) are
298 * automatically generated by the extract/codegen/ program.
300 * Any edits you make to this file will be lost.
302 * To update this file from the latest kernel database, it is recommended
303 * that you do 'make update-kernel-structs'.
307 let line = input_line ichan in
309 if Pcre.pmatch ~rex:re_subst line then (
310 let subs = Pcre.exec ~rex:re_subst line in
311 let start = Pcre.get_substring subs 1 in
312 let template = Pcre.get_substring subs 2 in
313 let rest = Pcre.get_substring subs 3 in
315 try Hashtbl.find parser_subs template
316 with Not_found -> assert false in
319 output_string ochan line; output_char ochan '\n';
322 (try loop () with End_of_file -> ());
327 Unix.unlink new_output_file