root / target-i386 / gdbstub.c @ 3523e4bd
History | View | Annotate | Download (7.8 kB)
1 | f20f9df0 | Andreas Färber | /*
|
---|---|---|---|
2 | f20f9df0 | Andreas Färber | * x86 gdb server stub
|
3 | f20f9df0 | Andreas Färber | *
|
4 | f20f9df0 | Andreas Färber | * Copyright (c) 2003-2005 Fabrice Bellard
|
5 | f20f9df0 | Andreas Färber | * Copyright (c) 2013 SUSE LINUX Products GmbH
|
6 | f20f9df0 | Andreas Färber | *
|
7 | f20f9df0 | Andreas Färber | * This library is free software; you can redistribute it and/or
|
8 | f20f9df0 | Andreas Färber | * modify it under the terms of the GNU Lesser General Public
|
9 | f20f9df0 | Andreas Färber | * License as published by the Free Software Foundation; either
|
10 | f20f9df0 | Andreas Färber | * version 2 of the License, or (at your option) any later version.
|
11 | f20f9df0 | Andreas Färber | *
|
12 | f20f9df0 | Andreas Färber | * This library is distributed in the hope that it will be useful,
|
13 | f20f9df0 | Andreas Färber | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | f20f9df0 | Andreas Färber | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 | f20f9df0 | Andreas Färber | * Lesser General Public License for more details.
|
16 | f20f9df0 | Andreas Färber | *
|
17 | f20f9df0 | Andreas Färber | * You should have received a copy of the GNU Lesser General Public
|
18 | f20f9df0 | Andreas Färber | * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
19 | f20f9df0 | Andreas Färber | */
|
20 | 5b50e790 | Andreas Färber | #include "config.h" |
21 | 5b50e790 | Andreas Färber | #include "qemu-common.h" |
22 | 5b50e790 | Andreas Färber | #include "exec/gdbstub.h" |
23 | f20f9df0 | Andreas Färber | |
24 | f20f9df0 | Andreas Färber | #ifdef TARGET_X86_64
|
25 | f20f9df0 | Andreas Färber | static const int gpr_map[16] = { |
26 | f20f9df0 | Andreas Färber | R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP, |
27 | f20f9df0 | Andreas Färber | 8, 9, 10, 11, 12, 13, 14, 15 |
28 | f20f9df0 | Andreas Färber | }; |
29 | f20f9df0 | Andreas Färber | #else
|
30 | f20f9df0 | Andreas Färber | #define gpr_map gpr_map32
|
31 | f20f9df0 | Andreas Färber | #endif
|
32 | f20f9df0 | Andreas Färber | static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; |
33 | f20f9df0 | Andreas Färber | |
34 | f20f9df0 | Andreas Färber | #define IDX_IP_REG CPU_NB_REGS
|
35 | f20f9df0 | Andreas Färber | #define IDX_FLAGS_REG (IDX_IP_REG + 1) |
36 | f20f9df0 | Andreas Färber | #define IDX_SEG_REGS (IDX_FLAGS_REG + 1) |
37 | f20f9df0 | Andreas Färber | #define IDX_FP_REGS (IDX_SEG_REGS + 6) |
38 | f20f9df0 | Andreas Färber | #define IDX_XMM_REGS (IDX_FP_REGS + 16) |
39 | f20f9df0 | Andreas Färber | #define IDX_MXCSR_REG (IDX_XMM_REGS + CPU_NB_REGS)
|
40 | f20f9df0 | Andreas Färber | |
41 | 5b50e790 | Andreas Färber | int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) |
42 | f20f9df0 | Andreas Färber | { |
43 | 5b50e790 | Andreas Färber | X86CPU *cpu = X86_CPU(cs); |
44 | 5b50e790 | Andreas Färber | CPUX86State *env = &cpu->env; |
45 | 5b50e790 | Andreas Färber | |
46 | f20f9df0 | Andreas Färber | if (n < CPU_NB_REGS) {
|
47 | f20f9df0 | Andreas Färber | if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { |
48 | 986a2998 | Andreas Färber | return gdb_get_reg64(mem_buf, env->regs[gpr_map[n]]);
|
49 | f20f9df0 | Andreas Färber | } else if (n < CPU_NB_REGS32) { |
50 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]);
|
51 | f20f9df0 | Andreas Färber | } |
52 | f20f9df0 | Andreas Färber | } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) { |
53 | f20f9df0 | Andreas Färber | #ifdef USE_X86LDOUBLE
|
54 | f20f9df0 | Andreas Färber | /* FIXME: byteswap float values - after fixing fpregs layout. */
|
55 | f20f9df0 | Andreas Färber | memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10);
|
56 | f20f9df0 | Andreas Färber | #else
|
57 | f20f9df0 | Andreas Färber | memset(mem_buf, 0, 10); |
58 | f20f9df0 | Andreas Färber | #endif
|
59 | f20f9df0 | Andreas Färber | return 10; |
60 | f20f9df0 | Andreas Färber | } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) { |
61 | f20f9df0 | Andreas Färber | n -= IDX_XMM_REGS; |
62 | f20f9df0 | Andreas Färber | if (n < CPU_NB_REGS32 ||
|
63 | f20f9df0 | Andreas Färber | (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
|
64 | f20f9df0 | Andreas Färber | stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0));
|
65 | f20f9df0 | Andreas Färber | stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1)); |
66 | f20f9df0 | Andreas Färber | return 16; |
67 | f20f9df0 | Andreas Färber | } |
68 | f20f9df0 | Andreas Färber | } else {
|
69 | f20f9df0 | Andreas Färber | switch (n) {
|
70 | f20f9df0 | Andreas Färber | case IDX_IP_REG:
|
71 | f20f9df0 | Andreas Färber | if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { |
72 | 986a2998 | Andreas Färber | return gdb_get_reg64(mem_buf, env->eip);
|
73 | f20f9df0 | Andreas Färber | } else {
|
74 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->eip);
|
75 | f20f9df0 | Andreas Färber | } |
76 | f20f9df0 | Andreas Färber | case IDX_FLAGS_REG:
|
77 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->eflags);
|
78 | f20f9df0 | Andreas Färber | |
79 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS:
|
80 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->segs[R_CS].selector);
|
81 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS + 1: |
82 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->segs[R_SS].selector);
|
83 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS + 2: |
84 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->segs[R_DS].selector);
|
85 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS + 3: |
86 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->segs[R_ES].selector);
|
87 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS + 4: |
88 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->segs[R_FS].selector);
|
89 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS + 5: |
90 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->segs[R_GS].selector);
|
91 | f20f9df0 | Andreas Färber | |
92 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 8: |
93 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->fpuc);
|
94 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 9: |
95 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, (env->fpus & ~0x3800) | |
96 | 986a2998 | Andreas Färber | (env->fpstt & 0x7) << 11); |
97 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 10: |
98 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, 0); /* ftag */ |
99 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 11: |
100 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, 0); /* fiseg */ |
101 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 12: |
102 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, 0); /* fioff */ |
103 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 13: |
104 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, 0); /* foseg */ |
105 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 14: |
106 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, 0); /* fooff */ |
107 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 15: |
108 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, 0); /* fop */ |
109 | f20f9df0 | Andreas Färber | |
110 | f20f9df0 | Andreas Färber | case IDX_MXCSR_REG:
|
111 | 986a2998 | Andreas Färber | return gdb_get_reg32(mem_buf, env->mxcsr);
|
112 | f20f9df0 | Andreas Färber | } |
113 | f20f9df0 | Andreas Färber | } |
114 | f20f9df0 | Andreas Färber | return 0; |
115 | f20f9df0 | Andreas Färber | } |
116 | f20f9df0 | Andreas Färber | |
117 | 5b50e790 | Andreas Färber | static int x86_cpu_gdb_load_seg(X86CPU *cpu, int sreg, uint8_t *mem_buf) |
118 | f20f9df0 | Andreas Färber | { |
119 | 5b50e790 | Andreas Färber | CPUX86State *env = &cpu->env; |
120 | f20f9df0 | Andreas Färber | uint16_t selector = ldl_p(mem_buf); |
121 | f20f9df0 | Andreas Färber | |
122 | f20f9df0 | Andreas Färber | if (selector != env->segs[sreg].selector) {
|
123 | f20f9df0 | Andreas Färber | #if defined(CONFIG_USER_ONLY)
|
124 | f20f9df0 | Andreas Färber | cpu_x86_load_seg(env, sreg, selector); |
125 | f20f9df0 | Andreas Färber | #else
|
126 | f20f9df0 | Andreas Färber | unsigned int limit, flags; |
127 | f20f9df0 | Andreas Färber | target_ulong base; |
128 | f20f9df0 | Andreas Färber | |
129 | f20f9df0 | Andreas Färber | if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { |
130 | f20f9df0 | Andreas Färber | base = selector << 4;
|
131 | f20f9df0 | Andreas Färber | limit = 0xffff;
|
132 | f20f9df0 | Andreas Färber | flags = 0;
|
133 | f20f9df0 | Andreas Färber | } else {
|
134 | f20f9df0 | Andreas Färber | if (!cpu_x86_get_descr_debug(env, selector, &base, &limit,
|
135 | f20f9df0 | Andreas Färber | &flags)) { |
136 | f20f9df0 | Andreas Färber | return 4; |
137 | f20f9df0 | Andreas Färber | } |
138 | f20f9df0 | Andreas Färber | } |
139 | f20f9df0 | Andreas Färber | cpu_x86_load_seg_cache(env, sreg, selector, base, limit, flags); |
140 | f20f9df0 | Andreas Färber | #endif
|
141 | f20f9df0 | Andreas Färber | } |
142 | f20f9df0 | Andreas Färber | return 4; |
143 | f20f9df0 | Andreas Färber | } |
144 | f20f9df0 | Andreas Färber | |
145 | 5b50e790 | Andreas Färber | int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) |
146 | f20f9df0 | Andreas Färber | { |
147 | 5b50e790 | Andreas Färber | X86CPU *cpu = X86_CPU(cs); |
148 | 5b50e790 | Andreas Färber | CPUX86State *env = &cpu->env; |
149 | f20f9df0 | Andreas Färber | uint32_t tmp; |
150 | f20f9df0 | Andreas Färber | |
151 | f20f9df0 | Andreas Färber | if (n < CPU_NB_REGS) {
|
152 | f20f9df0 | Andreas Färber | if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { |
153 | f20f9df0 | Andreas Färber | env->regs[gpr_map[n]] = ldtul_p(mem_buf); |
154 | f20f9df0 | Andreas Färber | return sizeof(target_ulong); |
155 | f20f9df0 | Andreas Färber | } else if (n < CPU_NB_REGS32) { |
156 | f20f9df0 | Andreas Färber | n = gpr_map32[n]; |
157 | f20f9df0 | Andreas Färber | env->regs[n] &= ~0xffffffffUL;
|
158 | f20f9df0 | Andreas Färber | env->regs[n] |= (uint32_t)ldl_p(mem_buf); |
159 | f20f9df0 | Andreas Färber | return 4; |
160 | f20f9df0 | Andreas Färber | } |
161 | f20f9df0 | Andreas Färber | } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) { |
162 | f20f9df0 | Andreas Färber | #ifdef USE_X86LDOUBLE
|
163 | f20f9df0 | Andreas Färber | /* FIXME: byteswap float values - after fixing fpregs layout. */
|
164 | f20f9df0 | Andreas Färber | memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
|
165 | f20f9df0 | Andreas Färber | #endif
|
166 | f20f9df0 | Andreas Färber | return 10; |
167 | f20f9df0 | Andreas Färber | } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) { |
168 | f20f9df0 | Andreas Färber | n -= IDX_XMM_REGS; |
169 | f20f9df0 | Andreas Färber | if (n < CPU_NB_REGS32 ||
|
170 | f20f9df0 | Andreas Färber | (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
|
171 | f20f9df0 | Andreas Färber | env->xmm_regs[n].XMM_Q(0) = ldq_p(mem_buf);
|
172 | f20f9df0 | Andreas Färber | env->xmm_regs[n].XMM_Q(1) = ldq_p(mem_buf + 8); |
173 | f20f9df0 | Andreas Färber | return 16; |
174 | f20f9df0 | Andreas Färber | } |
175 | f20f9df0 | Andreas Färber | } else {
|
176 | f20f9df0 | Andreas Färber | switch (n) {
|
177 | f20f9df0 | Andreas Färber | case IDX_IP_REG:
|
178 | f20f9df0 | Andreas Färber | if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { |
179 | f20f9df0 | Andreas Färber | env->eip = ldq_p(mem_buf); |
180 | f20f9df0 | Andreas Färber | return 8; |
181 | f20f9df0 | Andreas Färber | } else {
|
182 | f20f9df0 | Andreas Färber | env->eip &= ~0xffffffffUL;
|
183 | f20f9df0 | Andreas Färber | env->eip |= (uint32_t)ldl_p(mem_buf); |
184 | f20f9df0 | Andreas Färber | return 4; |
185 | f20f9df0 | Andreas Färber | } |
186 | f20f9df0 | Andreas Färber | case IDX_FLAGS_REG:
|
187 | f20f9df0 | Andreas Färber | env->eflags = ldl_p(mem_buf); |
188 | f20f9df0 | Andreas Färber | return 4; |
189 | f20f9df0 | Andreas Färber | |
190 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS:
|
191 | 5b50e790 | Andreas Färber | return x86_cpu_gdb_load_seg(cpu, R_CS, mem_buf);
|
192 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS + 1: |
193 | 5b50e790 | Andreas Färber | return x86_cpu_gdb_load_seg(cpu, R_SS, mem_buf);
|
194 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS + 2: |
195 | 5b50e790 | Andreas Färber | return x86_cpu_gdb_load_seg(cpu, R_DS, mem_buf);
|
196 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS + 3: |
197 | 5b50e790 | Andreas Färber | return x86_cpu_gdb_load_seg(cpu, R_ES, mem_buf);
|
198 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS + 4: |
199 | 5b50e790 | Andreas Färber | return x86_cpu_gdb_load_seg(cpu, R_FS, mem_buf);
|
200 | f20f9df0 | Andreas Färber | case IDX_SEG_REGS + 5: |
201 | 5b50e790 | Andreas Färber | return x86_cpu_gdb_load_seg(cpu, R_GS, mem_buf);
|
202 | f20f9df0 | Andreas Färber | |
203 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 8: |
204 | f20f9df0 | Andreas Färber | env->fpuc = ldl_p(mem_buf); |
205 | f20f9df0 | Andreas Färber | return 4; |
206 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 9: |
207 | f20f9df0 | Andreas Färber | tmp = ldl_p(mem_buf); |
208 | f20f9df0 | Andreas Färber | env->fpstt = (tmp >> 11) & 7; |
209 | f20f9df0 | Andreas Färber | env->fpus = tmp & ~0x3800;
|
210 | f20f9df0 | Andreas Färber | return 4; |
211 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 10: /* ftag */ |
212 | f20f9df0 | Andreas Färber | return 4; |
213 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 11: /* fiseg */ |
214 | f20f9df0 | Andreas Färber | return 4; |
215 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 12: /* fioff */ |
216 | f20f9df0 | Andreas Färber | return 4; |
217 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 13: /* foseg */ |
218 | f20f9df0 | Andreas Färber | return 4; |
219 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 14: /* fooff */ |
220 | f20f9df0 | Andreas Färber | return 4; |
221 | f20f9df0 | Andreas Färber | case IDX_FP_REGS + 15: /* fop */ |
222 | f20f9df0 | Andreas Färber | return 4; |
223 | f20f9df0 | Andreas Färber | |
224 | f20f9df0 | Andreas Färber | case IDX_MXCSR_REG:
|
225 | f20f9df0 | Andreas Färber | env->mxcsr = ldl_p(mem_buf); |
226 | f20f9df0 | Andreas Färber | return 4; |
227 | f20f9df0 | Andreas Färber | } |
228 | f20f9df0 | Andreas Färber | } |
229 | f20f9df0 | Andreas Färber | /* Unrecognised register. */
|
230 | f20f9df0 | Andreas Färber | return 0; |
231 | f20f9df0 | Andreas Färber | } |