{**************************************************************************************************} { } { Project JEDI Code Library (JCL) } { } { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); } { you may not use this file except in compliance with the License. You may obtain a copy of the } { License at http://www.mozilla.org/MPL/ } { } { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF } { ANY KIND, either express or implied. See the License for the specific language governing rights } { and limitations under the License. } { } { The Original Code is JclCIL.pas. } { } { The Initial Developer of the Original Code is Flier Lu (). } { Portions created by Flier Lu are Copyright (C) Flier Lu. All Rights Reserved. } { } { Contributors: } { Flier Lu (flier) } { Robert Marquardt (marquardt) } { Robert Rossmair (rrossmair) } { Olivier Sannier (obones) } { Petr Vones (pvones) } { } {**************************************************************************************************} { } { Microsoft .Net CIL Instruction Set information support routines and classes. } { } { Unit owner: Flier Lu } { } {**************************************************************************************************} // Last modified: $Date: 2005/05/08 08:05:53 $ // For history see end of file unit JclCIL; interface {$I jcl.inc} uses {$IFDEF MSWINDOWS} Windows, {$ENDIF MSWINDOWS} Classes, SysUtils, {$IFDEF RTL130_UP} Contnrs, {$ENDIF RTL130_UP} JclBase, JclSysUtils, JclCLR, JclMetadata; type TJclOpCode = (opNop, opBreak, opLdArg_0, opLdArg_1, opLdArg_2, opLdArg_3, opLdLoc_0, opLdLoc_1, opLdLoc_2, opLdLoc_3, opStLoc_0, opStLoc_1, opStLoc_2, opStLoc_3, opldArg_s, opLdArga_s, opStArg_s, opLdLoc_s, opLdLoca_s, opStLoc_s, opLdNull, opLdc_I4_M1, opLdc_I4_0, opLdc_I4_1, opLdc_I4_2, opLdc_I4_3, opLdc_I4_4, opLdc_I4_5, opLdc_I4_6, opLdc_I4_7, opLdc_I4_8, opLdc_I4_s, opLdc_i4, opLdc_i8, opLdc_r4, opLdc_r8, opUnused49, opDup, opPop, opJmp, opCall, opCalli, opRet, opBr_s, opBrFalse_s, opBrTrue_s, opBeq_s, opBge_s, opBgt_s, opBle_s, opBlt_s, opBne_un_s, opBge_un_s, opBgt_un_s, opBle_un_s, opBlt_un_s, opBr, opBrFalse, opBrTrue, opBeq, opBge, opBgt, opBle, opBlt, opBne_un, opBge_un, opBgt_un, opBle_un, opBlt_un, opSwitch, opLdInd_i1, opLdInd_i2, opLdInd_u1, opLdInd_u2, opLdInd_i4, opLdInd_u4, opLdInd_i8, opLdInd_i, opLdInd_r4, opLdInd_r8, opLdInd_ref, opStInd_ref, opStInd_i1, opStInd_i2, opStInd_i4, opStInd_i8, opStInd_r4, opStInd_r8, opAdd, opSub, opMul, opDiv, opDiv_un, opRem, opRem_un, opAnd, opOr, opXor, opShl, opShr, opShr_un, opNeg, opNot, opConv_i1, opConv_i2, opConv_i4, opConv_i8, opConv_r4, opConv_r8, opConv_u4, opConv_u8, opCallVirt, opCpObj, opLdObj, opLdStr, opNewObj, opCastClass, opIsInst, opConv_r_un, opUnused58, opUnused1, opUnbox, opThrow, opLdFld, opLdFlda, opStFld, opLdsFld, opLdsFlda, opStsFld, opStObj, opConv_ovf_i1_un, opConv_ovf_i2_un, opConv_ovf_i4_un, opConv_ovf_i8_un, opConv_ovf_u1_un, opConv_ovf_u2_un, opConv_ovf_u4_un, opConv_ovf_u8_un, opConv_ovf_i_un, opConv_ovf_u_un, opBox, opNewArr, opLdLen, opLdElema, opLdElem_i1, opLdElem_u1, opLdElem_i2, opLdElem_u2, opLdElem_i4, opLdElem_u4, opLdElem_i8, opLdElem_i, opLdElem_r4, opLdElem_r8, opLdElem_ref, opStElem_i, opStElem_i1, opStElem_i2, opStElem_i4, opStElem_i8, opStElem_r4, opStElem_r8, opStElem_ref, opUnused2, opUnused3, opUnused4, opUnused5, opUnused6, opUnused7, opUnused8, opUnused9, opUnused10, opUnused11, opUnused12, opUnused13, opUnused14, opUnused15, opUnused16, opUnused17, opConv_ovf_i1, opConv_ovf_u1, opConv_ovf_i2, opConv_ovf_u2, opConv_ovf_i4, opConv_ovf_u4, opConv_ovf_i8, opConv_ovf_u8, opUnused50, opUnused18, opUnused19, opUnused20, opUnused21, opUnused22, opUnused23, opRefAnyVal, opCkFinite, opUnused24, opUnused25, opMkRefAny, opUnused59, opUnused60, opUnused61, opUnused62, opUnused63, opUnused64, opUnused65, opUnused66, opUnused67, opLdToken, opConv_u2, opConv_u1, opConv_i, opConv_ovf_i, opConv_ovf_u, opAdd_ovf, opAdd_ovf_un, opMul_ovf, opMul_ovf_un, opSub_ovf, opSub_ovf_un, opEndFinally, opLeave, opLeave_s, opStInd_i, opConv_u, opUnused26, opUnused27, opUnused28, opUnused29, opUnused30, opUnused31, opUnused32, opUnused33, opUnused34, opUnused35, opUnused36, opUnused37, opUnused38, opUnused39, opUnused40, opUnused41, opUnused42, opUnused43, opUnused44, opUnused45, opUnused46, opUnused47, opUnused48, opPrefix7, opPrefix6, opPrefix5, opPrefix4, opPrefix3, opPrefix2, opPrefix1, opPrefixRef, opArgLlist, opCeq, opCgt, opCgt_un, opClt, opClt_un, opLdFtn, opLdVirtFtn, optUnused56, opLdArg, opLdArga, opStArg, opLdLoc, opLdLoca, opStLoc, opLocalLoc, opUnused57, opEndFilter, opUnaligned, opVolatile, opTail, opInitObj, opUnused68, opCpBlk, opInitBlk, opUnused69, opRethrow, opUnused51, opSizeOf, opRefAnyType, opUnused52, opUnused53, opUnused54, opUnused55, opUnused70); TJclInstructionDumpILOption = (doLineNo, doRawBytes, doIL, doTokenValue, doComment); TJclInstructionDumpILOptions = set of TJclInstructionDumpILOption; TJclInstructionParamType = (ptVoid, ptI1, ptI2, ptI4, ptI8, ptU1, ptU2, ptU4, ptU8, ptR4, ptR8, ptToken, ptSOff, ptLOff, ptArray); const InstructionDumpILAllOption = [doLineNo, doRawBytes, doIL, doTokenValue, doComment]; type TJclClrILGenerator = class; TJclInstruction = class(TObject) private FOpCode: TJclOpCode; FOffset: DWORD; FParam: Variant; FOwner: TJclClrILGenerator; function GetWideOpCode: Boolean; function GetRealOpCode: Byte; function GetName: string; function GetFullName: string; function GetDescription: string; function GetParamType: TJclInstructionParamType; function FormatLabel(Offset: Integer): string; protected function GetSize: DWORD; virtual; function DumpILOption(Option: TJclInstructionDumpILOption): string; virtual; public constructor Create(AOwner: TJclClrILGenerator; AOpCode: TJclOpCode); procedure Load(Stream: TStream); virtual; procedure Save(Stream: TStream); virtual; function DumpIL(Options: TJclInstructionDumpILOptions = [doIL]): string; property Owner: TJclClrILGenerator read FOwner; property OpCode: TJclOpCode read FOpCode; property WideOpCode: Boolean read GetWideOpCode; property RealOpCode: Byte read GetRealOpCode; property Param: Variant read FParam write FParam; property ParamType: TJclInstructionParamType read GetParamType; property Name: string read GetName; property FullName: string read GetFullName; property Description: string read GetDescription; property Size: DWORD read GetSize; property Offset: DWORD read FOffset; end; TJclUnaryInstruction = class(TJclInstruction); TJclBinaryInstruction = class(TJclInstruction); TJclClrILGenerator = class(TObject) private FMethod: TJclClrMethodBody; FInstructions: TObjectList; function GetInstructionCount: Integer; function GetInstruction(const Idx: Integer): TJclInstruction; public constructor Create(AMethod: TJclClrMethodBody = nil); destructor Destroy; override; function DumpIL(Options: TJclInstructionDumpILOptions): string; property Method: TJclClrMethodBody read FMethod; property Instructions[const Idx: Integer]: TJclInstruction read GetInstruction; property InstructionCount: Integer read GetInstructionCount; end; EJclCliInstructionError = class(EJclError); EJclCliInstructionStreamInvalid = class(EJclCliInstructionError); implementation uses {$IFDEF HAS_UNIT_VARIANTS} Variants, {$ENDIF HAS_UNIT_VARIANTS} JclStrings, JclResources; type TJclOpCodeInfoType = (itName, itFullName, itDescription); const STP1 = $FE; OpCodeInfos: array [TJclOpCode, TJclOpCodeInfoType] of string = ( ('nop', RsCILCmdnop, RsCILDescrnop), ('break', RsCILCmdbreak, RsCILDescrbreak), ('ldarg.0', RsCILCmdldarg0, RsCILDescrldarg0), ('ldarg.1', RsCILCmdldarg1, RsCILDescrldarg1), ('ldarg.2', RsCILCmdldarg2, RsCILDescrldarg2), ('ldarg.3', RsCILCmdldarg3, RsCILDescrldarg3), ('ldloc.0', RsCILCmdldloc0, RsCILDescrldloc0), ('ldloc.1', RsCILCmdldloc1, RsCILDescrldloc1), ('ldloc.2', RsCILCmdldloc2, RsCILDescrldloc2), ('ldloc.3', RsCILCmdldloc3, RsCILDescrldloc3), ('stloc.0', RsCILCmdstloc0, RsCILDescrstloc0), ('stloc.1', RsCILCmdstloc1, RsCILDescrstloc1), ('stloc.2', RsCILCmdstloc2, RsCILDescrstloc2), ('stloc.3', RsCILCmdstloc3, RsCILDescrstloc3), ('ldarg.s', RsCILCmdldargs, RsCILDescrldargs), ('ldarga.s', RsCILCmdldargas, RsCILDescrldargas), ('starg.s', RsCILCmdstargs, RsCILDescrstargs), ('ldloc.s', RsCILCmdldlocs, RsCILDescrldlocs), ('ldloca.s', RsCILCmdldlocas, RsCILDescrldlocas), ('stloc.s', RsCILCmdstlocs, RsCILDescrstlocs), ('ldnull', RsCILCmdldnull, RsCILDescrldnull), ('ldc.i4.m1', RsCILCmdldci4m1, RsCILDescrldci4m1), ('ldc.i4.0', RsCILCmdldci40, RsCILDescrldci40), ('ldc.i4.1', RsCILCmdldci41, RsCILDescrldci41), ('ldc.i4.2', RsCILCmdldci42, RsCILDescrldci42), ('ldc.i4.3', RsCILCmdldci43, RsCILDescrldci43), ('ldc.i4.4', RsCILCmdldci44, RsCILDescrldci44), ('ldc.i4.5', RsCILCmdldci45, RsCILDescrldci45), ('ldc.i4.6', RsCILCmdldci46, RsCILDescrldci46), ('ldc.i4.7', RsCILCmdldci47, RsCILDescrldci47), ('ldc.i4.8', RsCILCmdldci48, RsCILDescrldci48), ('ldc.i4.s', RsCILCmdldci4s, RsCILDescrldci4s), ('ldc.i4', RsCILCmdldci4, RsCILDescrldci4), ('ldc.i8', RsCILCmdldci8, RsCILDescrldci8), ('ldc.r4', RsCILCmdldcr4, RsCILDescrldcr4), ('ldc.r8', RsCILCmdldcr8, RsCILDescrldcr8), ('unused', RsCILCmdunused1, RsCILDescrunused1), ('dup', RsCILCmddup, RsCILDescrdup), ('pop', RsCILCmdpop, RsCILDescrpop), ('jmp', RsCILCmdjmp, RsCILDescrjmp), ('call', RsCILCmdcall, RsCILDescrcall), ('calli', RsCILCmdcalli, RsCILDescrcalli), ('ret', RsCILCmdret, RsCILDescrret), ('br.s', RsCILCmdbrs, RsCILDescrbrs), ('brfalse.s', RsCILCmdbrfalses, RsCILDescrbrfalses), ('brtrue.s', RsCILCmdbrtrues, RsCILDescrbrtrues), ('beq.s', RsCILCmdbeqs, RsCILDescrbeqs), ('bge.s', RsCILCmdbges, RsCILDescrbges), ('bgt.s', RsCILCmdbgts, RsCILDescrbgts), ('ble.s', RsCILCmdbles, RsCILDescrbles), ('blt.s', RsCILCmdblts, RsCILDescrblts), ('bne.un.s', RsCILCmdbneuns, RsCILDescrbneuns), ('bge.un.s', RsCILCmdbgeuns, RsCILDescrbgeuns), ('bgt.un.s', RsCILCmdbgtuns, RsCILDescrbgtuns), ('ble.un.s', RsCILCmdbleuns, RsCILDescrbleuns), ('blt.un.s', RsCILCmdbltuns, RsCILDescrbltuns), ('br', RsCILCmdbr, RsCILDescrbr), ('brfalse', RsCILCmdbrfalse, RsCILDescrbrfalse), ('brtrue', RsCILCmdbrtrue, RsCILDescrbrtrue), ('beq', RsCILCmdbeq, RsCILDescrbeq), ('bge', RsCILCmdbge, RsCILDescrbge), ('bgt', RsCILCmdbgt, RsCILDescrbgt), ('ble', RsCILCmdble, RsCILDescrble), ('blt', RsCILCmdblt, RsCILDescrblt), ('bne.un', RsCILCmdbneun, RsCILDescrbneun), ('bge.un', RsCILCmdbgeun, RsCILDescrbgeun), ('bgt.un', RsCILCmdbgtun, RsCILDescrbgtun), ('ble.un', RsCILCmdbleun, RsCILDescrbleun), ('blt.un', RsCILCmdbltun, RsCILDescrbltun), ('switch', RsCILCmdswitch, RsCILDescrswitch), ('ldind.i1', RsCILCmdldindi1, RsCILDescrldindi1), ('ldind.u1', RsCILCmdldindu1, RsCILDescrldindu1), ('ldind.i2', RsCILCmdldindi2, RsCILDescrldindi2), ('ldind.u2', RsCILCmdldindu2, RsCILDescrldindu2), ('ldind.i4', RsCILCmdldindi4, RsCILDescrldindi4), ('ldind.u4', RsCILCmdldindu4, RsCILDescrldindu4), ('ldind.i8', RsCILCmdldindi8, RsCILDescrldindi8), ('ldind.i', RsCILCmdldindi, RsCILDescrldindi), ('ldind.r4', RsCILCmdldindr4, RsCILDescrldindr4), ('ldind.r8', RsCILCmdldindr8, RsCILDescrldindr8), ('ldind.ref', RsCILCmdldindref, RsCILDescrldindref), ('stind.ref', RsCILCmdstindref, RsCILDescrstindref), ('stind.i1', RsCILCmdstindi1, RsCILDescrstindi1), ('stind.i2', RsCILCmdstindi2, RsCILDescrstindi2), ('stind.i4', RsCILCmdstindi4, RsCILDescrstindi4), ('stind.i8', RsCILCmdstindi8, RsCILDescrstindi8), ('stind.r4', RsCILCmdstindr4, RsCILDescrstindr4), ('stind.r8', RsCILCmdstindr8, RsCILDescrstindr8), ('add', RsCILCmdadd, RsCILDescradd), ('sub', RsCILCmdsub, RsCILDescrsub), ('mul', RsCILCmdmul, RsCILDescrmul), ('div', RsCILCmddiv, RsCILDescrdiv), ('div.un', RsCILCmddivun, RsCILDescrdivun), ('rem', RsCILCmdrem, RsCILDescrrem), ('rem.un', RsCILCmdremun, RsCILDescrremun), ('and', RsCILCmdand, RsCILDescrand), ('or', RsCILCmdor, RsCILDescror), ('xor', RsCILCmdxor, RsCILDescrxor), ('shl', RsCILCmdshl, RsCILDescrshl), ('shr', RsCILCmdshr, RsCILDescrshr), ('shr.un', RsCILCmdshrun, RsCILDescrshrun), ('neg', RsCILCmdneg, RsCILDescrneg), ('not', RsCILCmdnot, RsCILDescrnot), ('conv.i1', RsCILCmdconvi1, RsCILDescrconvi1), ('conv.i2', RsCILCmdconvi2, RsCILDescrconvi2), ('conv.i4', RsCILCmdconvi4, RsCILDescrconvi4), ('conv.i8', RsCILCmdconvi8, RsCILDescrconvi8), ('conv.r4', RsCILCmdconvr4, RsCILDescrconvr4), ('conv.r8', RsCILCmdconvr8, RsCILDescrconvr8), ('conv.u4', RsCILCmdconvu4, RsCILDescrconvu4), ('conv.u8', RsCILCmdconvu8, RsCILDescrconvu8), ('callvirt', RsCILCmdcallvirt, RsCILDescrcallvirt), ('cpobj', RsCILCmdcpobj, RsCILDescrcpobj), ('ldobj', RsCILCmdldobj, RsCILDescrldobj), ('ldstr', RsCILCmdldstr, RsCILDescrldstr), ('newobj', RsCILCmdnewobj, RsCILDescrnewobj), ('castclass', RsCILCmdcastclass, RsCILDescrcastclass), ('isinst', RsCILCmdisinst, RsCILDescrisinst), ('conv.r.un', RsCILCmdconvrun, RsCILDescrconvrun), ('unused', RsCILCmdunused2, RsCILDescrunused2), ('unused', RsCILCmdunused3, RsCILDescrunused3), ('unbox', RsCILCmdunbox, RsCILDescrunbox), ('throw', RsCILCmdthrow, RsCILDescrthrow), ('ldfld', RsCILCmdldfld, RsCILDescrldfld), ('ldflda', RsCILCmdldflda, RsCILDescrldflda), ('stfld', RsCILCmdstfld, RsCILDescrstfld), ('ldsfld', RsCILCmdldsfld, RsCILDescrldsfld), ('ldsflda', RsCILCmdldsflda, RsCILDescrldsflda), ('stsfld', RsCILCmdstsfld, RsCILDescrstsfld), ('stobj', RsCILCmdstobj, RsCILDescrstobj), ('conv.ovf.i1.un', RsCILCmdconvovfi1un, RsCILDescrconvovfi1un), ('conv.ovf.i2.un', RsCILCmdconvovfi2un, RsCILDescrconvovfi2un), ('conv.ovf.i4.un', RsCILCmdconvovfi4un, RsCILDescrconvovfi4un), ('conv.ovf.i8.un', RsCILCmdconvovfi8un, RsCILDescrconvovfi8un), ('conv.ovf.u1.un', RsCILCmdconvovfu1un, RsCILDescrconvovfu1un), ('conv.ovf.u2.un', RsCILCmdconvovfu2un, RsCILDescrconvovfu2un), ('conv.ovf.u4.un', RsCILCmdconvovfu4un, RsCILDescrconvovfu4un), ('conv.ovf.u8.un', RsCILCmdconvovfu8un, RsCILDescrconvovfu8un), ('conv.ovf.i.un', RsCILCmdconvovfiun, RsCILDescrconvovfiun), ('conv.ovf.u.un', RsCILCmdconvovfuun, RsCILDescrconvovfuun), ('box', RsCILCmdbox, RsCILDescrbox), ('newarr', RsCILCmdnewarr, RsCILDescrnewarr), ('ldlen', RsCILCmdldlen, RsCILDescrldlen), ('ldelema', RsCILCmdldelema, RsCILDescrldelema), ('ldelem.i1', RsCILCmdldelemi1, RsCILDescrldelemi1), ('ldelem.u1', RsCILCmdldelemu1, RsCILDescrldelemu1), ('ldelem.i2', RsCILCmdldelemi2, RsCILDescrldelemi2), ('ldelem.u2', RsCILCmdldelemu2, RsCILDescrldelemu2), ('ldelem.i4', RsCILCmdldelemi4, RsCILDescrldelemi4), ('ldelem.u4', RsCILCmdldelemu4, RsCILDescrldelemu4), ('ldelem.i8', RsCILCmdldelemi8, RsCILDescrldelemi8), ('ldelem.i', RsCILCmdldelemi, RsCILDescrldelemi), ('ldelem.r4', RsCILCmdldelemr4, RsCILDescrldelemr4), ('ldelem.r8', RsCILCmdldelemr8, RsCILDescrldelemr8), ('ldelem.ref', RsCILCmdldelemref, RsCILDescrldelemref), ('stelem.i', RsCILCmdstelemi, RsCILDescrstelemi), ('stelem.i1', RsCILCmdstelemi1, RsCILDescrstelemi1), ('stelem.i2', RsCILCmdstelemi2, RsCILDescrstelemi2), ('stelem.i4', RsCILCmdstelemi4, RsCILDescrstelemi4), ('stelem.i8', RsCILCmdstelemi8, RsCILDescrstelemi8), ('stelem.r4', RsCILCmdstelemr4, RsCILDescrstelemr4), ('stelem.r8', RsCILCmdstelemr8, RsCILDescrstelemr8), ('stelem.ref', RsCILCmdstelemref, RsCILDescrstelemref), ('unused', RsCILCmdunused4, RsCILDescrunused4), ('unused', RsCILCmdunused5, RsCILDescrunused5), ('unused', RsCILCmdunused6, RsCILDescrunused6), ('unused', RsCILCmdunused7, RsCILDescrunused7), ('unused', RsCILCmdunused8, RsCILDescrunused8), ('unused', RsCILCmdunused9, RsCILDescrunused9), ('unused', RsCILCmdunused10, RsCILDescrunused10), ('unused', RsCILCmdunused11, RsCILDescrunused11), ('unused', RsCILCmdunused12, RsCILDescrunused12), ('unused', RsCILCmdunused13, RsCILDescrunused13), ('unused', RsCILCmdunused14, RsCILDescrunused14), ('unused', RsCILCmdunused15, RsCILDescrunused15), ('unused', RsCILCmdunused16, RsCILDescrunused16), ('unused', RsCILCmdunused17, RsCILDescrunused17), ('unused', RsCILCmdunused18, RsCILDescrunused18), ('unused', RsCILCmdunused19, RsCILDescrunused19), ('conv.ovf.i1', RsCILCmdconvovfi1, RsCILDescrconvovfi1), ('conv.ovf.u1', RsCILCmdconvovfu1, RsCILDescrconvovfu1), ('conv.ovf.i2', RsCILCmdconvovfi2, RsCILDescrconvovfi2), ('conv.ovf.u2', RsCILCmdconvovfu2, RsCILDescrconvovfu2), ('conv.ovf.i4', RsCILCmdconvovfi4, RsCILDescrconvovfi4), ('conv.ovf.u4', RsCILCmdconvovfu4, RsCILDescrconvovfu4), ('conv.ovf.i8', RsCILCmdconvovfi8, RsCILDescrconvovfi8), ('conv.ovf.u8', RsCILCmdconvovfu8, RsCILDescrconvovfu8), ('unused', RsCILCmdunused20, RsCILDescrunused20), ('unused', RsCILCmdunused21, RsCILDescrunused21), ('unused', RsCILCmdunused22, RsCILDescrunused22), ('unused', RsCILCmdunused23, RsCILDescrunused23), ('unused', RsCILCmdunused24, RsCILDescrunused24), ('unused', RsCILCmdunused25, RsCILDescrunused25), ('unused', RsCILCmdunused26, RsCILDescrunused26), ('refanyval', RsCILCmdrefanyval, RsCILDescrrefanyval), ('ckfinite', RsCILCmdckfinite, RsCILDescrckfinite), ('unused', RsCILCmdunused27, RsCILDescrunused27), ('unused', RsCILCmdunused28, RsCILDescrunused28), ('mkrefany', RsCILCmdmkrefany, RsCILDescrmkrefany), ('unused', RsCILCmdunused29, RsCILDescrunused29), ('unused', RsCILCmdunused30, RsCILDescrunused30), ('unused', RsCILCmdunused31, RsCILDescrunused31), ('unused', RsCILCmdunused32, RsCILDescrunused32), ('unused', RsCILCmdunused33, RsCILDescrunused33), ('unused', RsCILCmdunused34, RsCILDescrunused34), ('unused', RsCILCmdunused35, RsCILDescrunused35), ('unused', RsCILCmdunused36, RsCILDescrunused36), ('unused', RsCILCmdunused37, RsCILDescrunused37), ('ldtoken', RsCILCmdldtoken, RsCILDescrldtoken), ('conv.u2', RsCILCmdconvu2, RsCILDescrconvu2), ('conv.u1', RsCILCmdconvu1, RsCILDescrconvu1), ('conv.i', RsCILCmdconvi, RsCILDescrconvi), ('conv.ovf.i', RsCILCmdconvovfi, RsCILDescrconvovfi), ('conv.ovf.u', RsCILCmdconvovfu, RsCILDescrconvovfu), ('add.ovf', RsCILCmdaddovf, RsCILDescraddovf), ('add.ovf.un', RsCILCmdaddovfun, RsCILDescraddovfun), ('mul.ovf', RsCILCmdmulovf, RsCILDescrmulovf), ('mul.ovf.un', RsCILCmdmulovfun, RsCILDescrmulovfun), ('sub.ovf', RsCILCmdsubovf, RsCILDescrsubovf), ('sub.ovf.un', RsCILCmdsubovfun, RsCILDescrsubovfun), ('endfinally', RsCILCmdendfinally, RsCILDescrendfinally), ('leave', RsCILCmdleave, RsCILDescrleave), ('leave.s', RsCILCmdleaves, RsCILDescrleaves), ('stind.i', RsCILCmdstindi, RsCILDescrstindi), ('conv.u', RsCILCmdconvu, RsCILDescrconvu), ('unused', RsCILCmdunused38, RsCILDescrunused38), ('unused', RsCILCmdunused39, RsCILDescrunused39), ('unused', RsCILCmdunused40, RsCILDescrunused40), ('unused', RsCILCmdunused41, RsCILDescrunused41), ('unused', RsCILCmdunused42, RsCILDescrunused42), ('unused', RsCILCmdunused43, RsCILDescrunused43), ('unused', RsCILCmdunused44, RsCILDescrunused44), ('unused', RsCILCmdunused45, RsCILDescrunused45), ('unused', RsCILCmdunused46, RsCILDescrunused46), ('unused', RsCILCmdunused47, RsCILDescrunused47), ('unused', RsCILCmdunused48, RsCILDescrunused48), ('unused', RsCILCmdunused49, RsCILDescrunused49), ('unused', RsCILCmdunused50, RsCILDescrunused50), ('unused', RsCILCmdunused51, RsCILDescrunused51), ('unused', RsCILCmdunused52, RsCILDescrunused52), ('unused', RsCILCmdunused53, RsCILDescrunused53), ('unused', RsCILCmdunused54, RsCILDescrunused54), ('unused', RsCILCmdunused55, RsCILDescrunused55), ('unused', RsCILCmdunused56, RsCILDescrunused56), ('unused', RsCILCmdunused57, RsCILDescrunused57), ('unused', RsCILCmdunused58, RsCILDescrunused58), ('unused', RsCILCmdunused59, RsCILDescrunused59), ('unused', RsCILCmdunused60, RsCILDescrunused60), ('prefix7', RsCILCmdprefix7, RsCILDescrprefix7), ('prefix6', RsCILCmdprefix6, RsCILDescrprefix6), ('prefix5', RsCILCmdprefix5, RsCILDescrprefix5), ('prefix4', RsCILCmdprefix4, RsCILDescrprefix4), ('prefix3', RsCILCmdprefix3, RsCILDescrprefix3), ('prefix2', RsCILCmdprefix2, RsCILDescrprefix2), ('prefix1', RsCILCmdprefix1, RsCILDescrprefix1), ('prefixref', RsCILCmdprefixref, RsCILDescrprefixref), ('arglist', RsCILCmdarglist, RsCILDescrarglist), ('ceq', RsCILCmdceq, RsCILDescrceq), ('cgt', RsCILCmdcgt, RsCILDescrcgt), ('cgt.un', RsCILCmdcgtun, RsCILDescrcgtun), ('clt', RsCILCmdclt, RsCILDescrclt), ('clt.un', RsCILCmdcltun, RsCILDescrcltun), ('ldftn', RsCILCmdldftn, RsCILDescrldftn), ('ldvirtftn', RsCILCmdldvirtftn, RsCILDescrldvirtftn), ('unused', RsCILCmdunused61, RsCILDescrunused61), ('ldarg', RsCILCmdldarg, RsCILDescrldarg), ('ldarga', RsCILCmdldarga, RsCILDescrldarga), ('starg', RsCILCmdstarg, RsCILDescrstarg), ('ldloc', RsCILCmdldloc, RsCILDescrldloc), ('ldloca', RsCILCmdldloca, RsCILDescrldloca), ('stloc', RsCILCmdstloc, RsCILDescrstloc), ('localloc', RsCILCmdlocalloc, RsCILDescrlocalloc), ('unused', RsCILCmdunused62, RsCILDescrunused62), ('endfilter', RsCILCmdendfilter, RsCILDescrendfilter), ('unaligned.', RsCILCmdunaligned, RsCILDescrunaligned), ('volatile.', RsCILCmdvolatile, RsCILDescrvolatile), ('tail.', RsCILCmdtail, RsCILDescrtail), ('initobj', RsCILCmdinitobj, RsCILDescrinitobj), ('unused', RsCILCmdunused63, RsCILDescrunused63), ('cpblk', RsCILCmdcpblk, RsCILDescrcpblk), ('initblk', RsCILCmdinitblk, RsCILDescrinitblk), ('unused', RsCILCmdunused64, RsCILDescrunused64), ('rethrow', RsCILCmdrethrow, RsCILDescrrethrow), ('unused', RsCILCmdunused65, RsCILDescrunused65), ('sizeof', RsCILCmdsizeof, RsCILDescrsizeof), ('refanytype', RsCILCmdrefanytype, RsCILDescrrefanytype), ('unused', RsCILCmdunused66, RsCILDescrunused66), ('unused', RsCILCmdunused67, RsCILDescrunused67), ('unused', RsCILCmdunused68, RsCILDescrunused68), ('unused', RsCILCmdunused69, RsCILDescrunused69), ('unused', RsCILCmdunused70, RsCILDescrunused70) ); OpCodeParamTypes: array [TJclOpCode] of TJclInstructionParamType = (ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {00} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptU1, ptU1, {08} ptU1, ptU1, ptU1, ptU1, ptVoid, ptVoid, ptVoid, ptVoid, {10} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptI1, {18} ptI4, ptI8, ptR4, ptR8, ptVoid, ptVoid, ptVoid, ptToken, {20} ptToken, ptVoid, ptVoid, ptSOff, ptSOff, ptSOff, ptSOff, ptSOff, {28} ptSOff, ptSOff, ptSOff, ptSOff, ptSOff, ptSOff, ptSOff, ptSOff, {30} ptLOff, ptLOff, ptLOff, ptLOff, ptLOff, ptLOff, ptLOff, ptLOff, {38} ptLOff, ptLOff, ptLOff, ptLOff, ptLOff, ptVoid, ptVoid, ptVoid, {40} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {48} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {50} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {58} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {60} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptToken, {68} ptToken, ptToken, ptToken, ptToken, ptToken, ptToken, ptVoid, ptVoid, {70} ptVoid, ptToken, ptVoid, ptToken, ptToken, ptToken, ptToken, ptToken, {78} ptToken, ptToken, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {80} ptVoid, ptVoid, ptVoid, ptVoid, ptToken, ptToken, ptVoid, ptToken, {88} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {90} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {98} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {A0} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {A8} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {B0} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {B8} ptVoid, ptVoid, ptToken, ptVoid, ptVoid, ptVoid, ptToken, ptVoid, {C0} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {C8} ptToken, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {D0} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptI4, ptI1, ptVoid, {D8} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {E0} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {E8} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {F0} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, {F8} ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptVoid, ptToken, ptToken, {00} ptVoid, ptU2, ptU2, ptU2, ptU2, ptU2, ptU2, ptVoid, {08} ptVoid, ptVoid, ptI1, ptVoid, ptVoid, ptToken, ptVoid, ptVoid, {10} ptVoid, ptVoid, ptVoid, ptVoid, ptToken, ptVoid, ptVoid, ptVoid, {18} ptVoid, ptVoid, ptVoid); {20} //=== { TJclClrILGenerator } ================================================ constructor TJclClrILGenerator.Create(AMethod: TJclClrMethodBody = nil); var OpCode: Byte; Stream: TMemoryStream; Instruction: TJclInstruction; begin inherited Create; FMethod := AMethod; FInstructions := TObjectList.Create; if Assigned(AMethod) then begin Stream := TMemoryStream.Create; try Stream.Write(Method.Code^, Method.Size); Stream.Seek(0, soFromBeginning); while Stream.Position < Stream.Size do begin OpCode := PByte(Longint(Stream.Memory) + Stream.Position)^; if OpCode = STP1 then begin OpCode := PByte(Longint(Stream.Memory) + Stream.Position + 1)^; Instruction := TJclInstruction.Create(Self, TJclOpCode(MaxByte + 1 + OpCode)); end else Instruction := TJclInstruction.Create(Self, TJclOpCode(OpCode)); if Assigned(Instruction) then begin FInstructions.Add(Instruction); Instruction.Load(Stream); end; end; finally FreeAndNil(Stream); end; end; end; destructor TJclClrILGenerator.Destroy; begin FreeAndNil(FInstructions); inherited Destroy; end; function TJclClrILGenerator.DumpIL(Options: TJclInstructionDumpILOptions): string; var I, J, Indent: Integer; function FlagsToName(Flags: TJclClrExceptionClauseFlags): string; begin if cfFinally in Flags then Result := 'finally' else if cfFilter in Flags then Result := 'filter' else if cfFault in Flags then Result := 'fault' else Result := 'catch'; end; function IndentStr: string; begin Result := StrRepeat(' ', Indent); end; begin Indent := 0; with TStringList.Create do try for I := 0 to InstructionCount-1 do begin for J := 0 to Method.ExceptionHandlerCount-1 do with Method.ExceptionHandlers[J] do begin if Instructions[I].Offset = TryBlock.Offset then begin Add(IndentStr + '.try'); Add(IndentStr + '{'); Inc(Indent); end; if Instructions[I].Offset = (TryBlock.Offset + TryBlock.Length) then begin Dec(Indent); Add(IndentStr + '} // end .try'); end; if Instructions[I].Offset = HandlerBlock.Offset then begin Add(IndentStr + FlagsToName(Flags)); Add(IndentStr + '{'); Inc(Indent); end; if Instructions[I].Offset = (HandlerBlock.Offset + HandlerBlock.Length) then begin Dec(Indent); Add(IndentStr + '} // end ' + FlagsToName(Flags)); end; end; Add(IndentStr + Instructions[I].DumpIL(Options)); end; Result := Text; finally Free; end; end; function TJclClrILGenerator.GetInstructionCount: Integer; begin Result := FInstructions.Count; end; function TJclClrILGenerator.GetInstruction(const Idx: Integer): TJclInstruction; begin Result := TJclInstruction(FInstructions[Idx]); end; //=== { TJclInstruction } ==================================================== constructor TJclInstruction.Create(AOwner :TJclClrILGenerator; AOpCode: TJclOpCode); begin inherited Create; FOwner := AOwner; FOpCode := AOpCode; end; function TJclInstruction.GetWideOpCode: Boolean; begin Result := Integer(OpCode) > MaxByte; end; function TJclInstruction.GetRealOpCode: Byte; begin if WideOpCode then Result := Integer(OpCode) mod (MaxByte + 1) else Result := Integer(OpCode); end; function TJclInstruction.GetParamType: TJclInstructionParamType; begin Result := OpCodeParamTypes[OpCode]; end; function TJclInstruction.GetName: string; begin Result := OpCodeInfos[OpCode, itName]; end; function TJclInstruction.GetFullName: string; begin Result := OpCodeInfos[OpCode, itFullName]; end; function TJclInstruction.GetDescription: string; begin Result := OpCodeInfos[OpCode, itDescription] end; function TJclInstruction.GetSize: DWORD; const OpCodeSize: array [Boolean] of DWORD = (1, 2); begin case ParamType of ptSOff, ptI1, ptU1: Result := SizeOf(Byte); ptI2, ptU2: Result := SizeOf(Word); ptLOff, ptI4, ptToken, ptU4, ptR4: Result := SizeOf(DWORD); ptI8, ptU8, ptR8: Result := SizeOf(Int64); ptArray: Result := (VarArrayHighBound(FParam, 1) - VarArrayLowBound(FParam, 1) + 1 + 1) * SizeOf(Integer); else Result := 0; end; Result := OpCodeSize[OpCode in [opNop..opPrefixRef]] + Result; end; procedure TJclInstruction.Load(Stream: TStream); var Code: Byte; I, ArraySize: DWORD; { TODO : I, ArraySize = DWORD create a serious problem } Value: Integer; begin FOffset := Stream.Position; try Stream.Read(Code, SizeOf(Code)); if WideOpCode then begin if Code <> STP1 then raise EJclCliInstructionStreamInvalid.CreateRes(@RsInstructionStreamInvalid); Stream.Read(Code, SizeOf(Code)); end; if Code <> RealOpCode then raise EJclCliInstructionStreamInvalid.CreateRes(@RsInstructionStreamInvalid); with TVarData(FParam) do case ParamType of ptU1: begin Stream.Read(VByte, SizeOf(Byte)); VType := varByte; end; ptI2: begin Stream.Read(VSmallInt, SizeOf(SmallInt)); VType := varSmallInt; end; ptLOff, ptI4: begin Stream.Read(VInteger, SizeOf(Integer)); VType := varInteger; end; ptR4: begin Stream.Read(VSingle, SizeOf(Single)); VType := varSingle; end; ptR8: begin Stream.Read(VDouble, SizeOf(Double)); VType := varDouble; end; ptArray: begin Stream.Read(ArraySize, SizeOf(ArraySize)); FParam := VarArrayCreate([0, ArraySize-1], varInteger); for I := 0 to ArraySize-1 do { TODO : ArraySize = 0 and we have a nearly endless loop } begin Stream.Read(Value, SizeOf(Value)); FParam[I] := Value; end; end; {$IFDEF RTL140_UP} { TODO -cTest : since RTL 14.0 or 15.0? } ptSOff, ptI1: begin Stream.Read(VShortInt, SizeOf(ShortInt)); VType := varShortInt; end; ptU2: begin Stream.Read(VWord, SizeOf(Word)); VType := varWord; end; ptToken, ptU4: begin Stream.Read(VLongWord, SizeOf(LongWord)); VType := varLongWord; end; ptI8, ptU8: begin Stream.Read(VInt64, SizeOf(Int64)); VType := varInt64; end; {$ENDIF RTL140_UP} end; except Stream.Position := FOffset; raise; end; end; procedure TJclInstruction.Save(Stream: TStream); var Code: Byte; {$IFDEF RTL140_UP} { TODO -cTest : since RTL 14.0 or 15.0? } ArraySize: DWORD; I, Value: Integer; {$ENDIF RTL140_UP} begin if WideOpCode then begin Code := STP1; Stream.Write(Code, SizeOf(Code)); end; Code := RealOpCode;; Stream.Write(Code, SizeOf(Code)); case ParamType of ptU1: Stream.Write(TVarData(FParam).VByte, SizeOf(Byte)); ptI2: Stream.Write(TVarData(FParam).VSmallInt, SizeOf(SmallInt)); ptLOff, ptI4: Stream.Write(TVarData(FParam).VInteger, SizeOf(Integer)); ptR4: Stream.Write(TVarData(FParam).VSingle, SizeOf(Single)); ptR8: Stream.Write(TVarData(FParam).VDouble, SizeOf(Double)); {$IFDEF RTL140_UP} { TODO -cTest : since RTL 14.0 or 15.0? } ptSOff, ptI1: Stream.Write(TVarData(FParam).VShortInt, SizeOf(ShortInt)); ptU2: Stream.Write(TVarData(FParam).VWord, SizeOf(Word)); ptToken, ptU4: Stream.Write(TVarData(FParam).VLongWord, SizeOf(LongWord)); ptI8, ptU8: Stream.Write(TVarData(FParam).VInt64, SizeOf(Int64)); ptArray: begin ArraySize := VarArrayHighBound(FParam, 1) - VarArrayLowBound(FParam, 1) + 1; Stream.Write(ArraySize, SizeOf(ArraySize)); { TODO : VarArrayHighBound to VarArrayLowBound very likely wrong } for I := VarArrayHighBound(FParam, 1) to VarArrayLowBound(FParam, 1) do begin Value := VarArrayGet(FParam, [I]); Stream.Write(Value, SizeOf(Value)); end; end; {$ENDIF RTL140_UP} end; end; function TJclInstruction.DumpIL(Options: TJclInstructionDumpILOptions): string; var Opt: TJclInstructionDumpILOption; begin if doLineNo in Options then Result := DumpILOption(doLineNo) + ': '; if doRawBytes in Options then Result := Result + Format(' /* %.24s */ ', [DumpILOption(doRawBytes)]); for Opt := doIL to doTokenValue do Result := Result + DumpILOption(Opt) + ' '; if (doComment in Options) and ((FullName <> '') or (Description <> '')) then Result := Result + ' // ' + DumpILOption(doComment); end; function TJclInstruction.FormatLabel(Offset: Integer): string; begin Result := 'IL_' + IntToHex(Offset, 4); end; function TJclInstruction.DumpILOption(Option: TJclInstructionDumpILOption): string; function TokenToString(Token: DWORD): string; begin Result := '(' + IntToHex(Token shr 24, 2) + ')' + IntToHex(Token mod (1 shl 24), 6); end; var {$IFDEF RTL140_UP} { TODO -cTest : since RTL 14.0 or 15.0? } I: Integer; Row: TJclClrTableRow; {$ENDIF RTL140_UP} CodeStr, ParamStr: string; begin case Option of doLineNo: Result := 'IL_' + IntToHex(Offset, 4); doRawBytes: begin if WideOpCode then CodeStr := IntToHex(STP1, 2); CodeStr := CodeStr + IntToHex(RealOpCode, 2); CodeStr := CodeStr + StrRepeat(' ', 4 - Length(CodeStr)); case ParamType of ptSOff, ptI1, ptU1: ParamStr := IntToHex(TVarData(FParam).VByte, 2); ptArray: ParamStr := 'Array'; {$IFDEF RTL140_UP} { TODO -cTest : since RTL 14.0 or 15.0? } ptI2, ptU2: ParamStr := IntToHex(TVarData(FParam).VWord, 4); ptLOff, ptI4, ptU4, ptR4: ParamStr := IntToHex(TVarData(FParam).VLongWord, 8); ptI8, ptU8, ptR8: ParamStr := IntToHex(TVarData(FParam).VInt64, 16); ptToken: ParamStr := TokenToString(TVarData(FParam).VLongWord); {$ENDIF RTL140_UP} else ParamStr := ''; end; ParamStr := ParamStr + StrRepeat(' ', 10 - Length(ParamStr)); Result := CodeStr + ' | ' + ParamStr; end; doIL: begin case ParamType of ptVoid: ; // do nothing ptLOff: Result := FormatLabel(Integer(Offset + Size) + TVarData(Param).VInteger - 1); {$IFDEF RTL140_UP} { TODO -cTest : since RTL 14.0 or 15.0? } ptToken: begin if Byte(TJclPeMetadata.TokenTable(TVarData(Param).VLongWord)) = $70 then Result := '"' + Owner.Method.Method.Table.Stream.Metadata.UserStringAt(TJclPeMetadata.TokenIndex(TVarData(Param).VLongWord)) + '"' else begin Row := Owner.Method.Method.Table.Stream.Metadata.Tokens[TVarData(Param).VLongWord]; if Assigned(Row) then begin if Row is TJclClrTableTypeDefRow then Result := TJclClrTableTypeDefRow(Row).FullName else if Row is TJclClrTableTypeRefRow then with TJclClrTableTypeRefRow(Row) do Result := FullName else if Row is TJclClrTableMethodDefRow then with TJclClrTableMethodDefRow(Row) do Result := ParentToken.FullName + '.' + Name else if Row is TJclClrTableMemberRefRow then with TJclClrTableMemberRefRow(Row) do Result := FullName else if Row is TJclClrTableFieldDefRow then with TJclClrTableFieldDefRow(Row) do Result := ParentToken.FullName + '.' + Name else Result := Row.DumpIL; end else Result := ''; end; Result := Result + ' /* ' + IntToHex(TVarData(FParam).VLongWord, 8) + ' */'; end; ptSOff: Result := FormatLabel(Integer(Offset + Size) + TVarData(Param).VShortInt - 1); ptArray: begin for I := VarArrayHighBound(FParam, 1) to VarArrayLowBound(FParam, 1) do begin Result := Result + FormatLabel(Offset + Size + VarArrayGet(FParam, [I])); if I <> VarArrayLowBound(FParam, 1) then Result := Result + ', '; end; Result := ' (' + Result + ')'; end; {$ENDIF RTL140_UP} else Result := VarToStr(Param); end; Result := GetName + StrRepeat(' ', 10 - Length(GetName)) + ' ' + Result; Result := Result + StrRepeat(' ', 20 - Length(Result)); end; doTokenValue: Result := ''; // do nothing doComment: if FullName = '' then Result := Description else if Description = '' then Result := FullName else Result := FullName + ' - ' + Description; end; end; // History: // $Log: JclCIL.pas,v $ // Revision 1.15 2005/05/08 08:05:53 outchy // Warning suppression, DWORD (Cardinal) changed to Integer // // Revision 1.14 2005/03/14 02:13:13 rrossmair // - fixed JclCLR identifier case // // Revision 1.13 2005/03/08 08:33:22 marquardt // overhaul of exceptions and resourcestrings, minor style cleaning // // Revision 1.12 2005/03/07 17:27:58 marquardt // reworked for resorucestrings // // Revision 1.11 2005/02/27 14:55:26 marquardt // changed overloaded constructors to constructor with default parameter (BCB friendly) // // Revision 1.10 2005/02/24 16:34:52 marquardt // remove divider lines, add section lines (unfinished) // // Revision 1.9 2004/10/17 21:00:14 mthoma // cleaning // // Revision 1.8 2004/08/03 17:13:28 marquardt // make duplicate string literals constants // // Revision 1.7 2004/06/14 13:05:21 marquardt // style cleaning ENDIF, Tabs // // Revision 1.6 2004/05/05 07:33:49 rrossmair // header updated according to new policy: initial developers & contributors listed // // Revision 1.5 2004/04/06 04:55:17 // adapt compiler conditions, add log entry // end.