summaryrefslogtreecommitdiffstats
path: root/src/VBox/Disassembler/DisasmMisc.cpp
blob: 16d90e8d43e0582c77f5acad2002e9502e435501 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/* $Id: DisasmMisc.cpp $ */
/** @file
 * VBox disassembler- Misc Helpers.
 */

/*
 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * 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, in version 3 of the
 * License.
 *
 * 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, see <https://www.gnu.org/licenses>.
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */


/*********************************************************************************************************************************
*   Header Files                                                                                                                 *
*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DIS
#include <VBox/dis.h>
#include <VBox/disopcode.h>
#include <iprt/errcore.h>
#include <VBox/log.h>
#include <VBox/vmm/cpum.h>
#include <iprt/assert.h>
#include <iprt/string.h>
#include <iprt/stdarg.h>
#include "DisasmInternal.h"


DISDECL(uint8_t) DISGetParamSize(PCDISSTATE pDis, PCDISOPPARAM pParam)
{
    unsigned subtype = OP_PARM_VSUBTYPE(pParam->fParam);
    switch (subtype)
    {
        case OP_PARM_v:
            switch (pDis->uOpMode)
            {
                case DISCPUMODE_32BIT:
                    return 4;
                case DISCPUMODE_64BIT:
                    return 8;
                case DISCPUMODE_16BIT:
                    return 2;
                default: AssertFailed(); /* make gcc happy */ return 4;
            }
            break;

        case OP_PARM_b:
            return 1;

        case OP_PARM_w:
            return 2;

        case OP_PARM_d:
            return 4;

        case OP_PARM_q:
            return 8;

        case OP_PARM_dq:
            return 16;

        case OP_PARM_qq:
            return 32;

        case 0: /* nop, pause, lea, wrmsr, rdmsr, etc.  Most of these due to DISOPPARAM::cb being initialized in the wrong place
                   (disParseInstruction) where it will be called on intermediate stuff like IDX_ParseTwoByteEsc.  The parameter
                   parsers should do it instead, though I see the potential filtering issue. */
            //Assert(   pDis->pCurInstr
            //       && (   pDis->pCurInstr->uOpcode == OP_NOP
            //           || pDis->pCurInstr->uOpcode == OP_LEA ));
            return 0;

        case OP_PARM_p: /* far pointer */
            if (pDis->uAddrMode == DISCPUMODE_32BIT)
                return 6;   /* 16:32 */
            if (pDis->uAddrMode == DISCPUMODE_64BIT)
                return 12;  /* 16:64 */
            return 4;       /* 16:16 */

        case OP_PARM_s: /* lgdt, sgdt, lidt, sidt */
            return pDis->uCpuMode == DISCPUMODE_64BIT ? 2 + 8 : 2 + 4;

        case OP_PARM_a:
            return pDis->uOpMode == DISCPUMODE_16BIT ? 2 + 2 : 4 + 4;

        case OP_PARM_pi:
            return 8;

        case OP_PARM_sd:
        case OP_PARM_ss:
            return 16;

        case OP_PARM_x:
        case OP_PARM_pd:
        case OP_PARM_ps:
            return VEXREG_IS256B(pDis->bVexDestReg) ? 32 : 16; //??

        case OP_PARM_y:
            return pDis->uOpMode == DISCPUMODE_64BIT ? 4 : 8;  //??

        case OP_PARM_z:
            if (pParam->cb)
                return pParam->cb;
            return pDis->uOpMode == DISCPUMODE_16BIT ? 2 : 4;  //??

        default:
            if (pParam->cb)
                return pParam->cb;
            /// @todo dangerous!!!
            AssertMsgFailed(("subtype=%#x fParam=%#x fUse=%#RX64 op=%#x\n", subtype, pParam->fParam, pParam->fUse,
                             pDis->pCurInstr ? pDis->pCurInstr->uOpcode : 0));
            return 4;
    }
}

#if 0 /* currently unused */
DISDECL(DISSELREG) DISDetectSegReg(PCDISSTATE pDis, PCDISOPPARAM pParam)
{
    if (pDis->fPrefix & DISPREFIX_SEG)
        /* Use specified SEG: prefix. */
        return (DISSELREG)pDis->idxSegPrefix;

    /* Guess segment register by parameter type. */
    if (pParam->fUse & (DISUSE_REG_GEN32|DISUSE_REG_GEN64|DISUSE_REG_GEN16))
    {
        AssertCompile(DISGREG_ESP == DISGREG_RSP);
        AssertCompile(DISGREG_EBP == DISGREG_RBP);
        AssertCompile(DISGREG_ESP == DISGREG_SP);
        AssertCompile(DISGREG_EBP == DISGREG_BP);
        if (pParam->Base.idxGenReg == DISGREG_ESP || pParam->Base.idxGenReg == DISGREG_EBP)
            return DISSELREG_SS;
    }
    /* Default is use DS: for data access. */
    return DISSELREG_DS;
}


DISDECL(uint8_t) DISQuerySegPrefixByte(PCDISSTATE pDis)
{
    Assert(pDis->fPrefix & DISPREFIX_SEG);
    switch (pDis->idxSegPrefix)
    {
    case DISSELREG_ES:
        return 0x26;
    case DISSELREG_CS:
        return 0x2E;
    case DISSELREG_SS:
        return 0x36;
    case DISSELREG_DS:
        return 0x3E;
    case DISSELREG_FS:
        return 0x64;
    case DISSELREG_GS:
        return 0x65;
    default:
        AssertFailed();
        return 0;
    }
}
#endif