VirtualBox

Changeset 66124 in vbox


Ignore:
Timestamp:
Mar 16, 2017 1:34:53 PM (8 years ago)
Author:
vboxsync
Message:

bs3-cpu-generated-1,IEM: More tests, fixed rAX,Iz testing bug.

Location:
trunk/src/VBox
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsOneByte.cpp.h

    r66116 r66124  
    5252 * @opstats     add_Eb_Gb
    5353 * @opgroup     op_gen_arith_bin
    54  * @optest              op1=1   op2=1   -> op1=2   efl&|=nv,pl,nz,na,pe,nc
    55  * @optest      efl|=cf op1=1   op2=2   -> op1=3   efl&|=nv,pl,nz,na,po,nc
    56  * @optest              op1=254 op2=1   -> op1=255 efl&|=nv,ng,nz,na,po,nc
     54 * @optest              op1=1   op2=1   -> op1=2   efl&|=nc,pe,na,nz,pl,nv
     55 * @optest      efl|=cf op1=1   op2=2   -> op1=3   efl&|=nc,po,na,nz,pl,nv
     56 * @optest              op1=254 op2=1   -> op1=255 efl&|=nc,po,na,nz,ng,nv
    5757 * @optest              op1=128 op2=128 -> op1=0   efl&|=ov,pl,zf,na,po,cf
    5858 */
     
    6868 * @opgroup     op_gen_arith_bin
    6969 * @opflmodify  of,sf,zf,af,pf,cf
     70 * @optest               op1=1  op2=1  -> op1=2  efl&|=nc,pe,na,nz,pl,nv
     71 * @optest      efl|=cf  op1=2  op2=2  -> op1=4  efl&|=nc,pe,na,nz,pl,nv
     72 * @optest      efl&~=cf op1=-1 op2=1  -> op1=0  efl&|=cf,po,af,zf,pl,nv
     73 * @optest               op1=-1 op2=-1 -> op1=-2 efl&|=cf,pe,af,nz,ng,nv
    7074 */
    7175FNIEMOP_DEF(iemOp_add_Ev_Gv)
     
    8084 * @opgroup     op_gen_arith_bin
    8185 * @opflmodify  of,sf,zf,af,pf,cf
    82  * @opcopytests add_Eb_Gb
     86 * @opcopytests iemOp_add_Eb_Gb
    8387 */
    8488FNIEMOP_DEF(iemOp_add_Gb_Eb)
     
    9397 * @opgroup     op_gen_arith_bin
    9498 * @opflmodify  of,sf,zf,af,pf,cf
     99 * @opcopytests iemOp_add_Ev_Gv
    95100 */
    96101FNIEMOP_DEF(iemOp_add_Gv_Ev)
     
    105110 * @opgroup     op_gen_arith_bin
    106111 * @opflmodify  of,sf,zf,af,pf,cf
    107  * @opcopytests add_Eb_Gb
     112 * @opcopytests iemOp_add_Eb_Gb
    108113 */
    109114FNIEMOP_DEF(iemOp_add_Al_Ib)
     
    119124 * @opflmodify  of,sf,zf,af,pf,cf
    120125 * @optest      op1=1 op2=1 -> op1=2 efl&|=nv,pl,nz,na,pe
     126 * @optest      efl|=cf  op1=2  op2=2  -> op1=4  efl&|=nc,pe,na,nz,pl,nv
     127 * @optest      efl&~=cf op1=-1 op2=1  -> op1=0  efl&|=cf,po,af,zf,pl,nv
     128 * @optest               op1=-1 op2=-1 -> op1=-2 efl&|=cf,pe,af,nz,ng,nv
    121129 */
    122130FNIEMOP_DEF(iemOp_add_eAX_Iz)
  • trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsPython.py

    r66114 r66124  
    7878## EFlags values allowed in \@opfltest, \@opflmodify, \@opflundef, \@opflset, and \@opflclear.
    7979g_kdEFlagsMnemonics = {
    80     # Debugger flag notation:
     80    # Debugger flag notation (sorted by value):
     81    'cf':   'X86_EFL_CF',   ##< Carry Flag.
     82    'nc':  '!X86_EFL_CF',   ##< No Carry.
     83
     84    'po':   'X86_EFL_PF',   ##< Parity Pdd.
     85    'pe':  '!X86_EFL_PF',   ##< Parity Even.
     86
     87    'af':   'X86_EFL_AF',   ##< Aux Flag.
     88    'na':  '!X86_EFL_AF',   ##< No Aux.
     89
     90    'zr':   'X86_EFL_ZF',   ##< ZeRo.
     91    'nz':  '!X86_EFL_ZF',   ##< No Zero.
     92
     93    'ng':   'X86_EFL_SF',   ##< NeGative (sign).
     94    'pl':  '!X86_EFL_SF',   ##< PLuss (sign).
     95
     96    'tf':   'X86_EFL_TF',   ##< Trap flag.
     97
     98    'ei':   'X86_EFL_IF',   ##< Enabled Interrupts.
     99    'di':  '!X86_EFL_IF',   ##< Disabled Interrupts.
     100
     101    'dn':   'X86_EFL_DF',   ##< DowN (string op direction).
     102    'up':  '!X86_EFL_DF',   ##< UP (string op direction).
     103
    81104    'ov':   'X86_EFL_OF',   ##< OVerflow.
    82105    'nv':  '!X86_EFL_OF',   ##< No Overflow.
    83106
    84     'ng':   'X86_EFL_SF',   ##< NeGative (sign).
    85     'pl':  '!X86_EFL_SF',   ##< PLuss (sign).
    86 
    87     'zr':   'X86_EFL_ZF',   ##< ZeRo.
    88     'nz':  '!X86_EFL_ZF',   ##< No Zero.
    89 
    90     'af':   'X86_EFL_AF',   ##< Aux Flag.
    91     'na':  '!X86_EFL_AF',   ##< No Aux.
    92 
    93     'po':   'X86_EFL_PF',   ##< Parity Pdd.
    94     'pe':  '!X86_EFL_PF',   ##< Parity Even.
    95 
    96     'cf':   'X86_EFL_CF',   ##< Carry Flag.
    97     'nc':  '!X86_EFL_CF',   ##< No Carry.
    98 
    99     'ei':   'X86_EFL_IF',   ##< Enabled Interrupts.
    100     'di':  '!X86_EFL_IF',   ##< Disabled Interrupts.
    101 
    102     'dn':   'X86_EFL_DF',   ##< DowN (string op direction).
    103     'up':  '!X86_EFL_DF',   ##< UP (string op direction).
    104 
     107    'nt':   'X86_EFL_NT',   ##< Nested Task.
     108    'rf':   'X86_EFL_RF',   ##< Resume Flag.
     109    'vm':   'X86_EFL_VM',   ##< Virtual-8086 Mode.
     110    'ac':   'X86_EFL_AC',   ##< Alignment Check.
     111    'vif':  'X86_EFL_VIF',  ##< Virtual Interrupt Flag.
    105112    'vip':  'X86_EFL_VIP',  ##< Virtual Interrupt Pending.
    106     'vif':  'X86_EFL_VIF',  ##< Virtual Interrupt Flag.
    107     'ac':   'X86_EFL_AC',   ##< Alignment Check.
    108     'vm':   'X86_EFL_VM',   ##< Virtual-8086 Mode.
    109     'rf':   'X86_EFL_RF',   ##< Resume Flag.
    110     'nt':   'X86_EFL_NT',   ##< Nested Task.
    111     'tf':   'X86_EFL_TF',   ##< Trap flag.
    112 
    113     # Reference manual notation:
    114     'of':   'X86_EFL_OF',
     113
     114    # Reference manual notation not covered above (sorted by value):
     115    'pf':   'X86_EFL_PF',
     116    'zf':   'X86_EFL_ZF',
    115117    'sf':   'X86_EFL_SF',
    116     'zf':   'X86_EFL_ZF',
    117     'pf':   'X86_EFL_PF',
    118118    'if':   'X86_EFL_IF',
    119119    'df':   'X86_EFL_DF',
     120    'of':   'X86_EFL_OF',
    120121    'iopl': 'X86_EFL_IOPL',
    121122    'id':   'X86_EFL_ID',
     
    585586        if cDigits <= self.acbSizes[-1] * 2:
    586587            for cb in self.acbSizes:
    587                 if cDigits <= cb * 2:
    588                     cDigits = int((cDigits + cb - 1) / cb) * cb; # Seems like integer division returns a float in python.
     588                cNaturalDigits = cb * 2;
     589                if cDigits <= cNaturalDigits:
    589590                    break;
    590591        else:
    591             cDigits = int((cDigits + self.acbSizes[-1] - 1) / self.acbSizes[-1]) * self.acbSizes[-1];
    592             assert isinstance(cDigits, int)
    593 
    594         if cDigits != len(sHex):
    595             cNeeded = cDigits - len(sHex);
     592            cNaturalDigits = self.acbSizes[-1] * 2;
     593            cNaturalDigits = int((cDigits + cNaturalDigits - 1) / cNaturalDigits) * cNaturalDigits;
     594            assert isinstance(cNaturalDigits, int)
     595
     596        if cNaturalDigits != cDigits:
     597            cNeeded = cNaturalDigits - cDigits;
    596598            if iValue >= 0:
    597599                sHex = ('0' * cNeeded) + sHex;
     
    873875    def __init__(self, oInstr): # type: (InstructionTest, Instruction)
    874876        self.oInstr         = oInstr;   # type: InstructionTest
    875         self.aoInputs       = [];       # type: TestInOut
    876         self.aoOutputs      = [];       # type: TestInOut
     877        self.aoInputs       = [];       # type: list(TestInOut)
     878        self.aoOutputs      = [];       # type: list(TestInOut)
    877879        self.aoSelectors    = [];       # type: list(TestSelector)
    878880
     881    def toString(self, fRepr = False):
     882        """
     883        Converts it to string representation.
     884        """
     885        asWords = [];
     886        if self.aoSelectors:
     887            for oSelector in self.aoSelectors:
     888                asWords.append('%s%s%s' % (oSelector.sVariable, oSelector.sOp, oSelector.sValue,));
     889            asWords.append('/');
     890
     891        for oModifier in self.aoInputs:
     892            asWords.append('%s%s%s:%s' % (oModifier.sField, oModifier.sOp, oModifier.sValue, oModifier.sType,));
     893
     894        asWords.append('->');
     895
     896        for oModifier in self.aoOutputs:
     897            asWords.append('%s%s%s:%s' % (oModifier.sField, oModifier.sOp, oModifier.sValue, oModifier.sType,));
     898
     899        if fRepr:
     900            return '<' + ' '.join(asWords) + '>';
     901        return '  '.join(asWords);
     902
     903    def __str__(self):
     904        """ Provide string represenation. """
     905        return self.toString(False);
     906
     907    def __repr__(self):
     908        """ Provide unambigious string representation. """
     909        return self.toString(True);
    879910
    880911class Operand(object):
     
    10601091
    10611092## All the instructions.
    1062 g_aoAllInstructions = []; # type: Instruction
     1093g_aoAllInstructions = []; # type: list(Instruction)
    10631094
    10641095## All the instructions indexed by statistics name (opstat).
    1065 g_dAllInstructionsByStat = {}; # type: Instruction
     1096g_dAllInstructionsByStat = {}; # type: dict(Instruction)
     1097
     1098## All the instructions indexed by function name (opfunction).
     1099g_dAllInstructionsByFunction = {}; # type: dict(list(Instruction))
     1100
     1101## Instructions tagged by oponlytest
     1102g_aoOnlyTestInstructions = []; # type: list(Instruction)
    10661103
    10671104## Instruction maps.
     
    11941231            '@opinvlstyle': self.parseTagOpUnusedInvalid,
    11951232            '@optest':      self.parseTagOpTest,
     1233            '@optestign':   self.parseTagOpTestIgnore,
     1234            '@optestignore': self.parseTagOpTestIgnore,
    11961235            '@opcopytests': self.parseTagOpCopyTests,
     1236            '@oponlytest':  self.parseTagOpOnlyTest,
    11971237            '@opstats':     self.parseTagOpStats,
    11981238            '@opfunction':  self.parseTagOpFunction,
     
    13591399                self.error('Duplicate opstat value "%s"\nnew: %s\nold: %s'
    13601400                           % (oInstr.sStats, oInstr, g_dAllInstructionsByStat[oInstr.sStats],));
     1401
     1402        #
     1403        # Add to function indexed dictionary.  We allow multiple instructions per function.
     1404        #
     1405        if oInstr.sFunction:
     1406            if oInstr.sFunction not in g_dAllInstructionsByFunction:
     1407                g_dAllInstructionsByFunction[oInstr.sFunction] = [oInstr,];
     1408            else:
     1409                g_dAllInstructionsByFunction[oInstr.sFunction].append(oInstr);
    13611410
    13621411        #self.debug('%d..%d: %s; %d @op tags' % (oInstr.iLineCreated, oInstr.iLineCompleted, oInstr.sFunction, oInstr.cOpTags));
     
    20752124        return True;
    20762125
     2126    def parseTagOpTestIgnore(self, sTag, aasSections, iTagLine, iEndLine):
     2127        """
     2128        Tag:        \@optestign | \@optestignore
     2129        Value:      <value is ignored>
     2130
     2131        This is a simple trick to ignore a test while debugging another.
     2132
     2133        See also \@oponlytest.
     2134        """
     2135        _ = sTag; _ = aasSections; _ = iTagLine; _ = iEndLine;
     2136        return True;
     2137
    20772138    def parseTagOpCopyTests(self, sTag, aasSections, iTagLine, iEndLine):
    20782139        """
    20792140        Tag:        \@opcopytests
    2080         Value:      <opstat value> [..]
     2141        Value:      <opstat | function> [..]
    20812142        Example:    \@opcopytests add_Eb_Gb
    20822143
     
    20932154        for sToCopy in asToCopy:
    20942155            if sToCopy not in oInstr.asCopyTests:
    2095                 if self.oReStatsName.match(sToCopy):
     2156                if self.oReStatsName.match(sToCopy) or self.oReFunctionName.match(sToCopy):
    20962157                    oInstr.asCopyTests.append(sToCopy);
    20972158                else:
    2098                     self.errorComment(iTagLine, '%s: invalid instruction reference (opstat) "%s" (valid: %s)'
    2099                                                 % (sTag, sToCopy, self.oReStatsName.pattern));
     2159                    self.errorComment(iTagLine, '%s: invalid instruction reference (opstat or function) "%s" (valid: %s or %s)'
     2160                                                % (sTag, sToCopy, self.oReStatsName.pattern, self.oReFunctionName.pattern));
    21002161            else:
    21012162                self.errorComment(iTagLine, '%s: ignoring duplicate "%s"' % (sTag, sToCopy,));
     2163
     2164        _ = iEndLine;
     2165        return True;
     2166
     2167    def parseTagOpOnlyTest(self, sTag, aasSections, iTagLine, iEndLine):
     2168        """
     2169        Tag:        \@oponlytest
     2170        Value:      none
     2171
     2172        Only test instructions with this tag.  This is a trick that is handy
     2173        for singling out one or two new instructions or tests.
     2174
     2175        See also \@optestignore.
     2176        """
     2177        oInstr = self.ensureInstructionForOpTag(iTagLine);
     2178
     2179        # Validate and add instruction to only test dictionary.
     2180        sValue = self.flattenAllSections(aasSections).strip();
     2181        if sValue:
     2182            return self.errorComment(iTagLine, '%s: does not take any value: %s' % (sTag, sValue));
     2183
     2184        if oInstr not in g_aoOnlyTestInstructions:
     2185            g_aoOnlyTestInstructions.append(oInstr);
    21022186
    21032187        _ = iEndLine;
     
    26662750            for sSrcInstr in oDstInstr.asCopyTests:
    26672751                oSrcInstr = g_dAllInstructionsByStat.get(sSrcInstr, None);
    2668                 if oSrcInstr and oSrcInstr != oDstInstr:
    2669                     oDstInstr.aoTests.extend(oSrcInstr.aoTests);
    2670                 elif oSrcInstr:
    2671                     asErrors.append('%s:%s: error: @opcopytests reference "%s" matches the destination\n'
    2672                                     % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
     2752                if oSrcInstr:
     2753                    aoSrcInstrs = [oSrcInstr,];
     2754                else:
     2755                    aoSrcInstrs = g_dAllInstructionsByFunction.get(sSrcInstr, []);
     2756                if aoSrcInstrs:
     2757                    for oSrcInstr in aoSrcInstrs:
     2758                        if oSrcInstr != oDstInstr:
     2759                            oDstInstr.aoTests.extend(oSrcInstr.aoTests);
     2760                        else:
     2761                            asErrors.append('%s:%s: error: @opcopytests reference "%s" matches the destination\n'
     2762                                            % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
    26732763                else:
    26742764                    asErrors.append('%s:%s: error: @opcopytests reference "%s" not found\n'
     
    26792769    return len(asErrors);
    26802770
     2771
     2772def __applyOnlyTest():
     2773    """
     2774    If g_aoOnlyTestInstructions contains any instructions, drop aoTests from
     2775    all other instructions so that only these get tested.
     2776    """
     2777    if g_aoOnlyTestInstructions:
     2778        for oInstr in g_aoAllInstructions:
     2779            if oInstr.aoTests:
     2780                if oInstr not in g_aoOnlyTestInstructions:
     2781                    oInstr.aoTests = [];
     2782    return 0;
    26812783
    26822784def __parseAll():
     
    26942796        cErrors += __parseFileByName(os.path.join(sSrcDir, sName), sDefaultMap);
    26952797    cErrors += __doTestCopying();
    2696 
     2798    cErrors += __applyOnlyTest();
    26972799
    26982800    if cErrors != 0:
  • trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-data.py

    r66114 r66124  
    7373            sConstant = oSelector.kdVariables[oSelector.sVariable][oSelector.sValue];
    7474            sConstant = sConstant.upper().replace('.', '_');
    75             if oSelector.sValue.sOp == '==':
     75            if oSelector.sOp == '==':
    7676                sByte = '(BS3CG1PRED_%s << BS3CG1SEL_OP_PRED_SHIFT) | BS3CG1SEL_OP_IS_TRUE' % (sConstant,);
    77             elif oSelector.sValue.sOp == '!=':
     77            elif oSelector.sOp == '!=':
    7878                sByte = '(BS3CG1PRED_%s << BS3CG1SEL_OP_PRED_SHIFT) | BS3CG1SEL_OP_IS_FALSE' % (sConstant,);
    7979            else:
     
    167167                    sOpcode += 'BS3CG1_CTXOP_SIZE_ESC';
    168168                if fSignExtend:
    169                     sOpcode += '| BS3CG1_CTXOP_SIGN_EXT';
     169                    sOpcode += ' | BS3CG1_CTXOP_SIGN_EXT';
    170170                asRet.append(sOpcode);
    171171
     
    227227
    228228    def __init__(self, oInstr):
    229         self.offTests = -1;
    230         self.cbTests  = 0;
    231         self.asLines  = [];
     229        self.offTests       = -1;
     230        self.cbTests        = 0;
     231        self.asLines        = [];       # type: list(str)
     232        self.aoInstructions = [];       # type: list(iai.Instruction)
    232233
    233234        # Encode the tests.
     
    239240                          + len(oEncodedTest.asInputs) + len(oEncodedTest.asOutputs);
    240241
    241             self.asLines += self.bytesToLines('    /*hdr:*/ ', oEncodedTest.asHdr);
     242            self.asLines.append('    /* test #%s: %s */' % (iTest, oTest,));
     243            self.asLines += self.bytesToLines('             ', oEncodedTest.asHdr);
    242244            if oEncodedTest.asSelectors:
    243245                self.asLines += self.bytesToLines('    /*sel:*/ ', oEncodedTest.asSelectors);
     
    342344        self.cbTests        = 0;
    343345
    344     def addTests(self, oTests):
     346    def addTests(self, oTests, oInstr): # type: (Bs3Cg1EncodedTests, iai.Instruction) -> Bs3Cg1EncodedTests
    345347        """
    346348        Adds oTests to self.aoTests, setting the oTests.offTests member.
     
    351353        for oExisting in self.aoTests:
    352354            if oTests.isEqual(oExisting):
     355                oExisting.aoInstructions.append(oInstr);
    353356                return oExisting;
    354357
     
    357360        self.aoTests.append(oTests);
    358361        self.cbTests   += oTests.cbTests;
     362
     363        assert not oTests.aoInstructions;
     364        oTests.aoInstructions.append(oInstr);
    359365
    360366        return oTests;
     
    374380            if oInstr.aoTests:
    375381                oTests = Bs3Cg1EncodedTests(oInstr);
    376                 oTests = self.addTests(oTests);
     382                oTests = self.addTests(oTests, oInstr);
    377383
    378384                for oMap in oInstr.aoMaps:
     
    491497        ];
    492498        for oTests in self.aoTests:
    493             asLines.append('    /* offTests=%s */' % (oTests.offTests,));
     499            asLines.append('    /*');
     500            asLines.append('     * offTests=%s' % (oTests.offTests,));
     501            asLines.append('     * Instructions: %s' % (', '.join([oInstr.sStats for oInstr in oTests.aoInstructions]),));
     502            asLines.append('     */');
    494503            asLines += oTests.asLines;
    495504        asLines += [
  • trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-template.c

    r66123 r66124  
    7575 * Debug print macro.
    7676 */
    77 #if 1
     77#if 0
    7878# define BS3CG1_DPRINTF(a_ArgList) Bs3TestPrintf a_ArgList
    79 //# define BS3CG1_DEBUG_CTX_MOD
     79# define BS3CG1_DEBUG_CTX_MOD
    8080#else
    8181# define BS3CG1_DPRINTF(a_ArgList) do { } while (0)
     
    698698                    pThis->aOperands[0].cbOp = 4;
    699699                    pThis->aOperands[1].cbOp = 4;
    700                     pThis->cbOperand         = 2;
     700                    pThis->cbOperand         = 4;
    701701                }
    702702            }
     
    13391339            if (iEncodingNext <= iEncoding)
    13401340                break;
    1341             BS3CG1_DPRINTF(("\ndbg: Encoding #%u: cbCurInst=%u %.*Rhxs\n", iEncoding, This.cbCurInstr, This.cbCurInstr, This.abCurInstr));
     1341            BS3CG1_DPRINTF(("\ndbg: Encoding #%u: cbCurInst=%u: %.*Rhxs\n", iEncoding, This.cbCurInstr, This.cbCurInstr, This.abCurInstr));
    13421342
    13431343            /*
     
    13951395                                                             &This.TrapFrame.Ctx, NULL /*pbCode*/))
    13961396                                {
    1397                                     Bs3TestCheckRegCtxEx(&This.TrapFrame.Ctx, &This.Ctx, This.cbCurInstr,  0 /*cbSpAdjust*/,
    1398                                                          0 /*fExtraEfl*/, pszMode, iEncoding);
     1397                                    if (!Bs3TestCheckRegCtxEx(&This.TrapFrame.Ctx, &This.Ctx, This.cbCurInstr,  0 /*cbSpAdjust*/,
     1398                                                              0 /*fExtraEfl*/, pszMode, iEncoding))
     1399                                        Bs3TestFailedF("encoding#%u: %.*Rhxs", iEncoding, This.cbCurInstr, This.abCurInstr);
    13991400                                }
    14001401                            }
    14011402                            else
    14021403                            {
    1403                                 Bs3TestFailedF("bXcpt=%#x expected %#x; rip=%RX64 expected %RX64; encoding: %.*Rhxs",
     1404                                Bs3TestFailedF("bXcpt=%#x expected %#x; rip=%RX64 expected %RX64; encoding#u: %.*Rhxs",
    14041405                                               This.TrapFrame.bXcpt, BS3_MODE_IS_PAGED(bMode) ? X86_XCPT_PF : X86_XCPT_UD,
    14051406                                               This.TrapFrame.Ctx.rip.u, This.Ctx.rip.u + This.cbCurInstr,
    1406                                                This.cbCurInstr, This.abCurInstr);
     1407                                               iEncoding, This.cbCurInstr, This.abCurInstr);
    14071408                            }
    14081409                        }
     
    14141415                    if (pHdr->fLast)
    14151416                    {
    1416                         BS3CG1_DPRINTF(("dbg:  Last\n"));
     1417                        BS3CG1_DPRINTF(("dbg:  Last\n\n"));
    14171418                        break;
    14181419                    }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette