(* * This file is part of ilLib * Copyright (c)2004-2013 Haxe Foundation * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *) open IlMeta;; open IlData;; open PeReader;; open ExtString;; let rec follow s = match s with | SReqModifier (_,s) | SOptModifier (_,s) -> follow s | SPinned s -> follow s | s -> s (* tells if a type_def_or_ref is of type `path` *) let rec is_type path = function | TypeDef td -> td.td_namespace = fst path && td.td_name = snd path | TypeRef tr -> tr.tr_namespace = fst path && tr.tr_name = snd path | TypeSpec ts -> (match follow ts.ts_signature with | SClass c | SValueType c -> is_type path c | SGenericInst(s,_) -> (match follow s with | SClass c | SValueType c -> is_type path c | _ -> false) | _ -> false) | _ -> assert false let rec get_path type_def_or_ref = match type_def_or_ref with | TypeDef td -> (match td.td_extra_enclosing with | None -> td.td_namespace,[], td.td_name | Some t2 -> let ns, nested = match get_path (TypeDef t2) with | ns,nested, name -> ns, nested @ [name] in ns,nested, td.td_name) | TypeRef tr -> (match tr.tr_resolution_scope with | TypeRef tr2 -> let ns, nested = match get_path (TypeRef tr2) with | ns,nested, name -> ns, nested @ [name] in ns,nested, tr.tr_name | _ -> tr.tr_namespace,[],tr.tr_name) | TypeSpec ts -> (match follow ts.ts_signature with | SClass c | SValueType c -> get_path c | SGenericInst(s,_) -> (match follow s with | SClass c | SValueType c -> get_path c | _ -> [],[],"") | _ -> [],[],"") | _ -> assert false let constant_s = function | IBool true -> "true" | IBool false -> "false" | IChar chr -> "'" ^ Char.escaped (Char.chr chr) ^ "'" | IByte i -> Printf.sprintf "(byte) 0x%x" i | IShort i -> Printf.sprintf "(short) 0x%x" i | IInt i -> Printf.sprintf "0x%lx" i | IInt64 i -> Printf.sprintf "0x%Lx" i | IFloat32 f -> Printf.sprintf "%ff" f | IFloat64 f -> Printf.sprintf "%fd" f | IString s -> "\"" ^ s ^ "\"" | INull -> "null" let path_s = function | [],[], s -> s | ns,[], s -> String.concat "." ns ^ "." ^ s | [],enc, s -> String.concat "@" enc ^ "." ^ s | ns,enc,s -> String.concat "." ns ^ "." ^ String.concat "@" enc ^ "." ^ s let rec ilsig_s = function | SBoxed -> "boxed" | SEnum e -> "enum " ^ e | SType -> "System.Type" | SVoid -> "void" | SBool -> "bool" | SChar -> "char" | SInt8 -> "int8" | SUInt8 -> "uint8" | SInt16 -> "int16" | SUInt16 -> "uint16" | SInt32 -> "int32" | SUInt32 -> "uint32" | SInt64 -> "int64" | SUInt64 -> "uint64" | SFloat32 -> "float" | SFloat64 -> "double" | SString -> "string" | SPointer s -> ilsig_s s ^ "*" | SManagedPointer s -> ilsig_s s ^ "&" | SValueType td -> "valuetype " ^ path_s (get_path td) | SClass cl -> "classtype " ^ path_s (get_path cl) | STypeParam t | SMethodTypeParam t -> "!" ^ string_of_int t | SArray (s,opts) -> ilsig_s s ^ "[" ^ String.concat "," (List.map (function | Some i,None when i <> 0 -> string_of_int i ^ "..." | None, Some i when i <> 0 -> string_of_int i | Some s, Some b when b = 0 && s <> 0 -> string_of_int s ^ "..." | Some s, Some b when s <> 0 || b <> 0 -> let b = if b > 0 then b - 1 else b in string_of_int s ^ "..." ^ string_of_int (s + b) | _ -> "" ) (Array.to_list opts)) ^ "]" | SGenericInst (t,tl) -> "generic " ^ (ilsig_s t) ^ "<" ^ String.concat ", " (List.map ilsig_s tl) ^ ">" | STypedReference -> "typedreference" | SIntPtr -> "native int" | SUIntPtr -> "native unsigned int" | SFunPtr (callconv,ret,args) -> "function " ^ ilsig_s ret ^ "(" ^ String.concat ", " (List.map ilsig_s args) ^ ")" | SObject -> "object" | SVector s -> ilsig_s s ^ "[]" | SReqModifier (_,s) -> "modreq() " ^ ilsig_s s | SOptModifier (_,s) -> "modopt() " ^ ilsig_s s | SSentinel -> "..." | SPinned s -> "pinned " ^ ilsig_s s let rec instance_s = function | InstConstant c -> constant_s c | InstBoxed b -> "boxed " ^ instance_s b | InstType t -> "Type " ^ t | InstArray il -> "[" ^ String.concat ", " (List.map instance_s il) ^ "]" | InstEnum e -> "Enum " ^ string_of_int e let named_attribute_s (is_prop,name,inst) = (if is_prop then "/*prop*/ " else "") ^ name ^ " = " ^ instance_s inst let attributes_s (il,nal) = "(" ^ (String.concat ", " (List.map instance_s il)) ^ (if nal <> [] then ", " ^ (String.concat ", " (List.map named_attribute_s nal)) else "") ^")" let meta_root m : meta_root = match m with | Module r -> Obj.magic r | TypeRef r -> Obj.magic r | TypeDef r -> Obj.magic r | FieldPtr r -> Obj.magic r | Field r -> Obj.magic r | MethodPtr r -> Obj.magic r | Method r -> Obj.magic r | ParamPtr r -> Obj.magic r | Param r -> Obj.magic r | InterfaceImpl r -> Obj.magic r | MemberRef r -> Obj.magic r | Constant r -> Obj.magic r | CustomAttribute r -> Obj.magic r | FieldMarshal r -> Obj.magic r | DeclSecurity r -> Obj.magic r | ClassLayout r -> Obj.magic r | FieldLayout r -> Obj.magic r | StandAloneSig r -> Obj.magic r | EventMap r -> Obj.magic r | EventPtr r -> Obj.magic r | Event r -> Obj.magic r | PropertyMap r -> Obj.magic r | PropertyPtr r -> Obj.magic r | Property r -> Obj.magic r | MethodSemantics r -> Obj.magic r | MethodImpl r -> Obj.magic r | ModuleRef r -> Obj.magic r | TypeSpec r -> Obj.magic r | ImplMap r -> Obj.magic r | FieldRVA r -> Obj.magic r | ENCLog r -> Obj.magic r | ENCMap r -> Obj.magic r | Assembly r -> Obj.magic r | AssemblyProcessor r -> Obj.magic r | AssemblyOS r -> Obj.magic r | AssemblyRef r -> Obj.magic r | AssemblyRefProcessor r -> Obj.magic r | AssemblyRefOS r -> Obj.magic r | File r -> Obj.magic r | ExportedType r -> Obj.magic r | ManifestResource r -> Obj.magic r | NestedClass r -> Obj.magic r | GenericParam r -> Obj.magic r | MethodSpec r -> Obj.magic r | GenericParamConstraint r -> Obj.magic r | _ -> assert false let meta_root_ptr p : meta_root_ptr = match p with | FieldPtr r -> Obj.magic r | MethodPtr r -> Obj.magic r | ParamPtr r -> Obj.magic r | EventPtr r -> Obj.magic r | _ -> assert false let rec ilsig_norm = function | SVoid -> LVoid | SBool -> LBool | SChar -> LChar | SInt8 -> LInt8 | SUInt8 -> LUInt8 | SInt16 -> LInt16 | SUInt16 -> LUInt16 | SInt32 -> LInt32 | SUInt32 -> LUInt32 | SInt64 -> LInt64 | SUInt64 -> LUInt64 | SFloat32 -> LFloat32 | SFloat64 -> LFloat64 | SString -> LString | SPointer p -> LPointer (ilsig_norm p) | SManagedPointer p -> LManagedPointer (ilsig_norm p) | SValueType v -> LValueType (get_path v, []) | SClass v -> LClass (get_path v, []) | STypeParam i -> LTypeParam i | SArray (t, opts) -> LArray(ilsig_norm t, opts) | SGenericInst (p,args) -> (match follow p with | SClass v -> LClass(get_path v, List.map ilsig_norm args) | SValueType v -> LValueType(get_path v, List.map ilsig_norm args) | _ -> assert false) | STypedReference -> LTypedReference | SIntPtr -> LIntPtr | SUIntPtr -> LUIntPtr | SFunPtr(conv,ret,args) -> LMethod(conv,ilsig_norm ret,List.map ilsig_norm args) | SObject -> LObject | SVector s -> LVector (ilsig_norm s) | SMethodTypeParam i -> LMethodTypeParam i | SReqModifier (_,s) -> ilsig_norm s | SOptModifier (_,s) -> ilsig_norm s | SSentinel -> LSentinel | SPinned s -> ilsig_norm s | SType -> LClass( (["System"],[],"Type"), []) | SBoxed -> LObject | SEnum e -> let lst = String.nsplit e "." in let rev = List.rev lst in match rev with | hd :: tl -> LValueType( (List.rev tl,[],hd), [] ) | _ -> assert false let ilsig_t s = { snorm = ilsig_norm s; ssig = s; } let ilsig_of_tdef_ref = function | TypeDef td -> SClass (TypeDef td) | TypeRef tr -> SClass (TypeRef tr) | TypeSpec ts -> ts.ts_signature | s -> (* error ("Invalid tdef_or_ref: " ^ ilsig_s s) *) error "Invalid tdef_or_ref" let convert_field ctx f = let constant = List.fold_left (fun c -> function | Constant c -> Some c.c_value | _ -> c ) None (Hashtbl.find_all ctx.il_relations (IField, f.f_id)) in { fname = f.f_name; fflags = f.f_flags; fsig = ilsig_t f.f_signature; fconstant = constant; } let convert_generic ctx gp = let constraints = List.fold_left (fun c -> function | GenericParamConstraint gc -> ilsig_t (ilsig_of_tdef_ref gc.gc_constraint) :: c | _ -> c ) [] (Hashtbl.find_all ctx.il_relations (IGenericParam, gp.gp_id)) in { tnumber = gp.gp_number; tflags = gp.gp_flags; tname = gp.gp_name; tconstraints = constraints; } let convert_method ctx m = let msig = ilsig_t m.m_signature in let ret, margs = match follow msig.ssig with | SFunPtr (_,ret,args) -> (* print_endline m.m_name; *) (* print_endline (Printf.sprintf "%d vs %d" (List.length args) (List.length m.m_param_list)); *) (* print_endline (String.concat ", " (List.map (fun p ->string_of_int p.p_sequence ^ ":" ^ p.p_name) m.m_param_list)); *) (* print_endline (String.concat ", " (List.map (ilsig_s) args)); *) (* print_endline "\n"; *) (* TODO: find out WHY this happens *) let param_list = List.filter (fun p -> p.p_sequence > 0) m.m_param_list in if List.length param_list <> List.length args then let i = ref 0 in ilsig_t ret, List.map (fun s -> incr i; "arg" ^ (string_of_int !i), { pf_io = []; pf_reserved = [] }, ilsig_t s) args else ilsig_t ret, List.map2 (fun p s -> p.p_name, p.p_flags, ilsig_t s ) param_list args | _ -> assert false in let override, types, semantics = List.fold_left (fun (override,types,semantics) -> function | MethodImpl mi -> let declaring = match mi.mi_method_declaration with | MemberRef mr -> Some (get_path mr.memr_class, mr.memr_name) | Method m -> (match m.m_declaring with | Some td -> Some (get_path (TypeDef td), m.m_name) | None -> override) | _ -> override in declaring, types, semantics | GenericParam gp -> override, (convert_generic ctx gp) :: types, semantics | MethodSemantics ms -> override, types, ms.ms_semantic @ semantics | _ -> override,types, semantics ) (None,[],[]) (Hashtbl.find_all ctx.il_relations (IMethod, m.m_id)) in { mname = m.m_name; mflags = m.m_flags; msig = msig; margs = margs; mret = ret; moverride = override; mtypes = types; msemantics = semantics; } let convert_prop ctx prop = let name = prop.prop_name in let flags = prop.prop_flags in let psig = ilsig_t prop.prop_type in let pget, pset = List.fold_left (fun (get,set) -> function | MethodSemantics ms when List.mem SGetter ms.ms_semantic -> assert (get = None); Some (ms.ms_method.m_name, ms.ms_method.m_flags), set | MethodSemantics ms when List.mem SSetter ms.ms_semantic -> assert (set = None); get, Some (ms.ms_method.m_name,ms.ms_method.m_flags) | _ -> get,set ) (None,None) (Hashtbl.find_all ctx.il_relations (IProperty, prop.prop_id)) in { pname = name; psig = psig; pflags = flags; pget = pget; pset = pset; } let convert_event ctx event = let name = event.e_name in let flags = event.e_flags in let esig = ilsig_of_tdef_ref event.e_event_type in let esig = ilsig_t esig in let add, remove, eraise = List.fold_left (fun (add, remove, eraise) -> function | MethodSemantics ms when List.mem SAddOn ms.ms_semantic -> assert (add = None); Some (ms.ms_method.m_name, ms.ms_method.m_flags), remove, eraise | MethodSemantics ms when List.mem SRemoveOn ms.ms_semantic -> assert (remove = None); add, Some (ms.ms_method.m_name,ms.ms_method.m_flags), eraise | MethodSemantics ms when List.mem SFire ms.ms_semantic -> assert (eraise = None); add, remove, Some (ms.ms_method.m_name, ms.ms_method.m_flags) | _ -> add, remove, eraise ) (None,None,None) (Hashtbl.find_all ctx.il_relations (IEvent, event.e_id)) in { ename = name; eflags = flags; esig = esig; eadd = add; eremove = remove; eraise = eraise; } let convert_class ctx path = let td = Hashtbl.find ctx.il_typedefs path in let cpath = get_path (TypeDef td) in let cflags = td.td_flags in let csuper = Option.map (fun e -> ilsig_t (ilsig_of_tdef_ref e)) td.td_extends in let cfields = List.map (convert_field ctx) td.td_field_list in let cmethods = List.map (convert_method ctx) td.td_method_list in let enclosing = Option.map (fun t -> get_path (TypeDef t)) td.td_extra_enclosing in let impl, types, nested, props, events, attrs = List.fold_left (fun (impl,types,nested,props,events,attrs) -> function | InterfaceImpl ii -> (ilsig_t (ilsig_of_tdef_ref ii.ii_interface)) :: impl,types,nested, props, events, attrs | GenericParam gp -> (impl, (convert_generic ctx gp) :: types, nested, props,events, attrs) | NestedClass nc -> assert (nc.nc_enclosing.td_id = td.td_id); (impl,types,(get_path (TypeDef nc.nc_nested)) :: nested, props, events, attrs) | PropertyMap pm -> assert (props = []); impl,types,nested,List.map (convert_prop ctx) pm.pm_property_list, events, attrs | EventMap em -> assert (events = []); (impl,types,nested,props,List.map (convert_event ctx) em.em_event_list, attrs) | CustomAttribute a -> impl,types,nested,props,events,(a :: attrs) | _ -> (impl,types,nested,props,events,attrs) ) ([],[],[],[],[],[]) (Hashtbl.find_all ctx.il_relations (ITypeDef, td.td_id)) in { cpath = cpath; cflags = cflags; csuper = csuper; cfields = cfields; cmethods = cmethods; cevents = events; cprops = props; cimplements = impl; ctypes = types; cenclosing = enclosing; cnested = nested; cattrs = attrs; }