From c4206b0394401252481d028c25b0b877edce2128 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 11 Jun 2008 15:04:05 +0000 Subject: [PATCH] Committing NON-WORKING cil tools directory. This code all needs to be reworked for when we have reusable bitmatch structures. --- cil-tools/Makefile.in | 24 ++++- cil-tools/bitmatch-import-prefix.h | 7 ++ cil-tools/bitmatch_import_c.ml | 198 ++++++++++++++++++++++++++++++++++++- cil-tools/ext3.c | 2 +- cil-tools/task_struct.c | 25 +++++ 5 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 cil-tools/task_struct.c diff --git a/cil-tools/Makefile.in b/cil-tools/Makefile.in index c66dd21..4acf391 100644 --- a/cil-tools/Makefile.in +++ b/cil-tools/Makefile.in @@ -44,12 +44,32 @@ bitmatch-import-c.opt: bitmatch_import_c.cmx test: -examples: +# Examples. + +#DEBUG = +DEBUG = --debug +LINUX_HEADERS = linux-2.6.25.4-headers +LINUX_INCLUDES = -I $(LINUX_HEADERS) + +examples: ext3.ml task_struct.ml + +ext3.ml: ext3.c bitmatch-import-c + cd $(LINUX_HEADERS) && ln -sf asm-x86 asm + rm -f $@.new + ./bitmatch-import-c $(DEBUG) $(LINUX_INCLUDES) $< > $@.new + mv $@.new $@ + +task_struct.ml: task_struct.c bitmatch-import-c + cd $(LINUX_HEADERS) && ln -sf asm-x86 asm + rm -f $@.new + ./bitmatch-import-c $(DEBUG) $(LINUX_INCLUDES) $< > $@.new + mv $@.new $@ # Clean. clean: rm -f core *~ *.cmi *.cmo *.cmx *.cma *.cmxa *.a *.o + rm -f bitmatch-import-c bitmatch-import-c.opt distclean: clean @@ -68,7 +88,7 @@ install: depend: .depend -.depend: $(wildcard *.ml) $(wildcard *.mli) +.depend: bitmatch_import_c.ml rm -f .depend $(OCAMLFIND) ocamldep $(OCAMLCPACKAGES) $^ > $@ diff --git a/cil-tools/bitmatch-import-prefix.h b/cil-tools/bitmatch-import-prefix.h index d7f769a..a3ed5ff 100644 --- a/cil-tools/bitmatch-import-prefix.h +++ b/cil-tools/bitmatch-import-prefix.h @@ -2,6 +2,13 @@ * and provides some macros that we need for CIL. */ +/* This is needed for older versions of CIL which didn't + * support this C99 type. + */ +#ifndef _Bool +#define _Bool unsigned +#endif + #define BITMATCH_IMPORT(name) __bitmatch_import_##name #define BITMATCH_CONSTANT_STRING(name,val) \ char *__bitmatch_constant_##name = val diff --git a/cil-tools/bitmatch_import_c.ml b/cil-tools/bitmatch_import_c.ml index 7587fc4..c61f751 100644 --- a/cil-tools/bitmatch_import_c.ml +++ b/cil-tools/bitmatch_import_c.ml @@ -21,6 +21,7 @@ open Printf open ExtList open ExtString + open Cil let () = @@ -31,14 +32,24 @@ let () = printf "bitmatch-import-c %s" Bitmatch.version; exit 1 in + let cpp_args = ref [] in + let cpp_arg2 name value = + cpp_args := (name ^ value) :: !cpp_args + in let argspec = Arg.align [ "--debug", Arg.Set debug, " Debug messages"; - "-save-temps", Arg.Set save_temps, - " Save temporary files"; "--version", Arg.Unit version, " Display version and exit"; + "-save-temps", Arg.Set save_temps, + " Save temporary files"; + "-I", Arg.String (cpp_arg2 "-I"), + "dir Specify extra include directory for cpp"; + "-D", Arg.String (cpp_arg2 "-D"), + "name=value Define value in cpp"; + "-U", Arg.String (cpp_arg2 "-U"), + "name Undefine value in cpp"; ] in let input_file = ref None in @@ -67,6 +78,7 @@ OPTIONS" in | None -> eprintf "bitmatch-import-c: no input file specified\n"; exit 1 in + let cpp_args = List.rev !cpp_args in (* Grab the file and pass it to the preprocessor, and then read the * C code into memory using CIL. @@ -85,7 +97,8 @@ OPTIONS" in ) in let cmd = - sprintf "cpp -include bitmatch-import-prefix.h %s > %s" + sprintf "cpp %s -include bitmatch-import-prefix.h %s > %s" + (String.concat " " (List.map Filename.quote cpp_args)) (Filename.quote input_file) (Filename.quote tmp) in if debug then prerr_endline cmd; if Sys.command cmd <> 0 then ( @@ -148,3 +161,182 @@ OPTIONS" in ) structs; ); + (* Output constants. *) + List.iter ( + fun (vname, vinit, loc) -> + printf "let %s = 0x%LX\n" vname vinit + ) constants; + + (* Output structures. *) + List.iter ( + fun (tname, ttype, loc) -> + (* Uncomment the next line if you want to really print the + * complete CIL structure of the type (for debugging etc.). + * The ASTs printed here are usually quite large. + *) + (*Errormsg.log "%a: %s %a\n" d_loc loc tname d_plaintype ttype;*) + + (* Match on the type of this structure, and from it generate + * a single parsing function. + *) + match ttype with + (* struct or union *) + | TComp ({ cdefined = true; cname = cname }, _) -> + printf "let %s_of_bitstring bits =\n" tname; + printf " bitmatch bits with\n"; + printf " | {\n"; + (*output_struct [] NoOffset None ttype;*) + printf " } ->\n"; + printf " Some (...)\n"; + printf " | { _ } -> None\n\n" + + (* An undefined struct or union -- means one which was only ever + * defined with 'struct foo;'. This is an error. + *) + | TComp ({ cdefined = false; cname = cname }, _) -> + Errormsg.error + "%a: struct or union has no definition: %s" d_loc loc cname + + (* Types which are not allowed, eg. void, int, arrays. *) + | TVoid _ | TInt _ | TFloat _ | TPtr _ | TArray _ | TFun _ + | TNamed _ | TBuiltin_va_list _ -> + Errormsg.error + "%a: not a struct or union: %a" d_loc loc d_type ttype + + (* Types which we might implement in the future. + * For enum we should probably split out enums separately + * from structs above, since enums are more like constants. + *) + | TEnum ({ ename = ename }, _) -> + Errormsg.unimp "%a: %a" d_loc loc d_type ttype +(* + let rec to_fields names offset endian = function + (* Some types contain attributes to indicate their + * endianness. See many examples from . + *) + | (TNamed ({ tname = tname; + ttype = TNamed (_, attrs) }, + _) as t) + when hasAttribute "bitwise" attrs -> + let endian = + if String.starts_with tname "__le" then + Some Bitmatch.LittleEndian + else if String.starts_with tname "__be" then + Some Bitmatch.BigEndian + else ( + Errormsg.warn "%a: unknown bitwise attribute typename: %s\n" + d_loc loc tname; + endian + ) in + to_fields names offset endian (unrollType t) + + (* See into named types. *) + | (TNamed _ as t) -> + to_fields names offset endian (unrollType t) + + (* struct or union *) + | TComp ({ cdefined = true; cfields = cfields }, _) -> + let cfields = + List.map ( + fun ({ fname = fname; ftype = ftype } as finfo) -> + let offset = Field (finfo, offset) in + let names = fname :: names in + to_fields names offset endian ftype + ) cfields in + List.flatten cfields + + (* int array with constant length *) + | TArray (basetype, (Some _ as len), _) + when isIntegralType basetype -> + let len = lenOfArray len in + let bitsoffset, totalwidth = bitsOffset ttype offset in + let bitswidth = totalwidth / len (* of the element *) in + (*if debug then ( + let name = String.concat "." (List.rev names) in + Errormsg.log "%s: int array: %d, %d, len %d\n" + name bitsoffset bitswidth len + );*) + let basetype = unrollType basetype in + let ikind = + match basetype with + | TInt (ikind, _) -> ikind + | t -> + Errormsg.unimp "%a: unhandled type: %a" d_loc loc d_type t; + IInt in + let field = + to_int_field "" bitsoffset bitswidth ikind endian in + let fname = String.concat "_" (List.rev names) in + let byteoffset = bitsoffset lsr 3 in + let bytetotalwidth = totalwidth lsr 3 in + printf "--> array %s: byteoffset=%d bytetotalwidth=%d len=%d\n" + fname byteoffset bytetotalwidth len (* field *); + [] + + (* basic integer type *) + | TInt (ikind, _) -> + let bitsoffset, bitswidth = bitsOffset ttype offset in + (*if debug then ( + let name = String.concat "." (List.rev names) in + Errormsg.log "%s: int: %d, %d\n" name bitsoffset bitswidth + );*) + let fname = String.concat "_" (List.rev names) in + let field = + to_int_field fname bitsoffset bitswidth ikind endian in + [field] + + (* a pointer - in this mapping we assume this is an address + * (endianness and wordsize come from function parameters), + * in other words we DON'T try to follow pointers, we just + * note that they are there. + *) + | TPtr _ -> + let bitsoffset, bitswidth = bitsOffset ttype offset in + let fname = String.concat "_" (List.rev names) in + printf "--> pointer %s: bitsoffset=%d bitswidth=%d\n" + fname bitsoffset bitswidth; + [] + + | t -> + Errormsg.unimp "to_fields: %a: unhandled type: %a" + d_loc loc d_type t; + [] + + and to_int_field fname bitsoffset bitswidth ikind endian = + let byteoffset = bitsoffset lsr 3 in + let bytewidth = bitswidth lsr 3 in + let signed = isSigned ikind in + + if bitsoffset land 7 = 0 && bitswidth land 7 = 0 then ( + (* Not a bitfield. *) + match bitswidth with + | 8 -> + printf "--> byte %s: byteoffset=%d bytewidth=%d signed=%b\n" + fname byteoffset bytewidth signed + | 16 -> + printf "--> short %s: byteoffset=%d bytewidth=%d signed=%b endian=%s\n" + fname byteoffset bytewidth signed (Option.map_default Bitmatch.string_of_endian "None" endian) + | 32 -> + printf "--> int %s: byteoffset=%d bytewidth=%d signed=%b endian=%s\n" + fname byteoffset bytewidth signed (Option.map_default Bitmatch.string_of_endian "None" endian) + | 64 -> + printf "--> long %s: byteoffset=%d bytewidth=%d signed=%b endian=%s\n" + fname byteoffset bytewidth signed (Option.map_default Bitmatch.string_of_endian "None" endian) + | _ -> + Errormsg.unimp "%s: unhandled integer width: %d bits" + fname bitswidth + ) else ( + (* It's a bitfield if either the offset or width isn't + * byte-aligned. + *) + let bitsoffset = bitsoffset land 7 in + printf "--> bitfield %s: byteoffset=%d bytewidth=%d signed=%b endian=%s bitsoffset=%d bitswidth=%d\n" + fname byteoffset bytewidth + signed (Option.map_default Bitmatch.string_of_endian "None" endian) bitsoffset bitswidth + ) + in +*) + ) structs; + + if !Errormsg.hadErrors then exit 1; + + exit 0 diff --git a/cil-tools/ext3.c b/cil-tools/ext3.c index ba35518..89ca20d 100644 --- a/cil-tools/ext3.c +++ b/cil-tools/ext3.c @@ -1,7 +1,7 @@ /* This is an example import file, showing how to import the ext3 * superblock automatically from Linux header files. * - * Use: bitmatch-import-c ext3.c + * Use: bitmatch-import-c ext3.c > ext3_stubs.ml * * Tip: Add the --debug flag to that command line to see what's going on. */ diff --git a/cil-tools/task_struct.c b/cil-tools/task_struct.c new file mode 100644 index 0000000..b17f925 --- /dev/null +++ b/cil-tools/task_struct.c @@ -0,0 +1,25 @@ +/* This is an example import file, showing how to import the + * Linux task_struct structure from header files. + * + * Use: bitmatch-import-c task_struct.c > task_struct.ml + * + * Tip: Add the --debug flag to that command line to see what's going on. + */ + +/* Any defines, etc. necessary to get the include to work. */ +#define __KERNEL__ +#define CONFIG_HZ 100 +#define CONFIG_PAGE_OFFSETUL 0xc0000000 /* XXX? */ +#define THREAD_SIZE 4096 /* XXX? */ + +/* Include files necessary to get the structure(s) and constant(s) we're + * interested in. + * + * Note in this case glibc strips the useful structures out of the + * so-called "kernel headers" that it supplies, so instead I have + * a local copy of the real headers from a version of Linux. + */ +#include "linux/sched.h" + +/* This tells the importer program what structures and constants to import. */ +typedef struct task_struct BITMATCH_IMPORT(task_struct); -- 1.8.3.1